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 r = unit_name_printf(u, t, &k);
104 log_syntax(unit, LOG_ERR, filename, line, -r,
105 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
109 r = unit_add_dependency_by_name(u, d, k, NULL, true);
111 log_syntax(unit, LOG_ERR, filename, line, -r,
112 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
118 int config_parse_unit_string_printf(const char *unit,
119 const char *filename,
129 _cleanup_free_ char *k = NULL;
137 r = unit_full_printf(u, rvalue, &k);
139 log_syntax(unit, LOG_ERR, filename, line, -r,
140 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
142 return config_parse_string(unit, filename, line, section, lvalue, ltype,
143 k ? k : rvalue, data, userdata);
146 int config_parse_unit_strv_printf(const char *unit,
147 const char *filename,
157 _cleanup_free_ char *k = NULL;
165 r = unit_full_printf(u, rvalue, &k);
167 log_syntax(unit, LOG_ERR, filename, line, -r,
168 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
170 return config_parse_strv(unit, filename, line, section, lvalue, ltype,
171 k ? k : rvalue, data, userdata);
174 int config_parse_unit_path_printf(const char *unit,
175 const char *filename,
185 _cleanup_free_ char *k = NULL;
193 r = unit_full_printf(u, rvalue, &k);
195 log_syntax(unit, LOG_ERR, filename, line, -r,
196 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
198 return config_parse_path(unit, filename, line, section, lvalue, ltype,
199 k ? k : rvalue, data, userdata);
202 int config_parse_socket_listen(const char *unit,
203 const char *filename,
212 SocketPort *p, *tail;
223 if (isempty(rvalue)) {
224 /* An empty assignment removes all ports */
225 socket_free_ports(s);
229 p = new0(SocketPort, 1);
233 if (ltype != SOCKET_SOCKET) {
236 r = unit_full_printf(UNIT(s), rvalue, &p->path);
238 p->path = strdup(rvalue);
243 log_syntax(unit, LOG_ERR, filename, line, -r,
244 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
247 path_kill_slashes(p->path);
249 } else if (streq(lvalue, "ListenNetlink")) {
250 _cleanup_free_ char *k = NULL;
252 p->type = SOCKET_SOCKET;
253 r = unit_full_printf(UNIT(s), rvalue, &k);
255 log_syntax(unit, LOG_ERR, filename, line, -r,
256 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
258 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
260 log_syntax(unit, LOG_ERR, filename, line, -r,
261 "Failed to parse address value, ignoring: %s", rvalue);
267 _cleanup_free_ char *k = NULL;
269 p->type = SOCKET_SOCKET;
270 r = unit_full_printf(UNIT(s), rvalue, &k);
272 log_syntax(unit, LOG_ERR, filename, line, -r,
273 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
275 r = socket_address_parse(&p->address, k ? k : rvalue);
277 log_syntax(unit, LOG_ERR, filename, line, -r,
278 "Failed to parse address value, ignoring: %s", rvalue);
283 if (streq(lvalue, "ListenStream"))
284 p->address.type = SOCK_STREAM;
285 else if (streq(lvalue, "ListenDatagram"))
286 p->address.type = SOCK_DGRAM;
288 assert(streq(lvalue, "ListenSequentialPacket"));
289 p->address.type = SOCK_SEQPACKET;
292 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
293 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
294 "Address family not supported, ignoring: %s", rvalue);
303 LIST_FIND_TAIL(port, s->ports, tail);
304 LIST_INSERT_AFTER(port, s->ports, tail, p);
306 LIST_PREPEND(port, s->ports, p);
311 int config_parse_socket_bind(const char *unit,
312 const char *filename,
322 SocketAddressBindIPv6Only b;
331 b = socket_address_bind_ipv6_only_from_string(rvalue);
335 r = parse_boolean(rvalue);
337 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
338 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
342 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
344 s->bind_ipv6_only = b;
349 int config_parse_exec_nice(const char *unit,
350 const char *filename,
359 ExecContext *c = data;
367 r = safe_atoi(rvalue, &priority);
369 log_syntax(unit, LOG_ERR, filename, line, -r,
370 "Failed to parse nice priority, ignoring: %s. ", rvalue);
374 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
375 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
376 "Nice priority out of range, ignoring: %s", rvalue);
386 int config_parse_exec_oom_score_adjust(const char* unit,
387 const char *filename,
396 ExecContext *c = data;
404 r = safe_atoi(rvalue, &oa);
406 log_syntax(unit, LOG_ERR, filename, line, -r,
407 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
411 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
412 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
413 "OOM score adjust value out of range, ignoring: %s", rvalue);
417 c->oom_score_adjust = oa;
418 c->oom_score_adjust_set = true;
423 int config_parse_exec(const char *unit,
424 const char *filename,
433 ExecCommand **e = data, *nce;
445 if (isempty(rvalue)) {
446 /* An empty assignment resets the list */
447 exec_command_free_list(*e);
452 /* We accept an absolute path as first argument, or
453 * alternatively an absolute prefixed with @ to allow
454 * overriding of argv[0]. */
460 bool honour_argv0 = false, ignore = false;
466 rvalue += strspn(rvalue, WHITESPACE);
471 for (i = 0; i < 2; i++) {
472 if (rvalue[0] == '-' && !ignore) {
477 if (rvalue[0] == '@' && !honour_argv0) {
483 if (*rvalue != '/') {
484 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
485 "Executable path is not absolute, ignoring: %s", rvalue);
490 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
491 if (strneq(w, ";", MAX(l, 1U)))
497 n = new(char*, k + !honour_argv0);
502 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
503 if (strneq(w, ";", MAX(l, 1U)))
505 else if (strneq(w, "\\;", MAX(l, 1U)))
508 if (honour_argv0 && w == rvalue) {
511 path = strndup(w, l);
517 if (!utf8_is_valid(path)) {
518 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
519 "Path is not UTF-8 clean, ignoring assignment: %s",
528 c = n[k++] = cunescape_length(w, l);
534 if (!utf8_is_valid(c)) {
535 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
536 "Path is not UTF-8 clean, ignoring assignment: %s",
547 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
548 "Invalid command line, ignoring: %s", rvalue);
561 assert(path_is_absolute(path));
563 nce = new0(ExecCommand, 1);
571 nce->ignore = ignore;
573 path_kill_slashes(nce->path);
575 exec_command_append_list(e, nce);
591 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
592 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
594 int config_parse_socket_bindtodevice(const char* unit,
595 const char *filename,
612 if (rvalue[0] && !streq(rvalue, "*")) {
619 free(s->bind_to_device);
620 s->bind_to_device = n;
625 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
626 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
628 int config_parse_exec_io_class(const char *unit,
629 const char *filename,
638 ExecContext *c = data;
646 x = ioprio_class_from_string(rvalue);
648 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
649 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
653 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
654 c->ioprio_set = true;
659 int config_parse_exec_io_priority(const char *unit,
660 const char *filename,
669 ExecContext *c = data;
677 r = safe_atoi(rvalue, &i);
678 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
679 log_syntax(unit, LOG_ERR, filename, line, -r,
680 "Failed to parse IO priority, ignoring: %s", rvalue);
684 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
685 c->ioprio_set = true;
690 int config_parse_exec_cpu_sched_policy(const char *unit,
691 const char *filename,
701 ExecContext *c = data;
709 x = sched_policy_from_string(rvalue);
711 log_syntax(unit, LOG_ERR, filename, line, -x,
712 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
716 c->cpu_sched_policy = x;
717 /* Moving to or from real-time policy? We need to adjust the priority */
718 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
719 c->cpu_sched_set = true;
724 int config_parse_exec_cpu_sched_prio(const char *unit,
725 const char *filename,
734 ExecContext *c = data;
742 r = safe_atoi(rvalue, &i);
744 log_syntax(unit, LOG_ERR, filename, line, -r,
745 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
749 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
750 min = sched_get_priority_min(c->cpu_sched_policy);
751 max = sched_get_priority_max(c->cpu_sched_policy);
753 if (i < min || i > max) {
754 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
755 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
759 c->cpu_sched_priority = i;
760 c->cpu_sched_set = true;
765 int config_parse_exec_cpu_affinity(const char *unit,
766 const char *filename,
775 ExecContext *c = data;
785 if (isempty(rvalue)) {
786 /* An empty assignment resets the CPU list */
793 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
794 _cleanup_free_ char *t = NULL;
802 r = safe_atou(t, &cpu);
805 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
810 if (r < 0 || cpu >= c->cpuset_ncpus) {
811 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
812 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
816 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
822 int config_parse_exec_capabilities(const char *unit,
823 const char *filename,
832 ExecContext *c = data;
840 cap = cap_from_text(rvalue);
842 log_syntax(unit, LOG_ERR, filename, line, errno,
843 "Failed to parse capabilities, ignoring: %s", rvalue);
848 cap_free(c->capabilities);
849 c->capabilities = cap;
854 int config_parse_exec_secure_bits(const char *unit,
855 const char *filename,
864 ExecContext *c = data;
874 if (isempty(rvalue)) {
875 /* An empty assignment resets the field */
880 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
881 if (first_word(w, "keep-caps"))
882 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
883 else if (first_word(w, "keep-caps-locked"))
884 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
885 else if (first_word(w, "no-setuid-fixup"))
886 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
887 else if (first_word(w, "no-setuid-fixup-locked"))
888 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
889 else if (first_word(w, "noroot"))
890 c->secure_bits |= 1<<SECURE_NOROOT;
891 else if (first_word(w, "noroot-locked"))
892 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
894 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
895 "Failed to parse secure bits, ignoring: %s", rvalue);
903 int config_parse_bounding_set(const char *unit,
904 const char *filename,
913 uint64_t *capability_bounding_set_drop = data;
925 if (rvalue[0] == '~') {
930 /* Note that we store this inverted internally, since the
931 * kernel wants it like this. But we actually expose it
932 * non-inverted everywhere to have a fully normalized
935 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
936 _cleanup_free_ char *t = NULL;
944 r = cap_from_name(t, &cap);
946 log_syntax(unit, LOG_ERR, filename, line, errno,
947 "Failed to parse capability in bounding set, ignoring: %s", t);
951 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
955 *capability_bounding_set_drop |= sum;
957 *capability_bounding_set_drop |= ~sum;
962 int config_parse_limit(const char *unit,
963 const char *filename,
972 struct rlimit **rl = data;
973 unsigned long long u;
982 if (streq(rvalue, "infinity"))
983 u = (unsigned long long) RLIM_INFINITY;
987 r = safe_atollu(rvalue, &u);
989 log_syntax(unit, LOG_ERR, filename, line, -r,
990 "Failed to parse resource value, ignoring: %s", rvalue);
996 *rl = new(struct rlimit, 1);
1001 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1005 #ifdef HAVE_SYSV_COMPAT
1006 int config_parse_sysv_priority(const char *unit,
1007 const char *filename,
1009 const char *section,
1016 int *priority = data;
1024 r = safe_atoi(rvalue, &i);
1025 if (r < 0 || i < 0) {
1026 log_syntax(unit, LOG_ERR, filename, line, -r,
1027 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1031 *priority = (int) i;
1036 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1038 int config_parse_kill_signal(const char *unit,
1039 const char *filename,
1041 const char *section,
1056 r = signal_from_string_try_harder(rvalue);
1058 log_syntax(unit, LOG_ERR, filename, line, -r,
1059 "Failed to parse kill signal, ignoring: %s", rvalue);
1067 int config_parse_exec_mount_flags(const char *unit,
1068 const char *filename,
1070 const char *section,
1077 ExecContext *c = data;
1081 unsigned long flags = 0;
1088 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1089 _cleanup_free_ char *t;
1095 if (streq(t, "shared"))
1097 else if (streq(t, "slave"))
1099 else if (streq(w, "private"))
1100 flags |= MS_PRIVATE;
1102 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1103 "Failed to parse mount flag %s, ignoring: %s",
1109 c->mount_flags = flags;
1113 int config_parse_timer(const char *unit,
1114 const char *filename,
1116 const char *section,
1127 CalendarSpec *c = NULL;
1135 if (isempty(rvalue)) {
1136 /* Empty assignment resets list */
1137 timer_free_values(t);
1141 b = timer_base_from_string(lvalue);
1143 log_syntax(unit, LOG_ERR, filename, line, -b,
1144 "Failed to parse timer base, ignoring: %s", lvalue);
1148 if (b == TIMER_CALENDAR) {
1149 if (calendar_spec_from_string(rvalue, &c) < 0) {
1150 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1151 "Failed to parse calendar specification, ignoring: %s",
1156 id = CLOCK_REALTIME;
1158 if (parse_sec(rvalue, &u) < 0) {
1159 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1160 "Failed to parse timer value, ignoring: %s",
1165 id = CLOCK_MONOTONIC;
1168 v = new0(TimerValue, 1);
1175 v->calendar_spec = c;
1177 LIST_PREPEND(value, t->values, v);
1182 int config_parse_trigger_unit(
1184 const char *filename,
1186 const char *section,
1193 _cleanup_free_ char *p = NULL;
1203 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1204 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1205 "Multiple units to trigger specified, ignoring: %s", rvalue);
1209 r = unit_name_printf(u, rvalue, &p);
1211 log_syntax(unit, LOG_ERR, filename, line, -r,
1212 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1214 type = unit_name_to_type(p ?: rvalue);
1216 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1217 "Unit type not valid, ignoring: %s", rvalue);
1221 if (type == u->type) {
1222 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1223 "Trigger cannot be of same type, ignoring: %s", rvalue);
1227 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1229 log_syntax(unit, LOG_ERR, filename, line, -r,
1230 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1237 int config_parse_path_spec(const char *unit,
1238 const char *filename,
1240 const char *section,
1250 _cleanup_free_ char *k = NULL;
1258 if (isempty(rvalue)) {
1259 /* Empty assignment clears list */
1264 b = path_type_from_string(lvalue);
1266 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1267 "Failed to parse path type, ignoring: %s", lvalue);
1271 r = unit_full_printf(UNIT(p), rvalue, &k);
1277 log_syntax(unit, LOG_ERR, filename, line, -r,
1278 "Failed to resolve unit specifiers on %s. Ignoring.",
1282 if (!path_is_absolute(k)) {
1283 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1284 "Path is not absolute, ignoring: %s", k);
1288 s = new0(PathSpec, 1);
1292 s->path = path_kill_slashes(k);
1297 LIST_PREPEND(spec, p->specs, s);
1302 int config_parse_socket_service(const char *unit,
1303 const char *filename,
1305 const char *section,
1316 _cleanup_free_ char *p = NULL;
1323 dbus_error_init(&error);
1325 r = unit_name_printf(UNIT(s), rvalue, &p);
1327 log_syntax(unit, LOG_ERR, filename, line, -r,
1328 "Failed to resolve specifiers, ignoring: %s", rvalue);
1330 if (!endswith(p ?: rvalue, ".service")) {
1331 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1332 "Unit must be of type service, ignoring: %s", rvalue);
1336 r = manager_load_unit(UNIT(s)->manager, p ?: rvalue, NULL, &error, &x);
1338 log_syntax(unit, LOG_ERR, filename, line, r,
1339 "Failed to load unit %s, ignoring: %s",
1340 rvalue, bus_error(&error, r));
1341 dbus_error_free(&error);
1345 unit_ref_set(&s->service, x);
1350 int config_parse_service_sockets(const char *unit,
1351 const char *filename,
1353 const char *section,
1370 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1371 _cleanup_free_ char *t = NULL, *k = NULL;
1377 r = unit_name_printf(UNIT(s), t, &k);
1379 log_syntax(unit, LOG_ERR, filename, line, -r,
1380 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1382 if (!endswith(k ?: t, ".socket")) {
1383 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1384 "Unit must be of type socket, ignoring: %s", k ?: t);
1388 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1390 log_syntax(unit, LOG_ERR, filename, line, -r,
1391 "Failed to add dependency on %s, ignoring: %s",
1392 k ?: t, strerror(-r));
1394 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1402 int config_parse_service_timeout(const char *unit,
1403 const char *filename,
1405 const char *section,
1412 Service *s = userdata;
1420 r = config_parse_sec(unit, filename, line, section, lvalue, ltype,
1421 rvalue, data, userdata);
1425 if (streq(lvalue, "TimeoutSec")) {
1426 s->start_timeout_defined = true;
1427 s->timeout_stop_usec = s->timeout_start_usec;
1428 } else if (streq(lvalue, "TimeoutStartSec"))
1429 s->start_timeout_defined = true;
1434 int config_parse_unit_env_file(const char *unit,
1435 const char *filename,
1437 const char *section,
1446 _cleanup_free_ char *n = NULL;
1455 if (isempty(rvalue)) {
1456 /* Empty assignment frees the list */
1462 r = unit_full_printf(u, rvalue, &n);
1464 log_syntax(unit, LOG_ERR, filename, line, r,
1465 "Failed to resolve specifiers, ignoring: %s", rvalue);
1468 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1469 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1470 "Path '%s' is not absolute, ignoring.", s);
1474 r = strv_extend(env, s);
1481 int config_parse_environ(const char *unit,
1482 const char *filename,
1484 const char *section,
1492 char*** env = data, *w, *state;
1494 _cleanup_free_ char *k = NULL;
1502 if (isempty(rvalue)) {
1503 /* Empty assignment resets the list */
1510 r = unit_full_printf(u, rvalue, &k);
1512 log_syntax(unit, LOG_ERR, filename, line, -r,
1513 "Failed to resolve specifiers, ignoring: %s", rvalue);
1521 FOREACH_WORD_QUOTED(w, l, k, state) {
1522 _cleanup_free_ char *n;
1525 n = cunescape_length(w, l);
1529 if (!env_assignment_is_valid(n)) {
1530 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1531 "Invalid environment assignment, ignoring: %s", rvalue);
1535 x = strv_env_set(*env, n);
1546 int config_parse_ip_tos(const char *unit,
1547 const char *filename,
1549 const char *section,
1556 int *ip_tos = data, x;
1563 x = ip_tos_from_string(rvalue);
1565 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1566 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1574 int config_parse_unit_condition_path(const char *unit,
1575 const char *filename,
1577 const char *section,
1584 ConditionType cond = ltype;
1586 bool trigger, negate;
1588 _cleanup_free_ char *p = NULL;
1596 if (isempty(rvalue)) {
1597 /* Empty assignment resets the list */
1598 condition_free_list(u->conditions);
1599 u->conditions = NULL;
1603 trigger = rvalue[0] == '|';
1607 negate = rvalue[0] == '!';
1611 r = unit_full_printf(u, rvalue, &p);
1613 log_syntax(unit, LOG_ERR, filename, line, -r,
1614 "Failed to resolve specifiers, ignoring: %s", rvalue);
1621 if (!path_is_absolute(p)) {
1622 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1623 "Path in condition not absolute, ignoring: %s", p);
1627 c = condition_new(cond, p, trigger, negate);
1631 LIST_PREPEND(conditions, u->conditions, c);
1635 int config_parse_unit_condition_string(const char *unit,
1636 const char *filename,
1638 const char *section,
1645 ConditionType cond = ltype;
1647 bool trigger, negate;
1649 _cleanup_free_ char *s = NULL;
1657 if (isempty(rvalue)) {
1658 /* Empty assignment resets the list */
1659 condition_free_list(u->conditions);
1660 u->conditions = NULL;
1664 trigger = rvalue[0] == '|';
1668 negate = rvalue[0] == '!';
1672 r = unit_full_printf(u, rvalue, &s);
1674 log_syntax(unit, LOG_ERR, filename, line, -r,
1675 "Failed to resolve specifiers, ignoring: %s", rvalue);
1682 c = condition_new(cond, s, trigger, negate);
1686 LIST_PREPEND(conditions, u->conditions, c);
1690 int config_parse_unit_condition_null(const char *unit,
1691 const char *filename,
1693 const char *section,
1702 bool trigger, negate;
1710 if (isempty(rvalue)) {
1711 /* Empty assignment resets the list */
1712 condition_free_list(u->conditions);
1713 u->conditions = NULL;
1717 trigger = rvalue[0] == '|';
1721 negate = rvalue[0] == '!';
1725 b = parse_boolean(rvalue);
1727 log_syntax(unit, LOG_ERR, filename, line, -b,
1728 "Failed to parse boolean value in condition, ignoring: %s",
1736 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1740 LIST_PREPEND(conditions, u->conditions, c);
1744 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1745 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1747 int config_parse_unit_requires_mounts_for(
1749 const char *filename,
1751 const char *section,
1768 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1770 _cleanup_free_ char *n;
1776 if (!utf8_is_valid(n)) {
1777 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1778 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
1782 r = unit_require_mounts_for(u, n);
1784 log_syntax(unit, LOG_ERR, filename, line, r,
1785 "Failed to add required mount for, ignoring: %s", rvalue);
1793 int config_parse_documentation(const char *unit,
1794 const char *filename,
1796 const char *section,
1812 if (isempty(rvalue)) {
1813 /* Empty assignment resets the list */
1814 strv_free(u->documentation);
1815 u->documentation = NULL;
1819 r = config_parse_unit_strv_printf(unit, filename, line, section, lvalue, ltype,
1820 rvalue, data, userdata);
1824 for (a = b = u->documentation; a && *a; a++) {
1826 if (is_valid_documentation_url(*a))
1829 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1830 "Invalid URL, ignoring: %s", *a);
1840 static void syscall_set(uint32_t *p, int nr) {
1841 nr = SYSCALL_TO_INDEX(nr);
1842 p[nr >> 4] |= 1 << (nr & 31);
1845 static void syscall_unset(uint32_t *p, int nr) {
1846 nr = SYSCALL_TO_INDEX(nr);
1847 p[nr >> 4] &= ~(1 << (nr & 31));
1850 int config_parse_syscall_filter(const char *unit,
1851 const char *filename,
1853 const char *section,
1860 ExecContext *c = data;
1862 bool invert = false;
1872 if (isempty(rvalue)) {
1873 /* Empty assignment resets the list */
1874 free(c->syscall_filter);
1875 c->syscall_filter = NULL;
1879 if (rvalue[0] == '~') {
1884 if (!c->syscall_filter) {
1887 n = (syscall_max() + 31) >> 4;
1888 c->syscall_filter = new(uint32_t, n);
1889 if (!c->syscall_filter)
1892 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
1894 /* Add these by default */
1895 syscall_set(c->syscall_filter, __NR_execve);
1896 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
1897 #ifdef __NR_sigreturn
1898 syscall_set(c->syscall_filter, __NR_sigreturn);
1900 syscall_set(c->syscall_filter, __NR_exit_group);
1901 syscall_set(c->syscall_filter, __NR_exit);
1904 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1906 _cleanup_free_ char *t = NULL;
1912 id = syscall_from_name(t);
1914 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1915 "Failed to parse syscall, ignoring: %s", t);
1920 syscall_unset(c->syscall_filter, id);
1922 syscall_set(c->syscall_filter, id);
1925 c->no_new_privileges = true;
1930 int config_parse_unit_slice(
1932 const char *filename,
1934 const char *section,
1941 _cleanup_free_ char *k = NULL;
1942 Unit *u = userdata, *slice;
1950 r = unit_name_printf(u, rvalue, &k);
1952 log_syntax(unit, LOG_ERR, filename, line, -r,
1953 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
1960 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
1962 log_syntax(unit, LOG_ERR, filename, line, -r,
1963 "Failed to load slice unit %s. Ignoring.", k);
1967 if (slice->type != UNIT_SLICE) {
1968 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1969 "Slice unit %s is not a slice. Ignoring.", k);
1973 unit_ref_set(&u->slice, slice);
1977 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
1979 int config_parse_cpu_shares(
1981 const char *filename,
1983 const char *section,
1990 CGroupContext *c = data;
1998 if (isempty(rvalue)) {
1999 c->cpu_shares = 1024;
2003 r = safe_atolu(rvalue, &lu);
2004 if (r < 0 || lu <= 0) {
2005 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2006 "CPU shares '%s' invalid. Ignoring.", rvalue);
2014 int config_parse_memory_limit(
2016 const char *filename,
2018 const char *section,
2025 CGroupContext *c = data;
2029 if (isempty(rvalue)) {
2030 c->memory_limit = (uint64_t) -1;
2034 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2036 r = parse_bytes(rvalue, &bytes);
2038 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2039 "Memory limit '%s' invalid. Ignoring.", rvalue);
2043 c->memory_limit = (uint64_t) bytes;
2047 int config_parse_device_allow(
2049 const char *filename,
2051 const char *section,
2058 _cleanup_free_ char *path = NULL;
2059 CGroupContext *c = data;
2060 CGroupDeviceAllow *a;
2064 if (isempty(rvalue)) {
2065 while (c->device_allow)
2066 cgroup_context_free_device_allow(c, c->device_allow);
2071 n = strcspn(rvalue, WHITESPACE);
2072 path = strndup(rvalue, n);
2076 if (!path_startswith(path, "/dev")) {
2077 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2078 "Invalid device node path '%s'. Ignoring.", path);
2082 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2086 if (!in_charset(m, "rwm")) {
2087 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2088 "Invalid device rights '%s'. Ignoring.", m);
2092 a = new0(CGroupDeviceAllow, 1);
2098 a->r = !!strchr(m, 'r');
2099 a->w = !!strchr(m, 'w');
2100 a->m = !!strchr(m, 'm');
2102 LIST_PREPEND(device_allow, c->device_allow, a);
2106 int config_parse_blockio_weight(
2108 const char *filename,
2110 const char *section,
2117 CGroupContext *c = data;
2125 if (isempty(rvalue)) {
2126 c->blockio_weight = 1000;
2130 r = safe_atolu(rvalue, &lu);
2131 if (r < 0 || lu < 10 || lu > 1000) {
2132 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2133 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2137 c->blockio_weight = lu;
2142 int config_parse_blockio_device_weight(
2144 const char *filename,
2146 const char *section,
2153 _cleanup_free_ char *path = NULL;
2154 CGroupBlockIODeviceWeight *w;
2155 CGroupContext *c = data;
2165 if (isempty(rvalue)) {
2166 while (c->blockio_device_weights)
2167 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2172 n = strcspn(rvalue, WHITESPACE);
2173 weight = rvalue + n;
2175 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2176 "Expected block device and device weight. Ignoring.");
2180 path = strndup(rvalue, n);
2184 if (!path_startswith(path, "/dev")) {
2185 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2186 "Invalid device node path '%s'. Ignoring.", path);
2190 weight += strspn(weight, WHITESPACE);
2191 r = safe_atolu(weight, &lu);
2192 if (r < 0 || lu < 10 || lu > 1000) {
2193 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2194 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2199 w = new0(CGroupBlockIODeviceWeight, 1);
2208 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2212 int config_parse_blockio_bandwidth(
2214 const char *filename,
2216 const char *section,
2223 _cleanup_free_ char *path = NULL;
2224 CGroupBlockIODeviceBandwidth *b;
2225 CGroupContext *c = data;
2226 const char *bandwidth;
2236 read = streq("BlockIOReadBandwidth", lvalue);
2238 if (isempty(rvalue)) {
2239 CGroupBlockIODeviceBandwidth *next;
2241 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2242 if (b->read == read)
2243 cgroup_context_free_blockio_device_bandwidth(c, b);
2248 n = strcspn(rvalue, WHITESPACE);
2249 bandwidth = rvalue + n;
2250 bandwidth += strspn(bandwidth, WHITESPACE);
2253 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2254 "Expected space separated pair of device node and bandwidth. Ignoring.");
2258 path = strndup(rvalue, n);
2262 if (!path_startswith(path, "/dev")) {
2263 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2264 "Invalid device node path '%s'. Ignoring.", path);
2268 r = parse_bytes(bandwidth, &bytes);
2269 if (r < 0 || bytes <= 0) {
2270 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2271 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2275 b = new0(CGroupBlockIODeviceBandwidth, 1);
2281 b->bandwidth = (uint64_t) bytes;
2284 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2289 #define FOLLOW_MAX 8
2291 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2302 /* This will update the filename pointer if the loaded file is
2303 * reached by a symlink. The old string will be freed. */
2306 char *target, *name;
2308 if (c++ >= FOLLOW_MAX)
2311 path_kill_slashes(*filename);
2313 /* Add the file name we are currently looking at to
2314 * the names of this unit, but only if it is a valid
2316 name = path_get_file_name(*filename);
2318 if (unit_name_is_valid(name, true)) {
2320 id = set_get(names, name);
2326 r = set_consume(names, id);
2332 /* Try to open the file name, but don't if its a symlink */
2333 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2340 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2341 r = readlink_and_make_absolute(*filename, &target);
2349 f = fdopen(fd, "re");
2352 close_nointr_nofail(fd);
2361 static int merge_by_names(Unit **u, Set *names, const char *id) {
2369 /* Let's try to add in all symlink names we found */
2370 while ((k = set_steal_first(names))) {
2372 /* First try to merge in the other name into our
2374 r = unit_merge_by_name(*u, k);
2378 /* Hmm, we couldn't merge the other unit into
2379 * ours? Then let's try it the other way
2382 other = manager_get_unit((*u)->manager, k);
2386 r = unit_merge(other, *u);
2389 return merge_by_names(u, names, NULL);
2397 unit_choose_id(*u, id);
2405 static int load_from_path(Unit *u, const char *path) {
2409 char *filename = NULL, *id = NULL;
2416 symlink_names = set_new(string_hash_func, string_compare_func);
2420 if (path_is_absolute(path)) {
2422 filename = strdup(path);
2428 r = open_follow(&filename, &f, symlink_names, &id);
2440 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2442 /* Instead of opening the path right away, we manually
2443 * follow all symlinks and add their name to our unit
2444 * name set while doing so */
2445 filename = path_make_absolute(path, *p);
2451 if (u->manager->unit_path_cache &&
2452 !set_get(u->manager->unit_path_cache, filename))
2455 r = open_follow(&filename, &f, symlink_names, &id);
2464 /* Empty the symlink names for the next run */
2465 set_clear_free(symlink_names);
2474 /* Hmm, no suitable file found? */
2480 r = merge_by_names(&merged, symlink_names, id);
2485 u->load_state = UNIT_MERGED;
2490 if (fstat(fileno(f), &st) < 0) {
2495 if (null_or_empty(&st))
2496 u->load_state = UNIT_MASKED;
2498 u->load_state = UNIT_LOADED;
2500 /* Now, parse the file contents */
2501 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2502 config_item_perf_lookup,
2503 (void*) load_fragment_gperf_lookup, false, true, u);
2508 free(u->fragment_path);
2509 u->fragment_path = filename;
2512 u->fragment_mtime = timespec_load(&st.st_mtim);
2514 if (u->source_path) {
2515 if (stat(u->source_path, &st) >= 0)
2516 u->source_mtime = timespec_load(&st.st_mtim);
2518 u->source_mtime = 0;
2524 set_free_free(symlink_names);
2533 int unit_load_fragment(Unit *u) {
2539 assert(u->load_state == UNIT_STUB);
2542 /* First, try to find the unit under its id. We always look
2543 * for unit files in the default directories, to make it easy
2544 * to override things by placing things in /etc/systemd/system */
2545 r = load_from_path(u, u->id);
2549 /* Try to find an alias we can load this with */
2550 if (u->load_state == UNIT_STUB)
2551 SET_FOREACH(t, u->names, i) {
2556 r = load_from_path(u, t);
2560 if (u->load_state != UNIT_STUB)
2564 /* And now, try looking for it under the suggested (originally linked) path */
2565 if (u->load_state == UNIT_STUB && u->fragment_path) {
2567 r = load_from_path(u, u->fragment_path);
2571 if (u->load_state == UNIT_STUB) {
2572 /* Hmm, this didn't work? Then let's get rid
2573 * of the fragment path stored for us, so that
2574 * we don't point to an invalid location. */
2575 free(u->fragment_path);
2576 u->fragment_path = NULL;
2580 /* Look for a template */
2581 if (u->load_state == UNIT_STUB && u->instance) {
2584 k = unit_name_template(u->id);
2588 r = load_from_path(u, k);
2594 if (u->load_state == UNIT_STUB)
2595 SET_FOREACH(t, u->names, i) {
2600 k = unit_name_template(t);
2604 r = load_from_path(u, k);
2610 if (u->load_state != UNIT_STUB)
2618 void unit_dump_config_items(FILE *f) {
2619 static const struct {
2620 const ConfigParserCallback callback;
2623 { config_parse_int, "INTEGER" },
2624 { config_parse_unsigned, "UNSIGNED" },
2625 { config_parse_bytes_size, "SIZE" },
2626 { config_parse_bool, "BOOLEAN" },
2627 { config_parse_string, "STRING" },
2628 { config_parse_path, "PATH" },
2629 { config_parse_unit_path_printf, "PATH" },
2630 { config_parse_strv, "STRING [...]" },
2631 { config_parse_exec_nice, "NICE" },
2632 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2633 { config_parse_exec_io_class, "IOCLASS" },
2634 { config_parse_exec_io_priority, "IOPRIORITY" },
2635 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2636 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2637 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2638 { config_parse_mode, "MODE" },
2639 { config_parse_unit_env_file, "FILE" },
2640 { config_parse_output, "OUTPUT" },
2641 { config_parse_input, "INPUT" },
2642 { config_parse_facility, "FACILITY" },
2643 { config_parse_level, "LEVEL" },
2644 { config_parse_exec_capabilities, "CAPABILITIES" },
2645 { config_parse_exec_secure_bits, "SECUREBITS" },
2646 { config_parse_bounding_set, "BOUNDINGSET" },
2647 { config_parse_limit, "LIMIT" },
2648 { config_parse_unit_deps, "UNIT [...]" },
2649 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2650 { config_parse_service_type, "SERVICETYPE" },
2651 { config_parse_service_restart, "SERVICERESTART" },
2652 #ifdef HAVE_SYSV_COMPAT
2653 { config_parse_sysv_priority, "SYSVPRIORITY" },
2655 { config_parse_warn_compat, "NOTSUPPORTED" },
2657 { config_parse_kill_mode, "KILLMODE" },
2658 { config_parse_kill_signal, "SIGNAL" },
2659 { config_parse_socket_listen, "SOCKET [...]" },
2660 { config_parse_socket_bind, "SOCKETBIND" },
2661 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2662 { config_parse_sec, "SECONDS" },
2663 { config_parse_nsec, "NANOSECONDS" },
2664 { config_parse_path_strv, "PATH [...]" },
2665 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2666 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2667 { config_parse_unit_string_printf, "STRING" },
2668 { config_parse_trigger_unit, "UNIT" },
2669 { config_parse_timer, "TIMER" },
2670 { config_parse_path_spec, "PATH" },
2671 { config_parse_notify_access, "ACCESS" },
2672 { config_parse_ip_tos, "TOS" },
2673 { config_parse_unit_condition_path, "CONDITION" },
2674 { config_parse_unit_condition_string, "CONDITION" },
2675 { config_parse_unit_condition_null, "CONDITION" },
2676 { config_parse_unit_slice, "SLICE" },
2677 { config_parse_documentation, "URL" },
2678 { config_parse_service_timeout, "SECONDS" },
2679 { config_parse_start_limit_action, "ACTION" },
2680 { config_parse_set_status, "STATUS" },
2681 { config_parse_service_sockets, "SOCKETS" },
2682 { config_parse_environ, "ENVIRON" },
2683 { config_parse_syscall_filter, "SYSCALL" },
2684 { config_parse_cpu_shares, "SHARES" },
2685 { config_parse_memory_limit, "LIMIT" },
2686 { config_parse_device_allow, "DEVICE" },
2687 { config_parse_device_policy, "POLICY" },
2688 { config_parse_blockio_bandwidth, "BANDWIDTH" },
2689 { config_parse_blockio_weight, "WEIGHT" },
2690 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
2691 { config_parse_long, "LONG" },
2692 { config_parse_socket_service, "SERVICE" },
2695 const char *prev = NULL;
2700 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2701 const char *rvalue = "OTHER", *lvalue;
2705 const ConfigPerfItem *p;
2707 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2709 dot = strchr(i, '.');
2710 lvalue = dot ? dot + 1 : i;
2714 if (!prev || !strneq(prev, i, prefix_len+1)) {
2718 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2721 for (j = 0; j < ELEMENTSOF(table); j++)
2722 if (p->parse == table[j].callback) {
2723 rvalue = table[j].rvalue;
2727 fprintf(f, "%s=%s\n", lvalue, rvalue);