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_timer_unit(const char *unit,
1258 const char *filename,
1260 const char *section,
1271 _cleanup_free_ char *p = NULL;
1278 dbus_error_init(&error);
1280 p = unit_name_printf(UNIT(t), rvalue);
1284 if (endswith(p, ".timer")) {
1285 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1286 "Unit cannot be of type timer, ignoring: %s", rvalue);
1290 r = manager_load_unit(UNIT(t)->manager, p, NULL, NULL, &u);
1292 log_syntax(unit, LOG_ERR, filename, line, -r,
1293 "Failed to load unit %s, ignoring: %s",
1294 rvalue, bus_error(&error, r));
1295 dbus_error_free(&error);
1299 unit_ref_set(&t->unit, u);
1304 int config_parse_path_spec(const char *unit,
1305 const char *filename,
1307 const char *section,
1317 _cleanup_free_ char *k = NULL;
1324 if (isempty(rvalue)) {
1325 /* Empty assignment clears list */
1330 b = path_type_from_string(lvalue);
1332 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1333 "Failed to parse path type, ignoring: %s", lvalue);
1337 k = unit_full_printf(UNIT(p), rvalue);
1343 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1344 "Failed to resolve unit specifiers on %s. Ignoring.",
1348 if (!path_is_absolute(k)) {
1349 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1350 "Path is not absolute, ignoring: %s", k);
1354 s = new0(PathSpec, 1);
1358 s->path = path_kill_slashes(k);
1363 LIST_PREPEND(PathSpec, spec, p->specs, s);
1368 int config_parse_path_unit(const char *unit,
1369 const char *filename,
1371 const char *section,
1382 _cleanup_free_ char *p = NULL;
1389 dbus_error_init(&error);
1391 p = unit_name_printf(UNIT(t), rvalue);
1395 if (endswith(p, ".path")) {
1396 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1397 "Unit cannot be of type path, ignoring: %s", p);
1401 r = manager_load_unit(UNIT(t)->manager, p, NULL, &error, &u);
1403 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1404 "Failed to load unit %s, ignoring: %s",
1405 p, bus_error(&error, r));
1406 dbus_error_free(&error);
1410 unit_ref_set(&t->unit, u);
1415 int config_parse_socket_service(const char *unit,
1416 const char *filename,
1418 const char *section,
1429 _cleanup_free_ char *p = NULL;
1436 dbus_error_init(&error);
1438 p = unit_name_printf(UNIT(s), rvalue);
1442 if (!endswith(p, ".service")) {
1443 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1444 "Unit must be of type service, ignoring: %s", rvalue);
1448 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1450 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1451 "Failed to load unit %s, ignoring: %s",
1452 rvalue, bus_error(&error, r));
1453 dbus_error_free(&error);
1457 unit_ref_set(&s->service, x);
1462 int config_parse_service_sockets(const char *unit,
1463 const char *filename,
1465 const char *section,
1482 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1483 _cleanup_free_ char *t = NULL, *k = NULL;
1489 k = unit_name_printf(UNIT(s), t);
1493 if (!endswith(k, ".socket")) {
1494 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1495 "Unit must be of type socket, ignoring: %s", k);
1499 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1501 log_syntax(unit, LOG_ERR, filename, line, -r,
1502 "Failed to add dependency on %s, ignoring: %s",
1505 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1513 int config_parse_service_timeout(const char *unit,
1514 const char *filename,
1516 const char *section,
1523 Service *s = userdata;
1531 r = config_parse_sec(unit, filename, line, section, lvalue, ltype,
1532 rvalue, data, userdata);
1536 if (streq(lvalue, "TimeoutSec")) {
1537 s->start_timeout_defined = true;
1538 s->timeout_stop_usec = s->timeout_start_usec;
1539 } else if (streq(lvalue, "TimeoutStartSec"))
1540 s->start_timeout_defined = true;
1545 int config_parse_unit_env_file(const char *unit,
1546 const char *filename,
1548 const char *section,
1557 _cleanup_free_ char *s = NULL;
1565 if (isempty(rvalue)) {
1566 /* Empty assignment frees the list */
1572 s = unit_full_printf(u, rvalue);
1576 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1577 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1578 "Path '%s' is not absolute, ignoring.", s);
1582 r = strv_extend(env, s);
1589 int config_parse_environ(const char *unit,
1590 const char *filename,
1592 const char *section,
1600 char*** env = data, *w, *state;
1602 _cleanup_free_ char *k = NULL;
1609 if (isempty(rvalue)) {
1610 /* Empty assignment resets the list */
1616 k = unit_full_printf(u, rvalue);
1620 FOREACH_WORD_QUOTED(w, l, k, state) {
1621 _cleanup_free_ char *n;
1624 n = cunescape_length(w, l);
1628 if (!env_assignment_is_valid(n)) {
1629 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1630 "Invalid environment assignment, ignoring: %s", rvalue);
1634 x = strv_env_set(*env, n);
1645 int config_parse_ip_tos(const char *unit,
1646 const char *filename,
1648 const char *section,
1655 int *ip_tos = data, x;
1662 x = ip_tos_from_string(rvalue);
1664 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1665 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1673 int config_parse_unit_condition_path(const char *unit,
1674 const char *filename,
1676 const char *section,
1683 ConditionType cond = ltype;
1685 bool trigger, negate;
1687 _cleanup_free_ char *p = NULL;
1694 if (isempty(rvalue)) {
1695 /* Empty assignment resets the list */
1696 condition_free_list(u->conditions);
1697 u->conditions = NULL;
1701 trigger = rvalue[0] == '|';
1705 negate = rvalue[0] == '!';
1709 p = unit_full_printf(u, rvalue);
1713 if (!path_is_absolute(p)) {
1714 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1715 "Path in condition not absolute, ignoring: %s", p);
1719 c = condition_new(cond, p, trigger, negate);
1723 LIST_PREPEND(Condition, conditions, u->conditions, c);
1727 int config_parse_unit_condition_string(const char *unit,
1728 const char *filename,
1730 const char *section,
1737 ConditionType cond = ltype;
1739 bool trigger, negate;
1741 _cleanup_free_ char *s = NULL;
1748 if (isempty(rvalue)) {
1749 /* Empty assignment resets the list */
1750 condition_free_list(u->conditions);
1751 u->conditions = NULL;
1755 trigger = rvalue[0] == '|';
1759 negate = rvalue[0] == '!';
1763 s = unit_full_printf(u, rvalue);
1767 c = condition_new(cond, s, trigger, negate);
1771 LIST_PREPEND(Condition, conditions, u->conditions, c);
1775 int config_parse_unit_condition_null(const char *unit,
1776 const char *filename,
1778 const char *section,
1787 bool trigger, negate;
1795 if (isempty(rvalue)) {
1796 /* Empty assignment resets the list */
1797 condition_free_list(u->conditions);
1798 u->conditions = NULL;
1802 trigger = rvalue[0] == '|';
1806 negate = rvalue[0] == '!';
1810 b = parse_boolean(rvalue);
1812 log_syntax(unit, LOG_ERR, filename, line, -b,
1813 "Failed to parse boolean value in condition, ignoring: %s",
1821 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1825 LIST_PREPEND(Condition, conditions, u->conditions, c);
1829 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1830 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1832 int config_parse_unit_cgroup_attr(const char *unit,
1833 const char *filename,
1835 const char *section,
1844 _cleanup_free_ char *n = NULL, *v = NULL;
1845 const CGroupSemantics *s;
1853 if (isempty(rvalue)) {
1854 /* Empty assignment clears the list */
1855 cgroup_attribute_free_list(u->cgroup_attributes);
1856 u->cgroup_attributes = NULL;
1860 a = strcspn(rvalue, WHITESPACE);
1861 b = strspn(rvalue + a, WHITESPACE);
1862 if (a <= 0 || b <= 0) {
1863 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1864 "Failed to parse cgroup attribute value, ignoring: %s",
1869 n = strndup(rvalue, a);
1873 r = cgroup_semantics_find(NULL, n, rvalue + a + b, &v, &s);
1875 log_syntax(unit, LOG_ERR, filename, line, -r,
1876 "Failed to parse cgroup attribute value, ignoring: %s",
1881 r = unit_add_cgroup_attribute(u, s, NULL, n, v ? v : rvalue + a + b, NULL);
1883 log_syntax(unit, LOG_ERR, filename, line, -r,
1884 "Failed to add cgroup attribute value, ignoring: %s", rvalue);
1891 int config_parse_unit_cgroup_attr_pretty(const char *unit,
1892 const char *filename,
1894 const char *section,
1902 _cleanup_free_ char *v = NULL;
1903 const CGroupSemantics *s;
1911 r = cgroup_semantics_find(NULL, lvalue, rvalue, &v, &s);
1913 log_syntax(unit, LOG_ERR, filename, line, -r,
1914 "Failed to parse cgroup attribute value, ignoring: %s",
1917 } else if (r == 0) {
1918 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
1919 "Unknown or unsupported cgroup attribute %s, ignoring: %s",
1924 r = unit_add_cgroup_attribute(u, s, NULL, NULL, v, NULL);
1926 log_syntax(unit, LOG_ERR, filename, line, -r,
1927 "Failed to add cgroup attribute value, ignoring: %s", rvalue);
1934 int config_parse_unit_requires_mounts_for(const char *unit,
1935 const char *filename,
1937 const char *section,
1953 empty_before = !u->requires_mounts_for;
1955 r = config_parse_path_strv(unit, filename, line, section, lvalue, ltype,
1956 rvalue, data, userdata);
1958 /* Make it easy to find units with requires_mounts set */
1959 if (empty_before && u->requires_mounts_for)
1960 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1965 int config_parse_documentation(const char *unit,
1966 const char *filename,
1968 const char *section,
1984 if (isempty(rvalue)) {
1985 /* Empty assignment resets the list */
1986 strv_free(u->documentation);
1987 u->documentation = NULL;
1991 r = config_parse_unit_strv_printf(unit, filename, line, section, lvalue, ltype,
1992 rvalue, data, userdata);
1996 for (a = b = u->documentation; a && *a; a++) {
1998 if (is_valid_documentation_url(*a))
2001 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2002 "Invalid URL, ignoring: %s", *a);
2011 static void syscall_set(uint32_t *p, int nr) {
2012 nr = SYSCALL_TO_INDEX(nr);
2013 p[nr >> 4] |= 1 << (nr & 31);
2016 static void syscall_unset(uint32_t *p, int nr) {
2017 nr = SYSCALL_TO_INDEX(nr);
2018 p[nr >> 4] &= ~(1 << (nr & 31));
2021 int config_parse_syscall_filter(const char *unit,
2022 const char *filename,
2024 const char *section,
2031 ExecContext *c = data;
2033 bool invert = false;
2043 if (isempty(rvalue)) {
2044 /* Empty assignment resets the list */
2045 free(c->syscall_filter);
2046 c->syscall_filter = NULL;
2050 if (rvalue[0] == '~') {
2055 if (!c->syscall_filter) {
2058 n = (syscall_max() + 31) >> 4;
2059 c->syscall_filter = new(uint32_t, n);
2060 if (!c->syscall_filter)
2063 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
2065 /* Add these by default */
2066 syscall_set(c->syscall_filter, __NR_execve);
2067 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
2068 #ifdef __NR_sigreturn
2069 syscall_set(c->syscall_filter, __NR_sigreturn);
2071 syscall_set(c->syscall_filter, __NR_exit_group);
2072 syscall_set(c->syscall_filter, __NR_exit);
2075 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2077 _cleanup_free_ char *t = NULL;
2083 id = syscall_from_name(t);
2085 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2086 "Failed to parse syscall, ignoring: %s", t);
2091 syscall_unset(c->syscall_filter, id);
2093 syscall_set(c->syscall_filter, id);
2096 c->no_new_privileges = true;
2101 #define FOLLOW_MAX 8
2103 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2114 /* This will update the filename pointer if the loaded file is
2115 * reached by a symlink. The old string will be freed. */
2118 char *target, *name;
2120 if (c++ >= FOLLOW_MAX)
2123 path_kill_slashes(*filename);
2125 /* Add the file name we are currently looking at to
2126 * the names of this unit, but only if it is a valid
2128 name = path_get_file_name(*filename);
2130 if (unit_name_is_valid(name, true)) {
2132 id = set_get(names, name);
2138 r = set_put(names, id);
2146 /* Try to open the file name, but don't if its a symlink */
2147 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2154 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2155 r = readlink_and_make_absolute(*filename, &target);
2163 f = fdopen(fd, "re");
2166 close_nointr_nofail(fd);
2175 static int merge_by_names(Unit **u, Set *names, const char *id) {
2183 /* Let's try to add in all symlink names we found */
2184 while ((k = set_steal_first(names))) {
2186 /* First try to merge in the other name into our
2188 r = unit_merge_by_name(*u, k);
2192 /* Hmm, we couldn't merge the other unit into
2193 * ours? Then let's try it the other way
2196 other = manager_get_unit((*u)->manager, k);
2200 r = unit_merge(other, *u);
2203 return merge_by_names(u, names, NULL);
2211 unit_choose_id(*u, id);
2219 static int load_from_path(Unit *u, const char *path) {
2223 char *filename = NULL, *id = NULL;
2230 symlink_names = set_new(string_hash_func, string_compare_func);
2234 if (path_is_absolute(path)) {
2236 filename = strdup(path);
2242 r = open_follow(&filename, &f, symlink_names, &id);
2254 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2256 /* Instead of opening the path right away, we manually
2257 * follow all symlinks and add their name to our unit
2258 * name set while doing so */
2259 filename = path_make_absolute(path, *p);
2265 if (u->manager->unit_path_cache &&
2266 !set_get(u->manager->unit_path_cache, filename))
2269 r = open_follow(&filename, &f, symlink_names, &id);
2278 /* Empty the symlink names for the next run */
2279 set_clear_free(symlink_names);
2288 /* Hmm, no suitable file found? */
2294 r = merge_by_names(&merged, symlink_names, id);
2299 u->load_state = UNIT_MERGED;
2304 if (fstat(fileno(f), &st) < 0) {
2309 if (null_or_empty(&st))
2310 u->load_state = UNIT_MASKED;
2312 /* Now, parse the file contents */
2313 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2314 config_item_perf_lookup,
2315 (void*) load_fragment_gperf_lookup, false, u);
2319 u->load_state = UNIT_LOADED;
2322 free(u->fragment_path);
2323 u->fragment_path = filename;
2326 u->fragment_mtime = timespec_load(&st.st_mtim);
2328 if (u->source_path) {
2329 if (stat(u->source_path, &st) >= 0)
2330 u->source_mtime = timespec_load(&st.st_mtim);
2332 u->source_mtime = 0;
2338 set_free_free(symlink_names);
2347 int unit_load_fragment(Unit *u) {
2353 assert(u->load_state == UNIT_STUB);
2356 /* First, try to find the unit under its id. We always look
2357 * for unit files in the default directories, to make it easy
2358 * to override things by placing things in /etc/systemd/system */
2359 r = load_from_path(u, u->id);
2363 /* Try to find an alias we can load this with */
2364 if (u->load_state == UNIT_STUB)
2365 SET_FOREACH(t, u->names, i) {
2370 r = load_from_path(u, t);
2374 if (u->load_state != UNIT_STUB)
2378 /* And now, try looking for it under the suggested (originally linked) path */
2379 if (u->load_state == UNIT_STUB && u->fragment_path) {
2381 r = load_from_path(u, u->fragment_path);
2385 if (u->load_state == UNIT_STUB) {
2386 /* Hmm, this didn't work? Then let's get rid
2387 * of the fragment path stored for us, so that
2388 * we don't point to an invalid location. */
2389 free(u->fragment_path);
2390 u->fragment_path = NULL;
2394 /* Look for a template */
2395 if (u->load_state == UNIT_STUB && u->instance) {
2398 k = unit_name_template(u->id);
2402 r = load_from_path(u, k);
2408 if (u->load_state == UNIT_STUB)
2409 SET_FOREACH(t, u->names, i) {
2414 k = unit_name_template(t);
2418 r = load_from_path(u, k);
2424 if (u->load_state != UNIT_STUB)
2432 void unit_dump_config_items(FILE *f) {
2433 static const struct {
2434 const ConfigParserCallback callback;
2437 { config_parse_int, "INTEGER" },
2438 { config_parse_unsigned, "UNSIGNED" },
2439 { config_parse_bytes_size, "SIZE" },
2440 { config_parse_bool, "BOOLEAN" },
2441 { config_parse_string, "STRING" },
2442 { config_parse_path, "PATH" },
2443 { config_parse_unit_path_printf, "PATH" },
2444 { config_parse_strv, "STRING [...]" },
2445 { config_parse_exec_nice, "NICE" },
2446 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2447 { config_parse_exec_io_class, "IOCLASS" },
2448 { config_parse_exec_io_priority, "IOPRIORITY" },
2449 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2450 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2451 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2452 { config_parse_mode, "MODE" },
2453 { config_parse_unit_env_file, "FILE" },
2454 { config_parse_output, "OUTPUT" },
2455 { config_parse_input, "INPUT" },
2456 { config_parse_facility, "FACILITY" },
2457 { config_parse_level, "LEVEL" },
2458 { config_parse_exec_capabilities, "CAPABILITIES" },
2459 { config_parse_exec_secure_bits, "SECUREBITS" },
2460 { config_parse_bounding_set, "BOUNDINGSET" },
2461 { config_parse_limit, "LIMIT" },
2462 { config_parse_unit_cgroup, "CGROUP [...]" },
2463 { config_parse_unit_deps, "UNIT [...]" },
2464 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2465 { config_parse_service_type, "SERVICETYPE" },
2466 { config_parse_service_restart, "SERVICERESTART" },
2467 #ifdef HAVE_SYSV_COMPAT
2468 { config_parse_sysv_priority, "SYSVPRIORITY" },
2470 { config_parse_warn_compat, "NOTSUPPORTED" },
2472 { config_parse_kill_mode, "KILLMODE" },
2473 { config_parse_kill_signal, "SIGNAL" },
2474 { config_parse_socket_listen, "SOCKET [...]" },
2475 { config_parse_socket_bind, "SOCKETBIND" },
2476 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2477 { config_parse_sec, "SECONDS" },
2478 { config_parse_nsec, "NANOSECONDS" },
2479 { config_parse_path_strv, "PATH [...]" },
2480 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2481 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2482 { config_parse_unit_string_printf, "STRING" },
2483 { config_parse_timer, "TIMER" },
2484 { config_parse_timer_unit, "NAME" },
2485 { config_parse_path_spec, "PATH" },
2486 { config_parse_path_unit, "UNIT" },
2487 { config_parse_notify_access, "ACCESS" },
2488 { config_parse_ip_tos, "TOS" },
2489 { config_parse_unit_condition_path, "CONDITION" },
2490 { config_parse_unit_condition_string, "CONDITION" },
2491 { config_parse_unit_condition_null, "CONDITION" },
2494 const char *prev = NULL;
2499 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2500 const char *rvalue = "OTHER", *lvalue;
2504 const ConfigPerfItem *p;
2506 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2508 dot = strchr(i, '.');
2509 lvalue = dot ? dot + 1 : i;
2513 if (!prev || !strneq(prev, i, prefix_len+1)) {
2517 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2520 for (j = 0; j < ELEMENTSOF(table); j++)
2521 if (p->parse == table[j].callback) {
2522 rvalue = table[j].rvalue;
2526 fprintf(f, "%s=%s\n", lvalue, rvalue);