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(SocketPort, port, s->ports, tail);
304 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
306 LIST_PREPEND(SocketPort, 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 int config_parse_fsck_passno(const char *unit,
1037 const char *filename,
1039 const char *section,
1054 r = safe_atoi(rvalue, &i);
1056 log_syntax(unit, LOG_ERR, filename, line, -r,
1057 "Failed to parse fsck pass number, ignoring: %s", rvalue);
1065 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1067 int config_parse_kill_signal(const char *unit,
1068 const char *filename,
1070 const char *section,
1085 r = signal_from_string_try_harder(rvalue);
1087 log_syntax(unit, LOG_ERR, filename, line, -r,
1088 "Failed to parse kill signal, ignoring: %s", rvalue);
1096 int config_parse_exec_mount_flags(const char *unit,
1097 const char *filename,
1099 const char *section,
1106 ExecContext *c = data;
1110 unsigned long flags = 0;
1117 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1118 _cleanup_free_ char *t;
1124 if (streq(t, "shared"))
1126 else if (streq(t, "slave"))
1128 else if (streq(w, "private"))
1129 flags |= MS_PRIVATE;
1131 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1132 "Failed to parse mount flag %s, ignoring: %s",
1138 c->mount_flags = flags;
1142 int config_parse_timer(const char *unit,
1143 const char *filename,
1145 const char *section,
1156 CalendarSpec *c = NULL;
1164 if (isempty(rvalue)) {
1165 /* Empty assignment resets list */
1166 timer_free_values(t);
1170 b = timer_base_from_string(lvalue);
1172 log_syntax(unit, LOG_ERR, filename, line, -b,
1173 "Failed to parse timer base, ignoring: %s", lvalue);
1177 if (b == TIMER_CALENDAR) {
1178 if (calendar_spec_from_string(rvalue, &c) < 0) {
1179 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1180 "Failed to parse calendar specification, ignoring: %s",
1185 id = CLOCK_REALTIME;
1187 if (parse_sec(rvalue, &u) < 0) {
1188 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1189 "Failed to parse timer value, ignoring: %s",
1194 id = CLOCK_MONOTONIC;
1197 v = new0(TimerValue, 1);
1204 v->calendar_spec = c;
1206 LIST_PREPEND(TimerValue, value, t->values, v);
1211 int config_parse_trigger_unit(
1213 const char *filename,
1215 const char *section,
1222 _cleanup_free_ char *p = NULL;
1232 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1233 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1234 "Multiple units to trigger specified, ignoring: %s", rvalue);
1238 r = unit_name_printf(u, rvalue, &p);
1240 log_syntax(unit, LOG_ERR, filename, line, -r,
1241 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1243 type = unit_name_to_type(p ?: rvalue);
1245 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1246 "Unit type not valid, ignoring: %s", rvalue);
1250 if (type == u->type) {
1251 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1252 "Trigger cannot be of same type, ignoring: %s", rvalue);
1256 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1258 log_syntax(unit, LOG_ERR, filename, line, -r,
1259 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1266 int config_parse_path_spec(const char *unit,
1267 const char *filename,
1269 const char *section,
1279 _cleanup_free_ char *k = NULL;
1287 if (isempty(rvalue)) {
1288 /* Empty assignment clears list */
1293 b = path_type_from_string(lvalue);
1295 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1296 "Failed to parse path type, ignoring: %s", lvalue);
1300 r = unit_full_printf(UNIT(p), rvalue, &k);
1306 log_syntax(unit, LOG_ERR, filename, line, -r,
1307 "Failed to resolve unit specifiers on %s. Ignoring.",
1311 if (!path_is_absolute(k)) {
1312 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1313 "Path is not absolute, ignoring: %s", k);
1317 s = new0(PathSpec, 1);
1321 s->path = path_kill_slashes(k);
1326 LIST_PREPEND(PathSpec, spec, p->specs, s);
1331 int config_parse_socket_service(const char *unit,
1332 const char *filename,
1334 const char *section,
1345 _cleanup_free_ char *p = NULL;
1352 dbus_error_init(&error);
1354 r = unit_name_printf(UNIT(s), rvalue, &p);
1356 log_syntax(unit, LOG_ERR, filename, line, -r,
1357 "Failed to resolve specifiers, ignoring: %s", rvalue);
1359 if (!endswith(p ?: rvalue, ".service")) {
1360 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1361 "Unit must be of type service, ignoring: %s", rvalue);
1365 r = manager_load_unit(UNIT(s)->manager, p ?: rvalue, NULL, &error, &x);
1367 log_syntax(unit, LOG_ERR, filename, line, r,
1368 "Failed to load unit %s, ignoring: %s",
1369 rvalue, bus_error(&error, r));
1370 dbus_error_free(&error);
1374 unit_ref_set(&s->service, x);
1379 int config_parse_service_sockets(const char *unit,
1380 const char *filename,
1382 const char *section,
1399 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1400 _cleanup_free_ char *t = NULL, *k = NULL;
1406 r = unit_name_printf(UNIT(s), t, &k);
1408 log_syntax(unit, LOG_ERR, filename, line, -r,
1409 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1411 if (!endswith(k ?: t, ".socket")) {
1412 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1413 "Unit must be of type socket, ignoring: %s", k ?: t);
1417 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1419 log_syntax(unit, LOG_ERR, filename, line, -r,
1420 "Failed to add dependency on %s, ignoring: %s",
1421 k ?: t, strerror(-r));
1423 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1431 int config_parse_service_timeout(const char *unit,
1432 const char *filename,
1434 const char *section,
1441 Service *s = userdata;
1449 r = config_parse_sec(unit, filename, line, section, lvalue, ltype,
1450 rvalue, data, userdata);
1454 if (streq(lvalue, "TimeoutSec")) {
1455 s->start_timeout_defined = true;
1456 s->timeout_stop_usec = s->timeout_start_usec;
1457 } else if (streq(lvalue, "TimeoutStartSec"))
1458 s->start_timeout_defined = true;
1463 int config_parse_unit_env_file(const char *unit,
1464 const char *filename,
1466 const char *section,
1475 _cleanup_free_ char *n = NULL;
1484 if (isempty(rvalue)) {
1485 /* Empty assignment frees the list */
1491 r = unit_full_printf(u, rvalue, &n);
1493 log_syntax(unit, LOG_ERR, filename, line, r,
1494 "Failed to resolve specifiers, ignoring: %s", rvalue);
1497 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1498 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1499 "Path '%s' is not absolute, ignoring.", s);
1503 r = strv_extend(env, s);
1510 int config_parse_environ(const char *unit,
1511 const char *filename,
1513 const char *section,
1521 char*** env = data, *w, *state;
1523 _cleanup_free_ char *k = NULL;
1531 if (isempty(rvalue)) {
1532 /* Empty assignment resets the list */
1539 r = unit_full_printf(u, rvalue, &k);
1541 log_syntax(unit, LOG_ERR, filename, line, -r,
1542 "Failed to resolve specifiers, ignoring: %s", rvalue);
1550 FOREACH_WORD_QUOTED(w, l, k, state) {
1551 _cleanup_free_ char *n;
1554 n = cunescape_length(w, l);
1558 if (!env_assignment_is_valid(n)) {
1559 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1560 "Invalid environment assignment, ignoring: %s", rvalue);
1564 x = strv_env_set(*env, n);
1575 int config_parse_ip_tos(const char *unit,
1576 const char *filename,
1578 const char *section,
1585 int *ip_tos = data, x;
1592 x = ip_tos_from_string(rvalue);
1594 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1595 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1603 int config_parse_unit_condition_path(const char *unit,
1604 const char *filename,
1606 const char *section,
1613 ConditionType cond = ltype;
1615 bool trigger, negate;
1617 _cleanup_free_ char *p = NULL;
1625 if (isempty(rvalue)) {
1626 /* Empty assignment resets the list */
1627 condition_free_list(u->conditions);
1628 u->conditions = NULL;
1632 trigger = rvalue[0] == '|';
1636 negate = rvalue[0] == '!';
1640 r = unit_full_printf(u, rvalue, &p);
1642 log_syntax(unit, LOG_ERR, filename, line, -r,
1643 "Failed to resolve specifiers, ignoring: %s", rvalue);
1650 if (!path_is_absolute(p)) {
1651 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1652 "Path in condition not absolute, ignoring: %s", p);
1656 c = condition_new(cond, p, trigger, negate);
1660 LIST_PREPEND(Condition, conditions, u->conditions, c);
1664 int config_parse_unit_condition_string(const char *unit,
1665 const char *filename,
1667 const char *section,
1674 ConditionType cond = ltype;
1676 bool trigger, negate;
1678 _cleanup_free_ char *s = NULL;
1686 if (isempty(rvalue)) {
1687 /* Empty assignment resets the list */
1688 condition_free_list(u->conditions);
1689 u->conditions = NULL;
1693 trigger = rvalue[0] == '|';
1697 negate = rvalue[0] == '!';
1701 r = unit_full_printf(u, rvalue, &s);
1703 log_syntax(unit, LOG_ERR, filename, line, -r,
1704 "Failed to resolve specifiers, ignoring: %s", rvalue);
1711 c = condition_new(cond, s, trigger, negate);
1715 LIST_PREPEND(Condition, conditions, u->conditions, c);
1719 int config_parse_unit_condition_null(const char *unit,
1720 const char *filename,
1722 const char *section,
1731 bool trigger, negate;
1739 if (isempty(rvalue)) {
1740 /* Empty assignment resets the list */
1741 condition_free_list(u->conditions);
1742 u->conditions = NULL;
1746 trigger = rvalue[0] == '|';
1750 negate = rvalue[0] == '!';
1754 b = parse_boolean(rvalue);
1756 log_syntax(unit, LOG_ERR, filename, line, -b,
1757 "Failed to parse boolean value in condition, ignoring: %s",
1765 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1769 LIST_PREPEND(Condition, conditions, u->conditions, c);
1773 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1774 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1776 int config_parse_unit_requires_mounts_for(const char *unit,
1777 const char *filename,
1779 const char *section,
1795 empty_before = !u->requires_mounts_for;
1797 r = config_parse_path_strv(unit, filename, line, section, lvalue, ltype,
1798 rvalue, data, userdata);
1800 /* Make it easy to find units with requires_mounts set */
1801 if (empty_before && u->requires_mounts_for)
1802 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1807 int config_parse_documentation(const char *unit,
1808 const char *filename,
1810 const char *section,
1826 if (isempty(rvalue)) {
1827 /* Empty assignment resets the list */
1828 strv_free(u->documentation);
1829 u->documentation = NULL;
1833 r = config_parse_unit_strv_printf(unit, filename, line, section, lvalue, ltype,
1834 rvalue, data, userdata);
1838 for (a = b = u->documentation; a && *a; a++) {
1840 if (is_valid_documentation_url(*a))
1843 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1844 "Invalid URL, ignoring: %s", *a);
1853 static void syscall_set(uint32_t *p, int nr) {
1854 nr = SYSCALL_TO_INDEX(nr);
1855 p[nr >> 4] |= 1 << (nr & 31);
1858 static void syscall_unset(uint32_t *p, int nr) {
1859 nr = SYSCALL_TO_INDEX(nr);
1860 p[nr >> 4] &= ~(1 << (nr & 31));
1863 int config_parse_syscall_filter(const char *unit,
1864 const char *filename,
1866 const char *section,
1873 ExecContext *c = data;
1875 bool invert = false;
1885 if (isempty(rvalue)) {
1886 /* Empty assignment resets the list */
1887 free(c->syscall_filter);
1888 c->syscall_filter = NULL;
1892 if (rvalue[0] == '~') {
1897 if (!c->syscall_filter) {
1900 n = (syscall_max() + 31) >> 4;
1901 c->syscall_filter = new(uint32_t, n);
1902 if (!c->syscall_filter)
1905 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
1907 /* Add these by default */
1908 syscall_set(c->syscall_filter, __NR_execve);
1909 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
1910 #ifdef __NR_sigreturn
1911 syscall_set(c->syscall_filter, __NR_sigreturn);
1913 syscall_set(c->syscall_filter, __NR_exit_group);
1914 syscall_set(c->syscall_filter, __NR_exit);
1917 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1919 _cleanup_free_ char *t = NULL;
1925 id = syscall_from_name(t);
1927 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1928 "Failed to parse syscall, ignoring: %s", t);
1933 syscall_unset(c->syscall_filter, id);
1935 syscall_set(c->syscall_filter, id);
1938 c->no_new_privileges = true;
1943 int config_parse_unit_slice(
1945 const char *filename,
1947 const char *section,
1954 _cleanup_free_ char *k = NULL;
1955 Unit *u = userdata, *slice;
1963 r = unit_name_printf(u, rvalue, &k);
1965 log_syntax(unit, LOG_ERR, filename, line, -r,
1966 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
1973 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
1975 log_syntax(unit, LOG_ERR, filename, line, -r,
1976 "Failed to load slice unit %s. Ignoring.", k);
1980 if (slice->type != UNIT_SLICE) {
1981 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1982 "Slice unit %s is not a slice. Ignoring.", k);
1986 unit_ref_set(&u->slice, slice);
1990 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
1992 int config_parse_cpu_shares(
1994 const char *filename,
1996 const char *section,
2003 CGroupContext *c = data;
2011 if (isempty(rvalue)) {
2012 c->cpu_shares = 1024;
2016 r = safe_atolu(rvalue, &lu);
2017 if (r < 0 || lu <= 0) {
2018 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2019 "CPU shares '%s' invalid. Ignoring.", rvalue);
2027 int config_parse_memory_limit(
2029 const char *filename,
2031 const char *section,
2038 CGroupContext *c = data;
2042 if (isempty(rvalue)) {
2043 c->memory_limit = (uint64_t) -1;
2047 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2049 r = parse_bytes(rvalue, &bytes);
2051 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2052 "Memory limit '%s' invalid. Ignoring.", rvalue);
2056 c->memory_limit = (uint64_t) bytes;
2060 int config_parse_device_allow(
2062 const char *filename,
2064 const char *section,
2071 _cleanup_free_ char *path = NULL;
2072 CGroupContext *c = data;
2073 CGroupDeviceAllow *a;
2077 if (isempty(rvalue)) {
2078 while (c->device_allow)
2079 cgroup_context_free_device_allow(c, c->device_allow);
2084 n = strcspn(rvalue, WHITESPACE);
2085 path = strndup(rvalue, n);
2089 if (!path_startswith(path, "/dev")) {
2090 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2091 "Invalid device node path '%s'. Ignoring.", path);
2095 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2099 if (!in_charset(m, "rwm")) {
2100 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2101 "Invalid device rights '%s'. Ignoring.", m);
2105 a = new0(CGroupDeviceAllow, 1);
2111 a->r = !!strchr(m, 'r');
2112 a->w = !!strchr(m, 'w');
2113 a->m = !!strchr(m, 'm');
2115 LIST_PREPEND(CGroupDeviceAllow, device_allow, c->device_allow, a);
2119 int config_parse_blockio_weight(
2121 const char *filename,
2123 const char *section,
2130 CGroupContext *c = data;
2138 if (isempty(rvalue)) {
2139 c->blockio_weight = 1000;
2143 r = safe_atolu(rvalue, &lu);
2144 if (r < 0 || lu < 10 || lu > 1000) {
2145 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2146 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2150 c->blockio_weight = lu;
2155 int config_parse_blockio_device_weight(
2157 const char *filename,
2159 const char *section,
2166 _cleanup_free_ char *path = NULL;
2167 CGroupBlockIODeviceWeight *w;
2168 CGroupContext *c = data;
2178 if (isempty(rvalue)) {
2179 while (c->blockio_device_weights)
2180 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2185 n = strcspn(rvalue, WHITESPACE);
2186 weight = rvalue + n;
2188 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2189 "Expected block device and device weight. Ignoring.");
2193 path = strndup(rvalue, n);
2197 if (!path_startswith(path, "/dev")) {
2198 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2199 "Invalid device node path '%s'. Ignoring.", path);
2203 weight += strspn(weight, WHITESPACE);
2204 r = safe_atolu(weight, &lu);
2205 if (r < 0 || lu < 10 || lu > 1000) {
2206 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2207 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2212 w = new0(CGroupBlockIODeviceWeight, 1);
2221 LIST_PREPEND(CGroupBlockIODeviceWeight, device_weights, c->blockio_device_weights, w);
2225 int config_parse_blockio_bandwidth(
2227 const char *filename,
2229 const char *section,
2236 _cleanup_free_ char *path = NULL;
2237 CGroupBlockIODeviceBandwidth *b;
2238 CGroupContext *c = data;
2239 const char *bandwidth;
2249 read = streq("BlockIOReadBandwidth", lvalue);
2251 if (isempty(rvalue)) {
2252 CGroupBlockIODeviceBandwidth *next;
2254 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2255 if (b->read == read)
2256 cgroup_context_free_blockio_device_bandwidth(c, b);
2261 n = strcspn(rvalue, WHITESPACE);
2262 bandwidth = rvalue + n;
2263 bandwidth += strspn(bandwidth, WHITESPACE);
2266 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2267 "Expected space separated pair of device node and bandwidth. Ignoring.");
2271 path = strndup(rvalue, n);
2275 if (!path_startswith(path, "/dev")) {
2276 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2277 "Invalid device node path '%s'. Ignoring.", path);
2281 r = parse_bytes(bandwidth, &bytes);
2282 if (r < 0 || bytes <= 0) {
2283 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2284 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2288 b = new0(CGroupBlockIODeviceBandwidth, 1);
2294 b->bandwidth = (uint64_t) bytes;
2297 LIST_PREPEND(CGroupBlockIODeviceBandwidth, device_bandwidths, c->blockio_device_bandwidths, b);
2302 #define FOLLOW_MAX 8
2304 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2315 /* This will update the filename pointer if the loaded file is
2316 * reached by a symlink. The old string will be freed. */
2319 char *target, *name;
2321 if (c++ >= FOLLOW_MAX)
2324 path_kill_slashes(*filename);
2326 /* Add the file name we are currently looking at to
2327 * the names of this unit, but only if it is a valid
2329 name = path_get_file_name(*filename);
2331 if (unit_name_is_valid(name, true)) {
2333 id = set_get(names, name);
2339 r = set_consume(names, id);
2345 /* Try to open the file name, but don't if its a symlink */
2346 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2353 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2354 r = readlink_and_make_absolute(*filename, &target);
2362 f = fdopen(fd, "re");
2365 close_nointr_nofail(fd);
2374 static int merge_by_names(Unit **u, Set *names, const char *id) {
2382 /* Let's try to add in all symlink names we found */
2383 while ((k = set_steal_first(names))) {
2385 /* First try to merge in the other name into our
2387 r = unit_merge_by_name(*u, k);
2391 /* Hmm, we couldn't merge the other unit into
2392 * ours? Then let's try it the other way
2395 other = manager_get_unit((*u)->manager, k);
2399 r = unit_merge(other, *u);
2402 return merge_by_names(u, names, NULL);
2410 unit_choose_id(*u, id);
2418 static int load_from_path(Unit *u, const char *path) {
2422 char *filename = NULL, *id = NULL;
2429 symlink_names = set_new(string_hash_func, string_compare_func);
2433 if (path_is_absolute(path)) {
2435 filename = strdup(path);
2441 r = open_follow(&filename, &f, symlink_names, &id);
2453 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2455 /* Instead of opening the path right away, we manually
2456 * follow all symlinks and add their name to our unit
2457 * name set while doing so */
2458 filename = path_make_absolute(path, *p);
2464 if (u->manager->unit_path_cache &&
2465 !set_get(u->manager->unit_path_cache, filename))
2468 r = open_follow(&filename, &f, symlink_names, &id);
2477 /* Empty the symlink names for the next run */
2478 set_clear_free(symlink_names);
2487 /* Hmm, no suitable file found? */
2493 r = merge_by_names(&merged, symlink_names, id);
2498 u->load_state = UNIT_MERGED;
2503 if (fstat(fileno(f), &st) < 0) {
2508 if (null_or_empty(&st))
2509 u->load_state = UNIT_MASKED;
2511 u->load_state = UNIT_LOADED;
2513 /* Now, parse the file contents */
2514 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2515 config_item_perf_lookup,
2516 (void*) load_fragment_gperf_lookup, false, true, u);
2521 free(u->fragment_path);
2522 u->fragment_path = filename;
2525 u->fragment_mtime = timespec_load(&st.st_mtim);
2527 if (u->source_path) {
2528 if (stat(u->source_path, &st) >= 0)
2529 u->source_mtime = timespec_load(&st.st_mtim);
2531 u->source_mtime = 0;
2537 set_free_free(symlink_names);
2546 int unit_load_fragment(Unit *u) {
2552 assert(u->load_state == UNIT_STUB);
2555 /* First, try to find the unit under its id. We always look
2556 * for unit files in the default directories, to make it easy
2557 * to override things by placing things in /etc/systemd/system */
2558 r = load_from_path(u, u->id);
2562 /* Try to find an alias we can load this with */
2563 if (u->load_state == UNIT_STUB)
2564 SET_FOREACH(t, u->names, i) {
2569 r = load_from_path(u, t);
2573 if (u->load_state != UNIT_STUB)
2577 /* And now, try looking for it under the suggested (originally linked) path */
2578 if (u->load_state == UNIT_STUB && u->fragment_path) {
2580 r = load_from_path(u, u->fragment_path);
2584 if (u->load_state == UNIT_STUB) {
2585 /* Hmm, this didn't work? Then let's get rid
2586 * of the fragment path stored for us, so that
2587 * we don't point to an invalid location. */
2588 free(u->fragment_path);
2589 u->fragment_path = NULL;
2593 /* Look for a template */
2594 if (u->load_state == UNIT_STUB && u->instance) {
2597 k = unit_name_template(u->id);
2601 r = load_from_path(u, k);
2607 if (u->load_state == UNIT_STUB)
2608 SET_FOREACH(t, u->names, i) {
2613 k = unit_name_template(t);
2617 r = load_from_path(u, k);
2623 if (u->load_state != UNIT_STUB)
2631 void unit_dump_config_items(FILE *f) {
2632 static const struct {
2633 const ConfigParserCallback callback;
2636 { config_parse_int, "INTEGER" },
2637 { config_parse_unsigned, "UNSIGNED" },
2638 { config_parse_bytes_size, "SIZE" },
2639 { config_parse_bool, "BOOLEAN" },
2640 { config_parse_string, "STRING" },
2641 { config_parse_path, "PATH" },
2642 { config_parse_unit_path_printf, "PATH" },
2643 { config_parse_strv, "STRING [...]" },
2644 { config_parse_exec_nice, "NICE" },
2645 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2646 { config_parse_exec_io_class, "IOCLASS" },
2647 { config_parse_exec_io_priority, "IOPRIORITY" },
2648 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2649 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2650 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2651 { config_parse_mode, "MODE" },
2652 { config_parse_unit_env_file, "FILE" },
2653 { config_parse_output, "OUTPUT" },
2654 { config_parse_input, "INPUT" },
2655 { config_parse_facility, "FACILITY" },
2656 { config_parse_level, "LEVEL" },
2657 { config_parse_exec_capabilities, "CAPABILITIES" },
2658 { config_parse_exec_secure_bits, "SECUREBITS" },
2659 { config_parse_bounding_set, "BOUNDINGSET" },
2660 { config_parse_limit, "LIMIT" },
2661 { config_parse_unit_deps, "UNIT [...]" },
2662 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2663 { config_parse_service_type, "SERVICETYPE" },
2664 { config_parse_service_restart, "SERVICERESTART" },
2665 #ifdef HAVE_SYSV_COMPAT
2666 { config_parse_sysv_priority, "SYSVPRIORITY" },
2668 { config_parse_warn_compat, "NOTSUPPORTED" },
2670 { config_parse_kill_mode, "KILLMODE" },
2671 { config_parse_kill_signal, "SIGNAL" },
2672 { config_parse_socket_listen, "SOCKET [...]" },
2673 { config_parse_socket_bind, "SOCKETBIND" },
2674 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2675 { config_parse_sec, "SECONDS" },
2676 { config_parse_nsec, "NANOSECONDS" },
2677 { config_parse_path_strv, "PATH [...]" },
2678 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2679 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2680 { config_parse_unit_string_printf, "STRING" },
2681 { config_parse_trigger_unit, "UNIT" },
2682 { config_parse_timer, "TIMER" },
2683 { config_parse_path_spec, "PATH" },
2684 { config_parse_notify_access, "ACCESS" },
2685 { config_parse_ip_tos, "TOS" },
2686 { config_parse_unit_condition_path, "CONDITION" },
2687 { config_parse_unit_condition_string, "CONDITION" },
2688 { config_parse_unit_condition_null, "CONDITION" },
2689 { config_parse_unit_slice, "SLICE" },
2690 { config_parse_documentation, "URL" },
2691 { config_parse_service_timeout, "SECONDS" },
2692 { config_parse_start_limit_action, "ACTION" },
2693 { config_parse_set_status, "STATUS" },
2694 { config_parse_service_sockets, "SOCKETS" },
2695 { config_parse_fsck_passno, "PASSNO" },
2696 { config_parse_environ, "ENVIRON" },
2697 { config_parse_syscall_filter, "SYSCALL" },
2698 { config_parse_cpu_shares, "SHARES" },
2699 { config_parse_memory_limit, "LIMIT" },
2700 { config_parse_device_allow, "DEVICE" },
2701 { config_parse_device_policy, "POLICY" },
2702 { config_parse_blockio_bandwidth, "BANDWIDTH" },
2703 { config_parse_blockio_weight, "WEIGHT" },
2704 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
2705 { config_parse_long, "LONG" },
2706 { config_parse_socket_service, "SERVICE" },
2709 const char *prev = NULL;
2714 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2715 const char *rvalue = "OTHER", *lvalue;
2719 const ConfigPerfItem *p;
2721 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2723 dot = strchr(i, '.');
2724 lvalue = dot ? dot + 1 : i;
2728 if (!prev || !strneq(prev, i, prefix_len+1)) {
2732 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2735 for (j = 0; j < ELEMENTSOF(table); j++)
2736 if (p->parse == table[j].callback) {
2737 rvalue = table[j].rvalue;
2741 fprintf(f, "%s=%s\n", lvalue, rvalue);