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>
37 #include <systemd/sd-messages.h>
41 #include "conf-parser.h"
42 #include "load-fragment.h"
45 #include "securebits.h"
47 #include "unit-name.h"
48 #include "unit-printf.h"
49 #include "dbus-common.h"
51 #include "path-util.h"
52 #include "syscall-list.h"
55 #ifndef HAVE_SYSV_COMPAT
56 int config_parse_warn_compat(const char *unit,
66 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
67 "Support for option %s= has been disabled at compile time and is ignored",
73 int config_parse_unit_deps(const char* unit,
83 UnitDependency d = ltype;
93 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
94 _cleanup_free_ char *t = NULL, *k = NULL;
101 k = unit_name_printf(u, t);
105 r = unit_add_dependency_by_name(u, d, k, NULL, true);
107 log_syntax(unit, LOG_ERR, filename, line, -r,
108 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
114 int config_parse_unit_string_printf(const char *unit,
115 const char *filename,
125 _cleanup_free_ char *k = NULL;
132 k = unit_full_printf(u, rvalue);
134 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
135 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
137 return config_parse_string(unit, filename, line, section, lvalue, ltype,
138 k ? k : rvalue, data, userdata);
141 int config_parse_unit_strv_printf(const char *unit,
142 const char *filename,
152 _cleanup_free_ char *k = NULL;
159 k = unit_full_printf(u, rvalue);
161 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
162 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
164 return config_parse_strv(unit, filename, line, section, lvalue, ltype,
165 k ? k : rvalue, data, userdata);
168 int config_parse_unit_path_printf(const char *unit,
169 const char *filename,
179 _cleanup_free_ char *k = NULL;
186 k = unit_full_printf(u, rvalue);
188 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
189 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
191 return config_parse_path(unit, filename, line, section, lvalue, ltype,
192 k ? k : rvalue, data, userdata);
195 int config_parse_socket_listen(const char *unit,
196 const char *filename,
205 SocketPort *p, *tail;
215 if (isempty(rvalue)) {
216 /* An empty assignment removes all ports */
217 socket_free_ports(s);
221 p = new0(SocketPort, 1);
225 if (ltype != SOCKET_SOCKET) {
228 p->path = unit_full_printf(UNIT(s), rvalue);
230 p->path = strdup(rvalue);
235 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
236 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
239 path_kill_slashes(p->path);
241 } else if (streq(lvalue, "ListenNetlink")) {
242 _cleanup_free_ char *k = NULL;
245 p->type = SOCKET_SOCKET;
246 k = unit_full_printf(UNIT(s), rvalue);
248 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
249 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
251 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
253 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
254 "Failed to parse address value, ignoring: %s", rvalue);
260 _cleanup_free_ char *k = NULL;
263 p->type = SOCKET_SOCKET;
264 k = unit_full_printf(UNIT(s), rvalue);
266 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
267 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
269 r = socket_address_parse(&p->address, k ? k : rvalue);
271 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
272 "Failed to parse address value, ignoring: %s", rvalue);
277 if (streq(lvalue, "ListenStream"))
278 p->address.type = SOCK_STREAM;
279 else if (streq(lvalue, "ListenDatagram"))
280 p->address.type = SOCK_DGRAM;
282 assert(streq(lvalue, "ListenSequentialPacket"));
283 p->address.type = SOCK_SEQPACKET;
286 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
287 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
288 "Address family not supported, ignoring: %s", rvalue);
297 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
298 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
300 LIST_PREPEND(SocketPort, port, s->ports, p);
305 int config_parse_socket_bind(const char *unit,
306 const char *filename,
316 SocketAddressBindIPv6Only b;
325 b = socket_address_bind_ipv6_only_from_string(rvalue);
329 r = parse_boolean(rvalue);
331 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
332 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
336 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
338 s->bind_ipv6_only = b;
343 int config_parse_exec_nice(const char *unit,
344 const char *filename,
353 ExecContext *c = data;
361 r = safe_atoi(rvalue, &priority);
363 log_syntax(unit, LOG_ERR, filename, line, -r,
364 "Failed to parse nice priority, ignoring: %s. ", rvalue);
368 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
369 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
370 "Nice priority out of range, ignoring: %s", rvalue);
380 int config_parse_exec_oom_score_adjust(const char* unit,
381 const char *filename,
390 ExecContext *c = data;
398 r = safe_atoi(rvalue, &oa);
400 log_syntax(unit, LOG_ERR, filename, line, -r,
401 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
405 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
406 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
407 "OOM score adjust value out of range, ignoring: %s", rvalue);
411 c->oom_score_adjust = oa;
412 c->oom_score_adjust_set = true;
417 int config_parse_exec(const char *unit,
418 const char *filename,
427 ExecCommand **e = data, *nce;
439 if (isempty(rvalue)) {
440 /* An empty assignment resets the list */
441 exec_command_free_list(*e);
446 /* We accept an absolute path as first argument, or
447 * alternatively an absolute prefixed with @ to allow
448 * overriding of argv[0]. */
454 bool honour_argv0 = false, ignore = false;
460 rvalue += strspn(rvalue, WHITESPACE);
465 for (i = 0; i < 2; i++) {
466 if (rvalue[0] == '-' && !ignore) {
471 if (rvalue[0] == '@' && !honour_argv0) {
477 if (*rvalue != '/') {
478 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
479 "Executable path is not absolute, ignoring: %s", rvalue);
484 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
485 if (strneq(w, ";", MAX(l, 1U)))
491 n = new(char*, k + !honour_argv0);
496 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
497 if (strneq(w, ";", MAX(l, 1U)))
499 else if (strneq(w, "\\;", MAX(l, 1U)))
502 if (honour_argv0 && w == rvalue) {
505 path = strndup(w, l);
511 if (!utf8_is_valid(path)) {
512 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
513 "Path is not UTF-8 clean, ignoring assignment: %s",
522 c = n[k++] = cunescape_length(w, l);
528 if (!utf8_is_valid(c)) {
529 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
530 "Path is not UTF-8 clean, ignoring assignment: %s",
541 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
542 "Invalid command line, ignoring: %s", rvalue);
555 assert(path_is_absolute(path));
557 nce = new0(ExecCommand, 1);
565 nce->ignore = ignore;
567 path_kill_slashes(nce->path);
569 exec_command_append_list(e, nce);
585 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
586 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
588 int config_parse_socket_bindtodevice(const char* unit,
589 const char *filename,
606 if (rvalue[0] && !streq(rvalue, "*")) {
613 free(s->bind_to_device);
614 s->bind_to_device = n;
619 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
620 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
622 int config_parse_exec_io_class(const char *unit,
623 const char *filename,
632 ExecContext *c = data;
640 x = ioprio_class_from_string(rvalue);
642 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
643 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
647 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
648 c->ioprio_set = true;
653 int config_parse_exec_io_priority(const char *unit,
654 const char *filename,
663 ExecContext *c = data;
671 r = safe_atoi(rvalue, &i);
672 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
673 log_syntax(unit, LOG_ERR, filename, line, -r,
674 "Failed to parse IO priority, ignoring: %s", rvalue);
678 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
679 c->ioprio_set = true;
684 int config_parse_exec_cpu_sched_policy(const char *unit,
685 const char *filename,
695 ExecContext *c = data;
703 x = sched_policy_from_string(rvalue);
705 log_syntax(unit, LOG_ERR, filename, line, -x,
706 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
710 c->cpu_sched_policy = x;
711 /* Moving to or from real-time policy? We need to adjust the priority */
712 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
713 c->cpu_sched_set = true;
718 int config_parse_exec_cpu_sched_prio(const char *unit,
719 const char *filename,
728 ExecContext *c = data;
736 r = safe_atoi(rvalue, &i);
738 log_syntax(unit, LOG_ERR, filename, line, -r,
739 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
743 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
744 min = sched_get_priority_min(c->cpu_sched_policy);
745 max = sched_get_priority_max(c->cpu_sched_policy);
747 if (i < min || i > max) {
748 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
749 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
753 c->cpu_sched_priority = i;
754 c->cpu_sched_set = true;
759 int config_parse_exec_cpu_affinity(const char *unit,
760 const char *filename,
769 ExecContext *c = data;
779 if (isempty(rvalue)) {
780 /* An empty assignment resets the CPU list */
787 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
788 _cleanup_free_ char *t = NULL;
796 r = safe_atou(t, &cpu);
799 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
804 if (r < 0 || cpu >= c->cpuset_ncpus) {
805 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
806 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
810 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
816 int config_parse_exec_capabilities(const char *unit,
817 const char *filename,
826 ExecContext *c = data;
834 cap = cap_from_text(rvalue);
836 log_syntax(unit, LOG_ERR, filename, line, errno,
837 "Failed to parse capabilities, ignoring: %s", rvalue);
842 cap_free(c->capabilities);
843 c->capabilities = cap;
848 int config_parse_exec_secure_bits(const char *unit,
849 const char *filename,
858 ExecContext *c = data;
868 if (isempty(rvalue)) {
869 /* An empty assignment resets the field */
874 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
875 if (first_word(w, "keep-caps"))
876 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
877 else if (first_word(w, "keep-caps-locked"))
878 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
879 else if (first_word(w, "no-setuid-fixup"))
880 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
881 else if (first_word(w, "no-setuid-fixup-locked"))
882 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
883 else if (first_word(w, "noroot"))
884 c->secure_bits |= 1<<SECURE_NOROOT;
885 else if (first_word(w, "noroot-locked"))
886 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
888 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
889 "Failed to parse secure bits, ignoring: %s", rvalue);
897 int config_parse_bounding_set(const char *unit,
898 const char *filename,
907 uint64_t *capability_bounding_set_drop = data;
919 if (rvalue[0] == '~') {
924 /* Note that we store this inverted internally, since the
925 * kernel wants it like this. But we actually expose it
926 * non-inverted everywhere to have a fully normalized
929 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
930 _cleanup_free_ char *t = NULL;
938 r = cap_from_name(t, &cap);
940 log_syntax(unit, LOG_ERR, filename, line, errno,
941 "Failed to parse capability in bounding set, ignoring: %s", t);
945 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
949 *capability_bounding_set_drop |= sum;
951 *capability_bounding_set_drop |= ~sum;
956 int config_parse_limit(const char *unit,
957 const char *filename,
966 struct rlimit **rl = data;
967 unsigned long long u;
976 if (streq(rvalue, "infinity"))
977 u = (unsigned long long) RLIM_INFINITY;
981 r = safe_atollu(rvalue, &u);
983 log_syntax(unit, LOG_ERR, filename, line, -r,
984 "Failed to parse resource value, ignoring: %s", rvalue);
990 *rl = new(struct rlimit, 1);
995 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
999 int config_parse_unit_cgroup(const char *unit,
1000 const char *filename,
1002 const char *section,
1014 if (isempty(rvalue)) {
1015 /* An empty assignment resets the list */
1016 cgroup_bonding_free_list(u->cgroup_bondings, false);
1017 u->cgroup_bondings = NULL;
1021 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1022 _cleanup_free_ char *t = NULL, *k = NULL, *ku = NULL;
1029 k = unit_full_printf(u, t);
1031 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1032 "Failed to resolve unit specifiers on %s. Ignoring.",
1035 ku = cunescape(k ? k : t);
1039 r = unit_add_cgroup_from_text(u, ku, true, NULL);
1041 log_syntax(unit, LOG_ERR, filename, line, -r,
1042 "Failed to parse cgroup value %s, ignoring: %s",
1051 #ifdef HAVE_SYSV_COMPAT
1052 int config_parse_sysv_priority(const char *unit,
1053 const char *filename,
1055 const char *section,
1062 int *priority = data;
1070 r = safe_atoi(rvalue, &i);
1071 if (r < 0 || i < 0) {
1072 log_syntax(unit, LOG_ERR, filename, line, -r,
1073 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1077 *priority = (int) i;
1082 int config_parse_fsck_passno(const char *unit,
1083 const char *filename,
1085 const char *section,
1100 r = safe_atoi(rvalue, &i);
1102 log_syntax(unit, LOG_ERR, filename, line, -r,
1103 "Failed to parse fsck pass number, ignoring: %s", rvalue);
1111 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1113 int config_parse_kill_signal(const char *unit,
1114 const char *filename,
1116 const char *section,
1131 r = signal_from_string_try_harder(rvalue);
1133 log_syntax(unit, LOG_ERR, filename, line, -r,
1134 "Failed to parse kill signal, ignoring: %s", rvalue);
1142 int config_parse_exec_mount_flags(const char *unit,
1143 const char *filename,
1145 const char *section,
1152 ExecContext *c = data;
1156 unsigned long flags = 0;
1163 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1164 _cleanup_free_ char *t;
1170 if (streq(t, "shared"))
1172 else if (streq(t, "slave"))
1174 else if (streq(w, "private"))
1175 flags |= MS_PRIVATE;
1177 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1178 "Failed to parse mount flag %s, ignoring: %s",
1184 c->mount_flags = flags;
1188 int config_parse_timer(const char *unit,
1189 const char *filename,
1191 const char *section,
1202 CalendarSpec *c = NULL;
1210 if (isempty(rvalue)) {
1211 /* Empty assignment resets list */
1212 timer_free_values(t);
1216 b = timer_base_from_string(lvalue);
1218 log_syntax(unit, LOG_ERR, filename, line, -b,
1219 "Failed to parse timer base, ignoring: %s", lvalue);
1223 if (b == TIMER_CALENDAR) {
1224 if (calendar_spec_from_string(rvalue, &c) < 0) {
1225 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1226 "Failed to parse calendar specification, ignoring: %s",
1231 id = CLOCK_REALTIME;
1233 if (parse_sec(rvalue, &u) < 0) {
1234 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1235 "Failed to parse timer value, ignoring: %s",
1240 id = CLOCK_MONOTONIC;
1243 v = new0(TimerValue, 1);
1250 v->calendar_spec = c;
1252 LIST_PREPEND(TimerValue, value, t->values, v);
1257 int config_parse_trigger_unit(
1259 const char *filename,
1261 const char *section,
1268 _cleanup_free_ char *p = NULL;
1278 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1279 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1280 "Multiple units to trigger specified, ignoring: %s", rvalue);
1284 p = unit_name_printf(u, rvalue);
1288 type = unit_name_to_type(p);
1290 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1291 "Unit type not valid, ignoring: %s", rvalue);
1295 if (type == u->type) {
1296 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1297 "Trigger cannot be of same type, ignoring: %s", rvalue);
1301 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true);
1303 log_syntax(unit, LOG_ERR, filename, line, -r,
1304 "Failed to add trigger on %s, ignoring: %s", p, strerror(-r));
1311 int config_parse_path_spec(const char *unit,
1312 const char *filename,
1314 const char *section,
1324 _cleanup_free_ char *k = NULL;
1331 if (isempty(rvalue)) {
1332 /* Empty assignment clears list */
1337 b = path_type_from_string(lvalue);
1339 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1340 "Failed to parse path type, ignoring: %s", lvalue);
1344 k = unit_full_printf(UNIT(p), rvalue);
1350 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1351 "Failed to resolve unit specifiers on %s. Ignoring.",
1355 if (!path_is_absolute(k)) {
1356 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1357 "Path is not absolute, ignoring: %s", k);
1361 s = new0(PathSpec, 1);
1365 s->path = path_kill_slashes(k);
1370 LIST_PREPEND(PathSpec, spec, p->specs, s);
1375 int config_parse_socket_service(const char *unit,
1376 const char *filename,
1378 const char *section,
1389 _cleanup_free_ char *p = NULL;
1396 dbus_error_init(&error);
1398 p = unit_name_printf(UNIT(s), rvalue);
1402 if (!endswith(p, ".service")) {
1403 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1404 "Unit must be of type service, ignoring: %s", rvalue);
1408 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1410 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1411 "Failed to load unit %s, ignoring: %s",
1412 rvalue, bus_error(&error, r));
1413 dbus_error_free(&error);
1417 unit_ref_set(&s->service, x);
1422 int config_parse_service_sockets(const char *unit,
1423 const char *filename,
1425 const char *section,
1442 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1443 _cleanup_free_ char *t = NULL, *k = NULL;
1449 k = unit_name_printf(UNIT(s), t);
1453 if (!endswith(k, ".socket")) {
1454 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1455 "Unit must be of type socket, ignoring: %s", k);
1459 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1461 log_syntax(unit, LOG_ERR, filename, line, -r,
1462 "Failed to add dependency on %s, ignoring: %s",
1465 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1473 int config_parse_service_timeout(const char *unit,
1474 const char *filename,
1476 const char *section,
1483 Service *s = userdata;
1491 r = config_parse_sec(unit, filename, line, section, lvalue, ltype,
1492 rvalue, data, userdata);
1496 if (streq(lvalue, "TimeoutSec")) {
1497 s->start_timeout_defined = true;
1498 s->timeout_stop_usec = s->timeout_start_usec;
1499 } else if (streq(lvalue, "TimeoutStartSec"))
1500 s->start_timeout_defined = true;
1505 int config_parse_unit_env_file(const char *unit,
1506 const char *filename,
1508 const char *section,
1517 _cleanup_free_ char *s = NULL;
1525 if (isempty(rvalue)) {
1526 /* Empty assignment frees the list */
1532 s = unit_full_printf(u, rvalue);
1536 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1537 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1538 "Path '%s' is not absolute, ignoring.", s);
1542 r = strv_extend(env, s);
1549 int config_parse_environ(const char *unit,
1550 const char *filename,
1552 const char *section,
1560 char*** env = data, *w, *state;
1562 _cleanup_free_ char *k = NULL;
1569 if (isempty(rvalue)) {
1570 /* Empty assignment resets the list */
1576 k = unit_full_printf(u, rvalue);
1580 FOREACH_WORD_QUOTED(w, l, k, state) {
1581 _cleanup_free_ char *n;
1584 n = cunescape_length(w, l);
1588 if (!env_assignment_is_valid(n)) {
1589 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1590 "Invalid environment assignment, ignoring: %s", rvalue);
1594 x = strv_env_set(*env, n);
1605 int config_parse_ip_tos(const char *unit,
1606 const char *filename,
1608 const char *section,
1615 int *ip_tos = data, x;
1622 x = ip_tos_from_string(rvalue);
1624 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1625 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1633 int config_parse_unit_condition_path(const char *unit,
1634 const char *filename,
1636 const char *section,
1643 ConditionType cond = ltype;
1645 bool trigger, negate;
1647 _cleanup_free_ char *p = NULL;
1654 if (isempty(rvalue)) {
1655 /* Empty assignment resets the list */
1656 condition_free_list(u->conditions);
1657 u->conditions = NULL;
1661 trigger = rvalue[0] == '|';
1665 negate = rvalue[0] == '!';
1669 p = unit_full_printf(u, rvalue);
1673 if (!path_is_absolute(p)) {
1674 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1675 "Path in condition not absolute, ignoring: %s", p);
1679 c = condition_new(cond, p, trigger, negate);
1683 LIST_PREPEND(Condition, conditions, u->conditions, c);
1687 int config_parse_unit_condition_string(const char *unit,
1688 const char *filename,
1690 const char *section,
1697 ConditionType cond = ltype;
1699 bool trigger, negate;
1701 _cleanup_free_ char *s = NULL;
1708 if (isempty(rvalue)) {
1709 /* Empty assignment resets the list */
1710 condition_free_list(u->conditions);
1711 u->conditions = NULL;
1715 trigger = rvalue[0] == '|';
1719 negate = rvalue[0] == '!';
1723 s = unit_full_printf(u, rvalue);
1727 c = condition_new(cond, s, trigger, negate);
1731 LIST_PREPEND(Condition, conditions, u->conditions, c);
1735 int config_parse_unit_condition_null(const char *unit,
1736 const char *filename,
1738 const char *section,
1747 bool trigger, negate;
1755 if (isempty(rvalue)) {
1756 /* Empty assignment resets the list */
1757 condition_free_list(u->conditions);
1758 u->conditions = NULL;
1762 trigger = rvalue[0] == '|';
1766 negate = rvalue[0] == '!';
1770 b = parse_boolean(rvalue);
1772 log_syntax(unit, LOG_ERR, filename, line, -b,
1773 "Failed to parse boolean value in condition, ignoring: %s",
1781 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1785 LIST_PREPEND(Condition, conditions, u->conditions, c);
1789 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1790 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1792 int config_parse_unit_cgroup_attr(const char *unit,
1793 const char *filename,
1795 const char *section,
1804 _cleanup_free_ char *n = NULL, *v = NULL;
1805 const CGroupSemantics *s;
1813 if (isempty(rvalue)) {
1814 /* Empty assignment clears the list */
1815 cgroup_attribute_free_list(u->cgroup_attributes);
1816 u->cgroup_attributes = NULL;
1820 a = strcspn(rvalue, WHITESPACE);
1821 b = strspn(rvalue + a, WHITESPACE);
1822 if (a <= 0 || b <= 0) {
1823 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1824 "Failed to parse cgroup attribute value, ignoring: %s",
1829 n = strndup(rvalue, a);
1833 r = cgroup_semantics_find(NULL, n, rvalue + a + b, &v, &s);
1835 log_syntax(unit, LOG_ERR, filename, line, -r,
1836 "Failed to parse cgroup attribute value, ignoring: %s",
1841 r = unit_add_cgroup_attribute(u, s, NULL, n, v ? v : rvalue + a + b, NULL);
1843 log_syntax(unit, LOG_ERR, filename, line, -r,
1844 "Failed to add cgroup attribute value, ignoring: %s", rvalue);
1851 int config_parse_unit_cgroup_attr_pretty(const char *unit,
1852 const char *filename,
1854 const char *section,
1862 _cleanup_free_ char *v = NULL;
1863 const CGroupSemantics *s;
1871 r = cgroup_semantics_find(NULL, lvalue, rvalue, &v, &s);
1873 log_syntax(unit, LOG_ERR, filename, line, -r,
1874 "Failed to parse cgroup attribute value, ignoring: %s",
1877 } else if (r == 0) {
1878 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
1879 "Unknown or unsupported cgroup attribute %s, ignoring: %s",
1884 r = unit_add_cgroup_attribute(u, s, NULL, NULL, v, NULL);
1886 log_syntax(unit, LOG_ERR, filename, line, -r,
1887 "Failed to add cgroup attribute value, ignoring: %s", rvalue);
1894 int config_parse_unit_requires_mounts_for(const char *unit,
1895 const char *filename,
1897 const char *section,
1913 empty_before = !u->requires_mounts_for;
1915 r = config_parse_path_strv(unit, filename, line, section, lvalue, ltype,
1916 rvalue, data, userdata);
1918 /* Make it easy to find units with requires_mounts set */
1919 if (empty_before && u->requires_mounts_for)
1920 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1925 int config_parse_documentation(const char *unit,
1926 const char *filename,
1928 const char *section,
1944 if (isempty(rvalue)) {
1945 /* Empty assignment resets the list */
1946 strv_free(u->documentation);
1947 u->documentation = NULL;
1951 r = config_parse_unit_strv_printf(unit, filename, line, section, lvalue, ltype,
1952 rvalue, data, userdata);
1956 for (a = b = u->documentation; a && *a; a++) {
1958 if (is_valid_documentation_url(*a))
1961 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1962 "Invalid URL, ignoring: %s", *a);
1971 static void syscall_set(uint32_t *p, int nr) {
1972 nr = SYSCALL_TO_INDEX(nr);
1973 p[nr >> 4] |= 1 << (nr & 31);
1976 static void syscall_unset(uint32_t *p, int nr) {
1977 nr = SYSCALL_TO_INDEX(nr);
1978 p[nr >> 4] &= ~(1 << (nr & 31));
1981 int config_parse_syscall_filter(const char *unit,
1982 const char *filename,
1984 const char *section,
1991 ExecContext *c = data;
1993 bool invert = false;
2003 if (isempty(rvalue)) {
2004 /* Empty assignment resets the list */
2005 free(c->syscall_filter);
2006 c->syscall_filter = NULL;
2010 if (rvalue[0] == '~') {
2015 if (!c->syscall_filter) {
2018 n = (syscall_max() + 31) >> 4;
2019 c->syscall_filter = new(uint32_t, n);
2020 if (!c->syscall_filter)
2023 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2025 /* Add these by default */
2026 syscall_set(c->syscall_filter, __NR_execve);
2027 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2028 #ifdef __NR_sigreturn
2029 syscall_set(c->syscall_filter, __NR_sigreturn);
2031 syscall_set(c->syscall_filter, __NR_exit_group);
2032 syscall_set(c->syscall_filter, __NR_exit);
2035 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2037 _cleanup_free_ char *t = NULL;
2043 id = syscall_from_name(t);
2045 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2046 "Failed to parse syscall, ignoring: %s", t);
2051 syscall_unset(c->syscall_filter, id);
2053 syscall_set(c->syscall_filter, id);
2056 c->no_new_privileges = true;
2061 #define FOLLOW_MAX 8
2063 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2074 /* This will update the filename pointer if the loaded file is
2075 * reached by a symlink. The old string will be freed. */
2078 char *target, *name;
2080 if (c++ >= FOLLOW_MAX)
2083 path_kill_slashes(*filename);
2085 /* Add the file name we are currently looking at to
2086 * the names of this unit, but only if it is a valid
2088 name = path_get_file_name(*filename);
2090 if (unit_name_is_valid(name, true)) {
2092 id = set_get(names, name);
2098 r = set_consume(names, id);
2104 /* Try to open the file name, but don't if its a symlink */
2105 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2112 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2113 r = readlink_and_make_absolute(*filename, &target);
2121 f = fdopen(fd, "re");
2124 close_nointr_nofail(fd);
2133 static int merge_by_names(Unit **u, Set *names, const char *id) {
2141 /* Let's try to add in all symlink names we found */
2142 while ((k = set_steal_first(names))) {
2144 /* First try to merge in the other name into our
2146 r = unit_merge_by_name(*u, k);
2150 /* Hmm, we couldn't merge the other unit into
2151 * ours? Then let's try it the other way
2154 other = manager_get_unit((*u)->manager, k);
2158 r = unit_merge(other, *u);
2161 return merge_by_names(u, names, NULL);
2169 unit_choose_id(*u, id);
2177 static int load_from_path(Unit *u, const char *path) {
2181 char *filename = NULL, *id = NULL;
2188 symlink_names = set_new(string_hash_func, string_compare_func);
2192 if (path_is_absolute(path)) {
2194 filename = strdup(path);
2200 r = open_follow(&filename, &f, symlink_names, &id);
2212 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2214 /* Instead of opening the path right away, we manually
2215 * follow all symlinks and add their name to our unit
2216 * name set while doing so */
2217 filename = path_make_absolute(path, *p);
2223 if (u->manager->unit_path_cache &&
2224 !set_get(u->manager->unit_path_cache, filename))
2227 r = open_follow(&filename, &f, symlink_names, &id);
2236 /* Empty the symlink names for the next run */
2237 set_clear_free(symlink_names);
2246 /* Hmm, no suitable file found? */
2252 r = merge_by_names(&merged, symlink_names, id);
2257 u->load_state = UNIT_MERGED;
2262 if (fstat(fileno(f), &st) < 0) {
2267 if (null_or_empty(&st))
2268 u->load_state = UNIT_MASKED;
2270 /* Now, parse the file contents */
2271 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2272 config_item_perf_lookup,
2273 (void*) load_fragment_gperf_lookup, false, u);
2277 u->load_state = UNIT_LOADED;
2280 free(u->fragment_path);
2281 u->fragment_path = filename;
2284 u->fragment_mtime = timespec_load(&st.st_mtim);
2286 if (u->source_path) {
2287 if (stat(u->source_path, &st) >= 0)
2288 u->source_mtime = timespec_load(&st.st_mtim);
2290 u->source_mtime = 0;
2296 set_free_free(symlink_names);
2305 int unit_load_fragment(Unit *u) {
2311 assert(u->load_state == UNIT_STUB);
2314 /* First, try to find the unit under its id. We always look
2315 * for unit files in the default directories, to make it easy
2316 * to override things by placing things in /etc/systemd/system */
2317 r = load_from_path(u, u->id);
2321 /* Try to find an alias we can load this with */
2322 if (u->load_state == UNIT_STUB)
2323 SET_FOREACH(t, u->names, i) {
2328 r = load_from_path(u, t);
2332 if (u->load_state != UNIT_STUB)
2336 /* And now, try looking for it under the suggested (originally linked) path */
2337 if (u->load_state == UNIT_STUB && u->fragment_path) {
2339 r = load_from_path(u, u->fragment_path);
2343 if (u->load_state == UNIT_STUB) {
2344 /* Hmm, this didn't work? Then let's get rid
2345 * of the fragment path stored for us, so that
2346 * we don't point to an invalid location. */
2347 free(u->fragment_path);
2348 u->fragment_path = NULL;
2352 /* Look for a template */
2353 if (u->load_state == UNIT_STUB && u->instance) {
2356 k = unit_name_template(u->id);
2360 r = load_from_path(u, k);
2366 if (u->load_state == UNIT_STUB)
2367 SET_FOREACH(t, u->names, i) {
2372 k = unit_name_template(t);
2376 r = load_from_path(u, k);
2382 if (u->load_state != UNIT_STUB)
2390 void unit_dump_config_items(FILE *f) {
2391 static const struct {
2392 const ConfigParserCallback callback;
2395 { config_parse_int, "INTEGER" },
2396 { config_parse_unsigned, "UNSIGNED" },
2397 { config_parse_bytes_size, "SIZE" },
2398 { config_parse_bool, "BOOLEAN" },
2399 { config_parse_string, "STRING" },
2400 { config_parse_path, "PATH" },
2401 { config_parse_unit_path_printf, "PATH" },
2402 { config_parse_strv, "STRING [...]" },
2403 { config_parse_exec_nice, "NICE" },
2404 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2405 { config_parse_exec_io_class, "IOCLASS" },
2406 { config_parse_exec_io_priority, "IOPRIORITY" },
2407 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2408 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2409 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2410 { config_parse_mode, "MODE" },
2411 { config_parse_unit_env_file, "FILE" },
2412 { config_parse_output, "OUTPUT" },
2413 { config_parse_input, "INPUT" },
2414 { config_parse_facility, "FACILITY" },
2415 { config_parse_level, "LEVEL" },
2416 { config_parse_exec_capabilities, "CAPABILITIES" },
2417 { config_parse_exec_secure_bits, "SECUREBITS" },
2418 { config_parse_bounding_set, "BOUNDINGSET" },
2419 { config_parse_limit, "LIMIT" },
2420 { config_parse_unit_cgroup, "CGROUP [...]" },
2421 { config_parse_unit_deps, "UNIT [...]" },
2422 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2423 { config_parse_service_type, "SERVICETYPE" },
2424 { config_parse_service_restart, "SERVICERESTART" },
2425 #ifdef HAVE_SYSV_COMPAT
2426 { config_parse_sysv_priority, "SYSVPRIORITY" },
2428 { config_parse_warn_compat, "NOTSUPPORTED" },
2430 { config_parse_kill_mode, "KILLMODE" },
2431 { config_parse_kill_signal, "SIGNAL" },
2432 { config_parse_socket_listen, "SOCKET [...]" },
2433 { config_parse_socket_bind, "SOCKETBIND" },
2434 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2435 { config_parse_sec, "SECONDS" },
2436 { config_parse_nsec, "NANOSECONDS" },
2437 { config_parse_path_strv, "PATH [...]" },
2438 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2439 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2440 { config_parse_unit_string_printf, "STRING" },
2441 { config_parse_trigger_unit, "UNIT" },
2442 { config_parse_timer, "TIMER" },
2443 { config_parse_path_spec, "PATH" },
2444 { config_parse_notify_access, "ACCESS" },
2445 { config_parse_ip_tos, "TOS" },
2446 { config_parse_unit_condition_path, "CONDITION" },
2447 { config_parse_unit_condition_string, "CONDITION" },
2448 { config_parse_unit_condition_null, "CONDITION" },
2451 const char *prev = NULL;
2456 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2457 const char *rvalue = "OTHER", *lvalue;
2461 const ConfigPerfItem *p;
2463 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2465 dot = strchr(i, '.');
2466 lvalue = dot ? dot + 1 : i;
2470 if (!prev || !strneq(prev, i, prefix_len+1)) {
2474 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2477 for (j = 0; j < ELEMENTSOF(table); j++)
2478 if (p->parse == table[j].callback) {
2479 rvalue = table[j].rvalue;
2483 fprintf(f, "%s=%s\n", lvalue, rvalue);