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"
56 #ifndef HAVE_SYSV_COMPAT
57 int config_parse_warn_compat(const char *unit,
67 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
68 "Support for option %s= has been disabled at compile time and is ignored",
74 int config_parse_unit_deps(const char* unit,
84 UnitDependency d = ltype;
94 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
95 _cleanup_free_ char *t = NULL, *k = NULL;
102 k = unit_name_printf(u, t);
106 r = unit_add_dependency_by_name(u, d, k, NULL, true);
108 log_syntax(unit, LOG_ERR, filename, line, -r,
109 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
115 int config_parse_unit_string_printf(const char *unit,
116 const char *filename,
126 _cleanup_free_ char *k = NULL;
133 k = unit_full_printf(u, rvalue);
135 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
136 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
138 return config_parse_string(unit, filename, line, section, lvalue, ltype,
139 k ? k : rvalue, data, userdata);
142 int config_parse_unit_strv_printf(const char *unit,
143 const char *filename,
153 _cleanup_free_ char *k = NULL;
160 k = unit_full_printf(u, rvalue);
162 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
163 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
165 return config_parse_strv(unit, filename, line, section, lvalue, ltype,
166 k ? k : rvalue, data, userdata);
169 int config_parse_unit_path_printf(const char *unit,
170 const char *filename,
180 _cleanup_free_ char *k = NULL;
187 k = unit_full_printf(u, rvalue);
189 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
190 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
192 return config_parse_path(unit, filename, line, section, lvalue, ltype,
193 k ? k : rvalue, data, userdata);
196 int config_parse_socket_listen(const char *unit,
197 const char *filename,
206 SocketPort *p, *tail;
216 if (isempty(rvalue)) {
217 /* An empty assignment removes all ports */
218 socket_free_ports(s);
222 p = new0(SocketPort, 1);
226 if (ltype != SOCKET_SOCKET) {
229 p->path = unit_full_printf(UNIT(s), rvalue);
231 p->path = strdup(rvalue);
236 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
237 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
240 path_kill_slashes(p->path);
242 } else if (streq(lvalue, "ListenNetlink")) {
243 _cleanup_free_ char *k = NULL;
246 p->type = SOCKET_SOCKET;
247 k = unit_full_printf(UNIT(s), rvalue);
249 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
250 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
252 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
254 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
255 "Failed to parse address value, ignoring: %s", rvalue);
261 _cleanup_free_ char *k = NULL;
264 p->type = SOCKET_SOCKET;
265 k = unit_full_printf(UNIT(s), rvalue);
267 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
268 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
270 r = socket_address_parse(&p->address, k ? k : rvalue);
272 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
273 "Failed to parse address value, ignoring: %s", rvalue);
278 if (streq(lvalue, "ListenStream"))
279 p->address.type = SOCK_STREAM;
280 else if (streq(lvalue, "ListenDatagram"))
281 p->address.type = SOCK_DGRAM;
283 assert(streq(lvalue, "ListenSequentialPacket"));
284 p->address.type = SOCK_SEQPACKET;
287 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
288 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
289 "Address family not supported, ignoring: %s", rvalue);
298 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
299 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
301 LIST_PREPEND(SocketPort, port, s->ports, p);
306 int config_parse_socket_bind(const char *unit,
307 const char *filename,
317 SocketAddressBindIPv6Only b;
326 b = socket_address_bind_ipv6_only_from_string(rvalue);
330 r = parse_boolean(rvalue);
332 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
333 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
337 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
339 s->bind_ipv6_only = b;
344 int config_parse_exec_nice(const char *unit,
345 const char *filename,
354 ExecContext *c = data;
362 r = safe_atoi(rvalue, &priority);
364 log_syntax(unit, LOG_ERR, filename, line, -r,
365 "Failed to parse nice priority, ignoring: %s. ", rvalue);
369 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
370 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
371 "Nice priority out of range, ignoring: %s", rvalue);
381 int config_parse_exec_oom_score_adjust(const char* unit,
382 const char *filename,
391 ExecContext *c = data;
399 r = safe_atoi(rvalue, &oa);
401 log_syntax(unit, LOG_ERR, filename, line, -r,
402 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
406 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
407 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
408 "OOM score adjust value out of range, ignoring: %s", rvalue);
412 c->oom_score_adjust = oa;
413 c->oom_score_adjust_set = true;
418 int config_parse_exec(const char *unit,
419 const char *filename,
428 ExecCommand **e = data, *nce;
440 if (isempty(rvalue)) {
441 /* An empty assignment resets the list */
442 exec_command_free_list(*e);
447 /* We accept an absolute path as first argument, or
448 * alternatively an absolute prefixed with @ to allow
449 * overriding of argv[0]. */
455 bool honour_argv0 = false, ignore = false;
461 rvalue += strspn(rvalue, WHITESPACE);
466 for (i = 0; i < 2; i++) {
467 if (rvalue[0] == '-' && !ignore) {
472 if (rvalue[0] == '@' && !honour_argv0) {
478 if (*rvalue != '/') {
479 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
480 "Executable path is not absolute, ignoring: %s", rvalue);
485 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
486 if (strneq(w, ";", MAX(l, 1U)))
492 n = new(char*, k + !honour_argv0);
497 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
498 if (strneq(w, ";", MAX(l, 1U)))
500 else if (strneq(w, "\\;", MAX(l, 1U)))
503 if (honour_argv0 && w == rvalue) {
506 path = strndup(w, l);
512 if (!utf8_is_valid(path)) {
513 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
514 "Path is not UTF-8 clean, ignoring assignment: %s",
523 c = n[k++] = cunescape_length(w, l);
529 if (!utf8_is_valid(c)) {
530 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
531 "Path is not UTF-8 clean, ignoring assignment: %s",
542 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
543 "Invalid command line, ignoring: %s", rvalue);
556 assert(path_is_absolute(path));
558 nce = new0(ExecCommand, 1);
566 nce->ignore = ignore;
568 path_kill_slashes(nce->path);
570 exec_command_append_list(e, nce);
586 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
587 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
589 int config_parse_socket_bindtodevice(const char* unit,
590 const char *filename,
607 if (rvalue[0] && !streq(rvalue, "*")) {
614 free(s->bind_to_device);
615 s->bind_to_device = n;
620 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
621 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
623 int config_parse_exec_io_class(const char *unit,
624 const char *filename,
633 ExecContext *c = data;
641 x = ioprio_class_from_string(rvalue);
643 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
644 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
648 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
649 c->ioprio_set = true;
654 int config_parse_exec_io_priority(const char *unit,
655 const char *filename,
664 ExecContext *c = data;
672 r = safe_atoi(rvalue, &i);
673 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
674 log_syntax(unit, LOG_ERR, filename, line, -r,
675 "Failed to parse IO priority, ignoring: %s", rvalue);
679 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
680 c->ioprio_set = true;
685 int config_parse_exec_cpu_sched_policy(const char *unit,
686 const char *filename,
696 ExecContext *c = data;
704 x = sched_policy_from_string(rvalue);
706 log_syntax(unit, LOG_ERR, filename, line, -x,
707 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
711 c->cpu_sched_policy = x;
712 /* Moving to or from real-time policy? We need to adjust the priority */
713 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
714 c->cpu_sched_set = true;
719 int config_parse_exec_cpu_sched_prio(const char *unit,
720 const char *filename,
729 ExecContext *c = data;
737 r = safe_atoi(rvalue, &i);
739 log_syntax(unit, LOG_ERR, filename, line, -r,
740 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
744 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
745 min = sched_get_priority_min(c->cpu_sched_policy);
746 max = sched_get_priority_max(c->cpu_sched_policy);
748 if (i < min || i > max) {
749 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
750 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
754 c->cpu_sched_priority = i;
755 c->cpu_sched_set = true;
760 int config_parse_exec_cpu_affinity(const char *unit,
761 const char *filename,
770 ExecContext *c = data;
780 if (isempty(rvalue)) {
781 /* An empty assignment resets the CPU list */
788 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
789 _cleanup_free_ char *t = NULL;
797 r = safe_atou(t, &cpu);
800 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
805 if (r < 0 || cpu >= c->cpuset_ncpus) {
806 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
807 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
811 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
817 int config_parse_exec_capabilities(const char *unit,
818 const char *filename,
827 ExecContext *c = data;
835 cap = cap_from_text(rvalue);
837 log_syntax(unit, LOG_ERR, filename, line, errno,
838 "Failed to parse capabilities, ignoring: %s", rvalue);
843 cap_free(c->capabilities);
844 c->capabilities = cap;
849 int config_parse_exec_secure_bits(const char *unit,
850 const char *filename,
859 ExecContext *c = data;
869 if (isempty(rvalue)) {
870 /* An empty assignment resets the field */
875 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
876 if (first_word(w, "keep-caps"))
877 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
878 else if (first_word(w, "keep-caps-locked"))
879 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
880 else if (first_word(w, "no-setuid-fixup"))
881 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
882 else if (first_word(w, "no-setuid-fixup-locked"))
883 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
884 else if (first_word(w, "noroot"))
885 c->secure_bits |= 1<<SECURE_NOROOT;
886 else if (first_word(w, "noroot-locked"))
887 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
889 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
890 "Failed to parse secure bits, ignoring: %s", rvalue);
898 int config_parse_bounding_set(const char *unit,
899 const char *filename,
908 uint64_t *capability_bounding_set_drop = data;
920 if (rvalue[0] == '~') {
925 /* Note that we store this inverted internally, since the
926 * kernel wants it like this. But we actually expose it
927 * non-inverted everywhere to have a fully normalized
930 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
931 _cleanup_free_ char *t = NULL;
939 r = cap_from_name(t, &cap);
941 log_syntax(unit, LOG_ERR, filename, line, errno,
942 "Failed to parse capability in bounding set, ignoring: %s", t);
946 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
950 *capability_bounding_set_drop |= sum;
952 *capability_bounding_set_drop |= ~sum;
957 int config_parse_limit(const char *unit,
958 const char *filename,
967 struct rlimit **rl = data;
968 unsigned long long u;
977 if (streq(rvalue, "infinity"))
978 u = (unsigned long long) RLIM_INFINITY;
982 r = safe_atollu(rvalue, &u);
984 log_syntax(unit, LOG_ERR, filename, line, -r,
985 "Failed to parse resource value, ignoring: %s", rvalue);
991 *rl = new(struct rlimit, 1);
996 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1000 #ifdef HAVE_SYSV_COMPAT
1001 int config_parse_sysv_priority(const char *unit,
1002 const char *filename,
1004 const char *section,
1011 int *priority = data;
1019 r = safe_atoi(rvalue, &i);
1020 if (r < 0 || i < 0) {
1021 log_syntax(unit, LOG_ERR, filename, line, -r,
1022 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1026 *priority = (int) i;
1031 int config_parse_fsck_passno(const char *unit,
1032 const char *filename,
1034 const char *section,
1049 r = safe_atoi(rvalue, &i);
1051 log_syntax(unit, LOG_ERR, filename, line, -r,
1052 "Failed to parse fsck pass number, ignoring: %s", rvalue);
1060 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1062 int config_parse_kill_signal(const char *unit,
1063 const char *filename,
1065 const char *section,
1080 r = signal_from_string_try_harder(rvalue);
1082 log_syntax(unit, LOG_ERR, filename, line, -r,
1083 "Failed to parse kill signal, ignoring: %s", rvalue);
1091 int config_parse_exec_mount_flags(const char *unit,
1092 const char *filename,
1094 const char *section,
1101 ExecContext *c = data;
1105 unsigned long flags = 0;
1112 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1113 _cleanup_free_ char *t;
1119 if (streq(t, "shared"))
1121 else if (streq(t, "slave"))
1123 else if (streq(w, "private"))
1124 flags |= MS_PRIVATE;
1126 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1127 "Failed to parse mount flag %s, ignoring: %s",
1133 c->mount_flags = flags;
1137 int config_parse_timer(const char *unit,
1138 const char *filename,
1140 const char *section,
1151 CalendarSpec *c = NULL;
1159 if (isempty(rvalue)) {
1160 /* Empty assignment resets list */
1161 timer_free_values(t);
1165 b = timer_base_from_string(lvalue);
1167 log_syntax(unit, LOG_ERR, filename, line, -b,
1168 "Failed to parse timer base, ignoring: %s", lvalue);
1172 if (b == TIMER_CALENDAR) {
1173 if (calendar_spec_from_string(rvalue, &c) < 0) {
1174 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1175 "Failed to parse calendar specification, ignoring: %s",
1180 id = CLOCK_REALTIME;
1182 if (parse_sec(rvalue, &u) < 0) {
1183 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1184 "Failed to parse timer value, ignoring: %s",
1189 id = CLOCK_MONOTONIC;
1192 v = new0(TimerValue, 1);
1199 v->calendar_spec = c;
1201 LIST_PREPEND(TimerValue, value, t->values, v);
1206 int config_parse_trigger_unit(
1208 const char *filename,
1210 const char *section,
1217 _cleanup_free_ char *p = NULL;
1227 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1228 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1229 "Multiple units to trigger specified, ignoring: %s", rvalue);
1233 p = unit_name_printf(u, rvalue);
1237 type = unit_name_to_type(p);
1239 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1240 "Unit type not valid, ignoring: %s", rvalue);
1244 if (type == u->type) {
1245 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1246 "Trigger cannot be of same type, ignoring: %s", rvalue);
1250 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true);
1252 log_syntax(unit, LOG_ERR, filename, line, -r,
1253 "Failed to add trigger on %s, ignoring: %s", p, strerror(-r));
1260 int config_parse_path_spec(const char *unit,
1261 const char *filename,
1263 const char *section,
1273 _cleanup_free_ char *k = NULL;
1280 if (isempty(rvalue)) {
1281 /* Empty assignment clears list */
1286 b = path_type_from_string(lvalue);
1288 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1289 "Failed to parse path type, ignoring: %s", lvalue);
1293 k = unit_full_printf(UNIT(p), rvalue);
1299 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1300 "Failed to resolve unit specifiers on %s. Ignoring.",
1304 if (!path_is_absolute(k)) {
1305 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1306 "Path is not absolute, ignoring: %s", k);
1310 s = new0(PathSpec, 1);
1314 s->path = path_kill_slashes(k);
1319 LIST_PREPEND(PathSpec, spec, p->specs, s);
1324 int config_parse_socket_service(const char *unit,
1325 const char *filename,
1327 const char *section,
1338 _cleanup_free_ char *p = NULL;
1345 dbus_error_init(&error);
1347 p = unit_name_printf(UNIT(s), rvalue);
1351 if (!endswith(p, ".service")) {
1352 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1353 "Unit must be of type service, ignoring: %s", rvalue);
1357 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1359 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1360 "Failed to load unit %s, ignoring: %s",
1361 rvalue, bus_error(&error, r));
1362 dbus_error_free(&error);
1366 unit_ref_set(&s->service, x);
1371 int config_parse_service_sockets(const char *unit,
1372 const char *filename,
1374 const char *section,
1391 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1392 _cleanup_free_ char *t = NULL, *k = NULL;
1398 k = unit_name_printf(UNIT(s), t);
1402 if (!endswith(k, ".socket")) {
1403 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1404 "Unit must be of type socket, ignoring: %s", k);
1408 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1410 log_syntax(unit, LOG_ERR, filename, line, -r,
1411 "Failed to add dependency on %s, ignoring: %s",
1414 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1422 int config_parse_service_timeout(const char *unit,
1423 const char *filename,
1425 const char *section,
1432 Service *s = userdata;
1440 r = config_parse_sec(unit, filename, line, section, lvalue, ltype,
1441 rvalue, data, userdata);
1445 if (streq(lvalue, "TimeoutSec")) {
1446 s->start_timeout_defined = true;
1447 s->timeout_stop_usec = s->timeout_start_usec;
1448 } else if (streq(lvalue, "TimeoutStartSec"))
1449 s->start_timeout_defined = true;
1454 int config_parse_unit_env_file(const char *unit,
1455 const char *filename,
1457 const char *section,
1466 _cleanup_free_ char *s = NULL;
1474 if (isempty(rvalue)) {
1475 /* Empty assignment frees the list */
1481 s = unit_full_printf(u, rvalue);
1485 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1486 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1487 "Path '%s' is not absolute, ignoring.", s);
1491 r = strv_extend(env, s);
1498 int config_parse_environ(const char *unit,
1499 const char *filename,
1501 const char *section,
1509 char*** env = data, *w, *state;
1511 _cleanup_free_ char *k = NULL;
1518 if (isempty(rvalue)) {
1519 /* Empty assignment resets the list */
1526 k = unit_full_printf(u, rvalue);
1533 FOREACH_WORD_QUOTED(w, l, k, state) {
1534 _cleanup_free_ char *n;
1537 n = cunescape_length(w, l);
1541 if (!env_assignment_is_valid(n)) {
1542 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1543 "Invalid environment assignment, ignoring: %s", rvalue);
1547 x = strv_env_set(*env, n);
1558 int config_parse_ip_tos(const char *unit,
1559 const char *filename,
1561 const char *section,
1568 int *ip_tos = data, x;
1575 x = ip_tos_from_string(rvalue);
1577 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1578 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1586 int config_parse_unit_condition_path(const char *unit,
1587 const char *filename,
1589 const char *section,
1596 ConditionType cond = ltype;
1598 bool trigger, negate;
1600 _cleanup_free_ char *p = NULL;
1607 if (isempty(rvalue)) {
1608 /* Empty assignment resets the list */
1609 condition_free_list(u->conditions);
1610 u->conditions = NULL;
1614 trigger = rvalue[0] == '|';
1618 negate = rvalue[0] == '!';
1622 p = unit_full_printf(u, rvalue);
1626 if (!path_is_absolute(p)) {
1627 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1628 "Path in condition not absolute, ignoring: %s", p);
1632 c = condition_new(cond, p, trigger, negate);
1636 LIST_PREPEND(Condition, conditions, u->conditions, c);
1640 int config_parse_unit_condition_string(const char *unit,
1641 const char *filename,
1643 const char *section,
1650 ConditionType cond = ltype;
1652 bool trigger, negate;
1654 _cleanup_free_ char *s = NULL;
1661 if (isempty(rvalue)) {
1662 /* Empty assignment resets the list */
1663 condition_free_list(u->conditions);
1664 u->conditions = NULL;
1668 trigger = rvalue[0] == '|';
1672 negate = rvalue[0] == '!';
1676 s = unit_full_printf(u, rvalue);
1680 c = condition_new(cond, s, trigger, negate);
1684 LIST_PREPEND(Condition, conditions, u->conditions, c);
1688 int config_parse_unit_condition_null(const char *unit,
1689 const char *filename,
1691 const char *section,
1700 bool trigger, negate;
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 b = parse_boolean(rvalue);
1725 log_syntax(unit, LOG_ERR, filename, line, -b,
1726 "Failed to parse boolean value in condition, ignoring: %s",
1734 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1738 LIST_PREPEND(Condition, conditions, u->conditions, c);
1742 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1743 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1745 int config_parse_unit_requires_mounts_for(const char *unit,
1746 const char *filename,
1748 const char *section,
1764 empty_before = !u->requires_mounts_for;
1766 r = config_parse_path_strv(unit, filename, line, section, lvalue, ltype,
1767 rvalue, data, userdata);
1769 /* Make it easy to find units with requires_mounts set */
1770 if (empty_before && u->requires_mounts_for)
1771 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1776 int config_parse_documentation(const char *unit,
1777 const char *filename,
1779 const char *section,
1795 if (isempty(rvalue)) {
1796 /* Empty assignment resets the list */
1797 strv_free(u->documentation);
1798 u->documentation = NULL;
1802 r = config_parse_unit_strv_printf(unit, filename, line, section, lvalue, ltype,
1803 rvalue, data, userdata);
1807 for (a = b = u->documentation; a && *a; a++) {
1809 if (is_valid_documentation_url(*a))
1812 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1813 "Invalid URL, ignoring: %s", *a);
1822 static void syscall_set(uint32_t *p, int nr) {
1823 nr = SYSCALL_TO_INDEX(nr);
1824 p[nr >> 4] |= 1 << (nr & 31);
1827 static void syscall_unset(uint32_t *p, int nr) {
1828 nr = SYSCALL_TO_INDEX(nr);
1829 p[nr >> 4] &= ~(1 << (nr & 31));
1832 int config_parse_syscall_filter(const char *unit,
1833 const char *filename,
1835 const char *section,
1842 ExecContext *c = data;
1844 bool invert = false;
1854 if (isempty(rvalue)) {
1855 /* Empty assignment resets the list */
1856 free(c->syscall_filter);
1857 c->syscall_filter = NULL;
1861 if (rvalue[0] == '~') {
1866 if (!c->syscall_filter) {
1869 n = (syscall_max() + 31) >> 4;
1870 c->syscall_filter = new(uint32_t, n);
1871 if (!c->syscall_filter)
1874 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
1876 /* Add these by default */
1877 syscall_set(c->syscall_filter, __NR_execve);
1878 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
1879 #ifdef __NR_sigreturn
1880 syscall_set(c->syscall_filter, __NR_sigreturn);
1882 syscall_set(c->syscall_filter, __NR_exit_group);
1883 syscall_set(c->syscall_filter, __NR_exit);
1886 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1888 _cleanup_free_ char *t = NULL;
1894 id = syscall_from_name(t);
1896 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1897 "Failed to parse syscall, ignoring: %s", t);
1902 syscall_unset(c->syscall_filter, id);
1904 syscall_set(c->syscall_filter, id);
1907 c->no_new_privileges = true;
1912 int config_parse_unit_slice(
1914 const char *filename,
1916 const char *section,
1923 _cleanup_free_ char *k = NULL;
1924 Unit *u = userdata, *slice;
1932 k = unit_name_printf(u, rvalue);
1934 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1935 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
1937 r = manager_load_unit(u->manager, k ? k : rvalue, NULL, NULL, &slice);
1939 log_syntax(unit, LOG_ERR, filename, line, -r,
1940 "Failed to load slice unit %s. Ignoring.", k ? k : rvalue);
1944 if (slice->type != UNIT_SLICE) {
1945 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1946 "Slice unit %s is not a slice. Ignoring.", k ? k : rvalue);
1950 unit_ref_set(&u->slice, slice);
1954 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
1956 int config_parse_cpu_shares(
1958 const char *filename,
1960 const char *section,
1967 CGroupContext *c = data;
1975 if (isempty(rvalue)) {
1976 c->cpu_shares = 1024;
1980 r = safe_atolu(rvalue, &lu);
1981 if (r < 0 || lu <= 0) {
1982 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1983 "CPU shares '%s' invalid. Ignoring.", rvalue);
1991 int config_parse_memory_limit(
1993 const char *filename,
1995 const char *section,
2002 CGroupContext *c = data;
2007 limit = streq(lvalue, "MemoryLimit") ? &c->memory_limit : &c->memory_soft_limit;
2009 if (isempty(rvalue)) {
2010 *limit = (uint64_t) -1;
2014 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2016 r = parse_bytes(rvalue, &bytes);
2018 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2019 "Memory limit '%s' invalid. Ignoring.", rvalue);
2023 *limit = (uint64_t) bytes;
2027 int config_parse_device_allow(
2029 const char *filename,
2031 const char *section,
2038 _cleanup_free_ char *path = NULL;
2039 CGroupContext *c = data;
2040 CGroupDeviceAllow *a;
2044 if (isempty(rvalue)) {
2045 while (c->device_allow)
2046 cgroup_context_free_device_allow(c, c->device_allow);
2051 n = strcspn(rvalue, WHITESPACE);
2052 path = strndup(rvalue, n);
2056 if (!path_startswith(path, "/dev")) {
2057 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2058 "Invalid device node path '%s'. Ignoring.", path);
2062 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2066 if (!in_charset(m, "rwm")) {
2067 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2068 "Invalid device rights '%s'. Ignoring.", m);
2072 a = new0(CGroupDeviceAllow, 1);
2078 a->r = !!strchr(m, 'r');
2079 a->w = !!strchr(m, 'w');
2080 a->m = !!strchr(m, 'm');
2082 LIST_PREPEND(CGroupDeviceAllow, device_allow, c->device_allow, a);
2086 int config_parse_blockio_weight(
2088 const char *filename,
2090 const char *section,
2097 CGroupContext *c = data;
2105 if (isempty(rvalue)) {
2106 c->blockio_weight = 1000;
2110 r = safe_atolu(rvalue, &lu);
2111 if (r < 0 || lu < 10 || lu > 1000) {
2112 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2113 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2117 c->blockio_weight = lu;
2122 int config_parse_blockio_device_weight(
2124 const char *filename,
2126 const char *section,
2133 _cleanup_free_ char *path = NULL;
2134 CGroupBlockIODeviceWeight *w;
2135 CGroupContext *c = data;
2145 if (isempty(rvalue)) {
2146 while (c->blockio_device_weights)
2147 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2152 n = strcspn(rvalue, WHITESPACE);
2153 weight = rvalue + n;
2155 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2156 "Expected block device and device weight. Ignoring.");
2160 path = strndup(rvalue, n);
2164 if (!path_startswith(path, "/dev")) {
2165 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2166 "Invalid device node path '%s'. Ignoring.", path);
2170 weight += strspn(weight, WHITESPACE);
2171 r = safe_atolu(weight, &lu);
2172 if (r < 0 || lu < 10 || lu > 1000) {
2173 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2174 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2179 w = new0(CGroupBlockIODeviceWeight, 1);
2188 LIST_PREPEND(CGroupBlockIODeviceWeight, device_weights, c->blockio_device_weights, w);
2192 int config_parse_blockio_bandwidth(
2194 const char *filename,
2196 const char *section,
2203 _cleanup_free_ char *path = NULL;
2204 CGroupBlockIODeviceBandwidth *b;
2205 CGroupContext *c = data;
2206 const char *bandwidth;
2215 if (isempty(rvalue)) {
2216 while (c->blockio_device_bandwidths)
2217 cgroup_context_free_blockio_device_bandwidth(c, c->blockio_device_bandwidths);
2222 n = strcspn(rvalue, WHITESPACE);
2223 bandwidth = rvalue + n;
2224 bandwidth += strspn(bandwidth, WHITESPACE);
2227 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2228 "Expected space separated pair of device node and bandwidth. Ignoring.");
2232 path = strndup(rvalue, n);
2236 if (!path_startswith(path, "/dev")) {
2237 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2238 "Invalid device node path '%s'. Ignoring.", path);
2242 r = parse_bytes(bandwidth, &bytes);
2243 if (r < 0 || bytes <= 0) {
2244 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2245 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2249 b = new0(CGroupBlockIODeviceBandwidth, 1);
2255 b->bandwidth = (uint64_t) bytes;
2257 LIST_PREPEND(CGroupBlockIODeviceBandwidth, device_bandwidths, c->blockio_device_bandwidths, b);
2262 #define FOLLOW_MAX 8
2264 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2275 /* This will update the filename pointer if the loaded file is
2276 * reached by a symlink. The old string will be freed. */
2279 char *target, *name;
2281 if (c++ >= FOLLOW_MAX)
2284 path_kill_slashes(*filename);
2286 /* Add the file name we are currently looking at to
2287 * the names of this unit, but only if it is a valid
2289 name = path_get_file_name(*filename);
2291 if (unit_name_is_valid(name, true)) {
2293 id = set_get(names, name);
2299 r = set_consume(names, id);
2305 /* Try to open the file name, but don't if its a symlink */
2306 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2313 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2314 r = readlink_and_make_absolute(*filename, &target);
2322 f = fdopen(fd, "re");
2325 close_nointr_nofail(fd);
2334 static int merge_by_names(Unit **u, Set *names, const char *id) {
2342 /* Let's try to add in all symlink names we found */
2343 while ((k = set_steal_first(names))) {
2345 /* First try to merge in the other name into our
2347 r = unit_merge_by_name(*u, k);
2351 /* Hmm, we couldn't merge the other unit into
2352 * ours? Then let's try it the other way
2355 other = manager_get_unit((*u)->manager, k);
2359 r = unit_merge(other, *u);
2362 return merge_by_names(u, names, NULL);
2370 unit_choose_id(*u, id);
2378 static int load_from_path(Unit *u, const char *path) {
2382 char *filename = NULL, *id = NULL;
2389 symlink_names = set_new(string_hash_func, string_compare_func);
2393 if (path_is_absolute(path)) {
2395 filename = strdup(path);
2401 r = open_follow(&filename, &f, symlink_names, &id);
2413 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2415 /* Instead of opening the path right away, we manually
2416 * follow all symlinks and add their name to our unit
2417 * name set while doing so */
2418 filename = path_make_absolute(path, *p);
2424 if (u->manager->unit_path_cache &&
2425 !set_get(u->manager->unit_path_cache, filename))
2428 r = open_follow(&filename, &f, symlink_names, &id);
2437 /* Empty the symlink names for the next run */
2438 set_clear_free(symlink_names);
2447 /* Hmm, no suitable file found? */
2453 r = merge_by_names(&merged, symlink_names, id);
2458 u->load_state = UNIT_MERGED;
2463 if (fstat(fileno(f), &st) < 0) {
2468 if (null_or_empty(&st))
2469 u->load_state = UNIT_MASKED;
2471 u->load_state = UNIT_LOADED;
2473 /* Now, parse the file contents */
2474 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2475 config_item_perf_lookup,
2476 (void*) load_fragment_gperf_lookup, false, true, u);
2481 free(u->fragment_path);
2482 u->fragment_path = filename;
2485 u->fragment_mtime = timespec_load(&st.st_mtim);
2487 if (u->source_path) {
2488 if (stat(u->source_path, &st) >= 0)
2489 u->source_mtime = timespec_load(&st.st_mtim);
2491 u->source_mtime = 0;
2497 set_free_free(symlink_names);
2506 int unit_load_fragment(Unit *u) {
2512 assert(u->load_state == UNIT_STUB);
2515 /* First, try to find the unit under its id. We always look
2516 * for unit files in the default directories, to make it easy
2517 * to override things by placing things in /etc/systemd/system */
2518 r = load_from_path(u, u->id);
2522 /* Try to find an alias we can load this with */
2523 if (u->load_state == UNIT_STUB)
2524 SET_FOREACH(t, u->names, i) {
2529 r = load_from_path(u, t);
2533 if (u->load_state != UNIT_STUB)
2537 /* And now, try looking for it under the suggested (originally linked) path */
2538 if (u->load_state == UNIT_STUB && u->fragment_path) {
2540 r = load_from_path(u, u->fragment_path);
2544 if (u->load_state == UNIT_STUB) {
2545 /* Hmm, this didn't work? Then let's get rid
2546 * of the fragment path stored for us, so that
2547 * we don't point to an invalid location. */
2548 free(u->fragment_path);
2549 u->fragment_path = NULL;
2553 /* Look for a template */
2554 if (u->load_state == UNIT_STUB && u->instance) {
2557 k = unit_name_template(u->id);
2561 r = load_from_path(u, k);
2567 if (u->load_state == UNIT_STUB)
2568 SET_FOREACH(t, u->names, i) {
2573 k = unit_name_template(t);
2577 r = load_from_path(u, k);
2583 if (u->load_state != UNIT_STUB)
2591 void unit_dump_config_items(FILE *f) {
2592 static const struct {
2593 const ConfigParserCallback callback;
2596 { config_parse_int, "INTEGER" },
2597 { config_parse_unsigned, "UNSIGNED" },
2598 { config_parse_bytes_size, "SIZE" },
2599 { config_parse_bool, "BOOLEAN" },
2600 { config_parse_string, "STRING" },
2601 { config_parse_path, "PATH" },
2602 { config_parse_unit_path_printf, "PATH" },
2603 { config_parse_strv, "STRING [...]" },
2604 { config_parse_exec_nice, "NICE" },
2605 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2606 { config_parse_exec_io_class, "IOCLASS" },
2607 { config_parse_exec_io_priority, "IOPRIORITY" },
2608 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2609 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2610 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2611 { config_parse_mode, "MODE" },
2612 { config_parse_unit_env_file, "FILE" },
2613 { config_parse_output, "OUTPUT" },
2614 { config_parse_input, "INPUT" },
2615 { config_parse_facility, "FACILITY" },
2616 { config_parse_level, "LEVEL" },
2617 { config_parse_exec_capabilities, "CAPABILITIES" },
2618 { config_parse_exec_secure_bits, "SECUREBITS" },
2619 { config_parse_bounding_set, "BOUNDINGSET" },
2620 { config_parse_limit, "LIMIT" },
2621 { config_parse_unit_deps, "UNIT [...]" },
2622 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2623 { config_parse_service_type, "SERVICETYPE" },
2624 { config_parse_service_restart, "SERVICERESTART" },
2625 #ifdef HAVE_SYSV_COMPAT
2626 { config_parse_sysv_priority, "SYSVPRIORITY" },
2628 { config_parse_warn_compat, "NOTSUPPORTED" },
2630 { config_parse_kill_mode, "KILLMODE" },
2631 { config_parse_kill_signal, "SIGNAL" },
2632 { config_parse_socket_listen, "SOCKET [...]" },
2633 { config_parse_socket_bind, "SOCKETBIND" },
2634 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2635 { config_parse_sec, "SECONDS" },
2636 { config_parse_nsec, "NANOSECONDS" },
2637 { config_parse_path_strv, "PATH [...]" },
2638 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2639 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2640 { config_parse_unit_string_printf, "STRING" },
2641 { config_parse_trigger_unit, "UNIT" },
2642 { config_parse_timer, "TIMER" },
2643 { config_parse_path_spec, "PATH" },
2644 { config_parse_notify_access, "ACCESS" },
2645 { config_parse_ip_tos, "TOS" },
2646 { config_parse_unit_condition_path, "CONDITION" },
2647 { config_parse_unit_condition_string, "CONDITION" },
2648 { config_parse_unit_condition_null, "CONDITION" },
2649 { config_parse_unit_slice, "SLICE" },
2652 const char *prev = NULL;
2657 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2658 const char *rvalue = "OTHER", *lvalue;
2662 const ConfigPerfItem *p;
2664 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2666 dot = strchr(i, '.');
2667 lvalue = dot ? dot + 1 : i;
2671 if (!prev || !strneq(prev, i, prefix_len+1)) {
2675 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2678 for (j = 0; j < ELEMENTSOF(table); j++)
2679 if (p->parse == table[j].callback) {
2680 rvalue = table[j].rvalue;
2684 fprintf(f, "%s=%s\n", lvalue, rvalue);