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 "sd-messages.h"
40 #include "conf-parser.h"
41 #include "load-fragment.h"
44 #include "securebits.h"
46 #include "unit-name.h"
47 #include "unit-printf.h"
48 #include "dbus-common.h"
50 #include "path-util.h"
51 #include "syscall-list.h"
55 #ifndef HAVE_SYSV_COMPAT
56 int config_parse_warn_compat(const char *unit,
66 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
67 "Support for option %s= has been disabled at compile time and is ignored",
73 int config_parse_unit_deps(const char* unit,
83 UnitDependency d = ltype;
93 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
94 _cleanup_free_ char *t = NULL, *k = NULL;
101 r = unit_name_printf(u, t, &k);
103 log_syntax(unit, LOG_ERR, filename, line, -r,
104 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
108 r = unit_add_dependency_by_name(u, d, k, NULL, true);
110 log_syntax(unit, LOG_ERR, filename, line, -r,
111 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
117 int config_parse_unit_string_printf(const char *unit,
118 const char *filename,
128 _cleanup_free_ char *k = NULL;
136 r = unit_full_printf(u, rvalue, &k);
138 log_syntax(unit, LOG_ERR, filename, line, -r,
139 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
141 return config_parse_string(unit, filename, line, section, lvalue, ltype,
142 k ? k : rvalue, data, userdata);
145 int config_parse_unit_strv_printf(const char *unit,
146 const char *filename,
156 _cleanup_free_ char *k = NULL;
164 r = unit_full_printf(u, rvalue, &k);
166 log_syntax(unit, LOG_ERR, filename, line, -r,
167 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
169 return config_parse_strv(unit, filename, line, section, lvalue, ltype,
170 k ? k : rvalue, data, userdata);
173 int config_parse_unit_path_printf(const char *unit,
174 const char *filename,
184 _cleanup_free_ char *k = NULL;
192 r = unit_full_printf(u, rvalue, &k);
194 log_syntax(unit, LOG_ERR, filename, line, -r,
195 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
197 return config_parse_path(unit, filename, line, section, lvalue, ltype,
198 k ? k : rvalue, data, userdata);
201 int config_parse_socket_listen(const char *unit,
202 const char *filename,
211 SocketPort *p, *tail;
222 if (isempty(rvalue)) {
223 /* An empty assignment removes all ports */
224 socket_free_ports(s);
228 p = new0(SocketPort, 1);
232 if (ltype != SOCKET_SOCKET) {
235 r = unit_full_printf(UNIT(s), rvalue, &p->path);
237 p->path = strdup(rvalue);
242 log_syntax(unit, LOG_ERR, filename, line, -r,
243 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
246 path_kill_slashes(p->path);
248 } else if (streq(lvalue, "ListenNetlink")) {
249 _cleanup_free_ char *k = NULL;
251 p->type = SOCKET_SOCKET;
252 r = unit_full_printf(UNIT(s), rvalue, &k);
254 log_syntax(unit, LOG_ERR, filename, line, -r,
255 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
257 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
259 log_syntax(unit, LOG_ERR, filename, line, -r,
260 "Failed to parse address value, ignoring: %s", rvalue);
266 _cleanup_free_ char *k = NULL;
268 p->type = SOCKET_SOCKET;
269 r = unit_full_printf(UNIT(s), rvalue, &k);
271 log_syntax(unit, LOG_ERR, filename, line, -r,
272 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
274 r = socket_address_parse(&p->address, k ? k : rvalue);
276 log_syntax(unit, LOG_ERR, filename, line, -r,
277 "Failed to parse address value, ignoring: %s", rvalue);
282 if (streq(lvalue, "ListenStream"))
283 p->address.type = SOCK_STREAM;
284 else if (streq(lvalue, "ListenDatagram"))
285 p->address.type = SOCK_DGRAM;
287 assert(streq(lvalue, "ListenSequentialPacket"));
288 p->address.type = SOCK_SEQPACKET;
291 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
292 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
293 "Address family not supported, ignoring: %s", rvalue);
302 LIST_FIND_TAIL(port, s->ports, tail);
303 LIST_INSERT_AFTER(port, s->ports, tail, p);
305 LIST_PREPEND(port, s->ports, p);
310 int config_parse_socket_bind(const char *unit,
311 const char *filename,
321 SocketAddressBindIPv6Only b;
330 b = socket_address_bind_ipv6_only_from_string(rvalue);
334 r = parse_boolean(rvalue);
336 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
337 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
341 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
343 s->bind_ipv6_only = b;
348 int config_parse_exec_nice(const char *unit,
349 const char *filename,
358 ExecContext *c = data;
366 r = safe_atoi(rvalue, &priority);
368 log_syntax(unit, LOG_ERR, filename, line, -r,
369 "Failed to parse nice priority, ignoring: %s. ", rvalue);
373 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
374 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
375 "Nice priority out of range, ignoring: %s", rvalue);
385 int config_parse_exec_oom_score_adjust(const char* unit,
386 const char *filename,
395 ExecContext *c = data;
403 r = safe_atoi(rvalue, &oa);
405 log_syntax(unit, LOG_ERR, filename, line, -r,
406 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
410 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
411 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
412 "OOM score adjust value out of range, ignoring: %s", rvalue);
416 c->oom_score_adjust = oa;
417 c->oom_score_adjust_set = true;
422 int config_parse_exec(const char *unit,
423 const char *filename,
432 ExecCommand **e = data, *nce;
444 if (isempty(rvalue)) {
445 /* An empty assignment resets the list */
446 exec_command_free_list(*e);
451 /* We accept an absolute path as first argument, or
452 * alternatively an absolute prefixed with @ to allow
453 * overriding of argv[0]. */
459 bool honour_argv0 = false, ignore = false;
465 rvalue += strspn(rvalue, WHITESPACE);
470 for (i = 0; i < 2; i++) {
471 if (rvalue[0] == '-' && !ignore) {
476 if (rvalue[0] == '@' && !honour_argv0) {
482 if (*rvalue != '/') {
483 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
484 "Executable path is not absolute, ignoring: %s", rvalue);
489 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
490 if (strneq(w, ";", MAX(l, 1U)))
496 n = new(char*, k + !honour_argv0);
501 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
502 if (strneq(w, ";", MAX(l, 1U)))
504 else if (strneq(w, "\\;", MAX(l, 1U)))
507 if (honour_argv0 && w == rvalue) {
510 path = strndup(w, l);
516 if (!utf8_is_valid(path)) {
517 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
518 "Path is not UTF-8 clean, ignoring assignment: %s",
527 c = n[k++] = cunescape_length(w, l);
533 if (!utf8_is_valid(c)) {
534 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
535 "Path is not UTF-8 clean, ignoring assignment: %s",
546 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
547 "Invalid command line, ignoring: %s", rvalue);
560 assert(path_is_absolute(path));
562 nce = new0(ExecCommand, 1);
570 nce->ignore = ignore;
572 path_kill_slashes(nce->path);
574 exec_command_append_list(e, nce);
590 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
591 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
593 int config_parse_socket_bindtodevice(const char* unit,
594 const char *filename,
611 if (rvalue[0] && !streq(rvalue, "*")) {
618 free(s->bind_to_device);
619 s->bind_to_device = n;
624 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
625 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
627 int config_parse_exec_io_class(const char *unit,
628 const char *filename,
637 ExecContext *c = data;
645 x = ioprio_class_from_string(rvalue);
647 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
648 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
652 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
653 c->ioprio_set = true;
658 int config_parse_exec_io_priority(const char *unit,
659 const char *filename,
668 ExecContext *c = data;
676 r = safe_atoi(rvalue, &i);
677 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
678 log_syntax(unit, LOG_ERR, filename, line, -r,
679 "Failed to parse IO priority, ignoring: %s", rvalue);
683 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
684 c->ioprio_set = true;
689 int config_parse_exec_cpu_sched_policy(const char *unit,
690 const char *filename,
700 ExecContext *c = data;
708 x = sched_policy_from_string(rvalue);
710 log_syntax(unit, LOG_ERR, filename, line, -x,
711 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
715 c->cpu_sched_policy = x;
716 /* Moving to or from real-time policy? We need to adjust the priority */
717 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
718 c->cpu_sched_set = true;
723 int config_parse_exec_cpu_sched_prio(const char *unit,
724 const char *filename,
733 ExecContext *c = data;
741 r = safe_atoi(rvalue, &i);
743 log_syntax(unit, LOG_ERR, filename, line, -r,
744 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
748 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
749 min = sched_get_priority_min(c->cpu_sched_policy);
750 max = sched_get_priority_max(c->cpu_sched_policy);
752 if (i < min || i > max) {
753 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
754 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
758 c->cpu_sched_priority = i;
759 c->cpu_sched_set = true;
764 int config_parse_exec_cpu_affinity(const char *unit,
765 const char *filename,
774 ExecContext *c = data;
784 if (isempty(rvalue)) {
785 /* An empty assignment resets the CPU list */
792 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
793 _cleanup_free_ char *t = NULL;
801 r = safe_atou(t, &cpu);
804 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
809 if (r < 0 || cpu >= c->cpuset_ncpus) {
810 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
811 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
815 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
821 int config_parse_exec_capabilities(const char *unit,
822 const char *filename,
831 ExecContext *c = data;
839 cap = cap_from_text(rvalue);
841 log_syntax(unit, LOG_ERR, filename, line, errno,
842 "Failed to parse capabilities, ignoring: %s", rvalue);
847 cap_free(c->capabilities);
848 c->capabilities = cap;
853 int config_parse_exec_secure_bits(const char *unit,
854 const char *filename,
863 ExecContext *c = data;
873 if (isempty(rvalue)) {
874 /* An empty assignment resets the field */
879 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
880 if (first_word(w, "keep-caps"))
881 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
882 else if (first_word(w, "keep-caps-locked"))
883 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
884 else if (first_word(w, "no-setuid-fixup"))
885 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
886 else if (first_word(w, "no-setuid-fixup-locked"))
887 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
888 else if (first_word(w, "noroot"))
889 c->secure_bits |= 1<<SECURE_NOROOT;
890 else if (first_word(w, "noroot-locked"))
891 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
893 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
894 "Failed to parse secure bits, ignoring: %s", rvalue);
902 int config_parse_bounding_set(const char *unit,
903 const char *filename,
912 uint64_t *capability_bounding_set_drop = data;
924 if (rvalue[0] == '~') {
929 /* Note that we store this inverted internally, since the
930 * kernel wants it like this. But we actually expose it
931 * non-inverted everywhere to have a fully normalized
934 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
935 _cleanup_free_ char *t = NULL;
943 r = cap_from_name(t, &cap);
945 log_syntax(unit, LOG_ERR, filename, line, errno,
946 "Failed to parse capability in bounding set, ignoring: %s", t);
950 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
954 *capability_bounding_set_drop |= sum;
956 *capability_bounding_set_drop |= ~sum;
961 int config_parse_limit(const char *unit,
962 const char *filename,
971 struct rlimit **rl = data;
972 unsigned long long u;
981 if (streq(rvalue, "infinity"))
982 u = (unsigned long long) RLIM_INFINITY;
986 r = safe_atollu(rvalue, &u);
988 log_syntax(unit, LOG_ERR, filename, line, -r,
989 "Failed to parse resource value, ignoring: %s", rvalue);
995 *rl = new(struct rlimit, 1);
1000 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1004 #ifdef HAVE_SYSV_COMPAT
1005 int config_parse_sysv_priority(const char *unit,
1006 const char *filename,
1008 const char *section,
1015 int *priority = data;
1023 r = safe_atoi(rvalue, &i);
1024 if (r < 0 || i < 0) {
1025 log_syntax(unit, LOG_ERR, filename, line, -r,
1026 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1030 *priority = (int) i;
1035 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1037 int config_parse_kill_signal(const char *unit,
1038 const char *filename,
1040 const char *section,
1055 r = signal_from_string_try_harder(rvalue);
1057 log_syntax(unit, LOG_ERR, filename, line, -r,
1058 "Failed to parse kill signal, ignoring: %s", rvalue);
1066 int config_parse_exec_mount_flags(const char *unit,
1067 const char *filename,
1069 const char *section,
1076 ExecContext *c = data;
1080 unsigned long flags = 0;
1087 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1088 _cleanup_free_ char *t;
1094 if (streq(t, "shared"))
1096 else if (streq(t, "slave"))
1098 else if (streq(w, "private"))
1099 flags |= MS_PRIVATE;
1101 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1102 "Failed to parse mount flag %s, ignoring: %s",
1108 c->mount_flags = flags;
1112 int config_parse_timer(const char *unit,
1113 const char *filename,
1115 const char *section,
1126 CalendarSpec *c = NULL;
1134 if (isempty(rvalue)) {
1135 /* Empty assignment resets list */
1136 timer_free_values(t);
1140 b = timer_base_from_string(lvalue);
1142 log_syntax(unit, LOG_ERR, filename, line, -b,
1143 "Failed to parse timer base, ignoring: %s", lvalue);
1147 if (b == TIMER_CALENDAR) {
1148 if (calendar_spec_from_string(rvalue, &c) < 0) {
1149 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1150 "Failed to parse calendar specification, ignoring: %s",
1155 id = CLOCK_REALTIME;
1157 if (parse_sec(rvalue, &u) < 0) {
1158 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1159 "Failed to parse timer value, ignoring: %s",
1164 id = CLOCK_MONOTONIC;
1167 v = new0(TimerValue, 1);
1174 v->calendar_spec = c;
1176 LIST_PREPEND(value, t->values, v);
1181 int config_parse_trigger_unit(
1183 const char *filename,
1185 const char *section,
1192 _cleanup_free_ char *p = NULL;
1202 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1203 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1204 "Multiple units to trigger specified, ignoring: %s", rvalue);
1208 r = unit_name_printf(u, rvalue, &p);
1210 log_syntax(unit, LOG_ERR, filename, line, -r,
1211 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1213 type = unit_name_to_type(p ?: rvalue);
1215 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1216 "Unit type not valid, ignoring: %s", rvalue);
1220 if (type == u->type) {
1221 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1222 "Trigger cannot be of same type, ignoring: %s", rvalue);
1226 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1228 log_syntax(unit, LOG_ERR, filename, line, -r,
1229 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1236 int config_parse_path_spec(const char *unit,
1237 const char *filename,
1239 const char *section,
1249 _cleanup_free_ char *k = NULL;
1257 if (isempty(rvalue)) {
1258 /* Empty assignment clears list */
1263 b = path_type_from_string(lvalue);
1265 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1266 "Failed to parse path type, ignoring: %s", lvalue);
1270 r = unit_full_printf(UNIT(p), rvalue, &k);
1276 log_syntax(unit, LOG_ERR, filename, line, -r,
1277 "Failed to resolve unit specifiers on %s. Ignoring.",
1281 if (!path_is_absolute(k)) {
1282 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1283 "Path is not absolute, ignoring: %s", k);
1287 s = new0(PathSpec, 1);
1291 s->path = path_kill_slashes(k);
1296 LIST_PREPEND(spec, p->specs, s);
1301 int config_parse_socket_service(const char *unit,
1302 const char *filename,
1304 const char *section,
1315 _cleanup_free_ char *p = NULL;
1322 dbus_error_init(&error);
1324 r = unit_name_printf(UNIT(s), rvalue, &p);
1326 log_syntax(unit, LOG_ERR, filename, line, -r,
1327 "Failed to resolve specifiers, ignoring: %s", rvalue);
1329 if (!endswith(p ?: rvalue, ".service")) {
1330 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1331 "Unit must be of type service, ignoring: %s", rvalue);
1335 r = manager_load_unit(UNIT(s)->manager, p ?: rvalue, NULL, &error, &x);
1337 log_syntax(unit, LOG_ERR, filename, line, r,
1338 "Failed to load unit %s, ignoring: %s",
1339 rvalue, bus_error(&error, r));
1340 dbus_error_free(&error);
1344 unit_ref_set(&s->service, x);
1349 int config_parse_service_sockets(const char *unit,
1350 const char *filename,
1352 const char *section,
1369 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1370 _cleanup_free_ char *t = NULL, *k = NULL;
1376 r = unit_name_printf(UNIT(s), t, &k);
1378 log_syntax(unit, LOG_ERR, filename, line, -r,
1379 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1381 if (!endswith(k ?: t, ".socket")) {
1382 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1383 "Unit must be of type socket, ignoring: %s", k ?: t);
1387 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1389 log_syntax(unit, LOG_ERR, filename, line, -r,
1390 "Failed to add dependency on %s, ignoring: %s",
1391 k ?: t, strerror(-r));
1393 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1401 int config_parse_service_timeout(const char *unit,
1402 const char *filename,
1404 const char *section,
1411 Service *s = userdata;
1419 r = config_parse_sec(unit, filename, line, section, lvalue, ltype,
1420 rvalue, data, userdata);
1424 if (streq(lvalue, "TimeoutSec")) {
1425 s->start_timeout_defined = true;
1426 s->timeout_stop_usec = s->timeout_start_usec;
1427 } else if (streq(lvalue, "TimeoutStartSec"))
1428 s->start_timeout_defined = true;
1433 int config_parse_unit_env_file(const char *unit,
1434 const char *filename,
1436 const char *section,
1445 _cleanup_free_ char *n = NULL;
1454 if (isempty(rvalue)) {
1455 /* Empty assignment frees the list */
1461 r = unit_full_printf(u, rvalue, &n);
1463 log_syntax(unit, LOG_ERR, filename, line, r,
1464 "Failed to resolve specifiers, ignoring: %s", rvalue);
1467 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1468 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1469 "Path '%s' is not absolute, ignoring.", s);
1473 r = strv_extend(env, s);
1480 int config_parse_environ(const char *unit,
1481 const char *filename,
1483 const char *section,
1491 char*** env = data, *w, *state;
1493 _cleanup_free_ char *k = NULL;
1501 if (isempty(rvalue)) {
1502 /* Empty assignment resets the list */
1509 r = unit_full_printf(u, rvalue, &k);
1511 log_syntax(unit, LOG_ERR, filename, line, -r,
1512 "Failed to resolve specifiers, ignoring: %s", rvalue);
1520 FOREACH_WORD_QUOTED(w, l, k, state) {
1521 _cleanup_free_ char *n;
1524 n = cunescape_length(w, l);
1528 if (!env_assignment_is_valid(n)) {
1529 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1530 "Invalid environment assignment, ignoring: %s", rvalue);
1534 x = strv_env_set(*env, n);
1545 int config_parse_ip_tos(const char *unit,
1546 const char *filename,
1548 const char *section,
1555 int *ip_tos = data, x;
1562 x = ip_tos_from_string(rvalue);
1564 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1565 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1573 int config_parse_unit_condition_path(const char *unit,
1574 const char *filename,
1576 const char *section,
1583 ConditionType cond = ltype;
1585 bool trigger, negate;
1587 _cleanup_free_ char *p = NULL;
1595 if (isempty(rvalue)) {
1596 /* Empty assignment resets the list */
1597 condition_free_list(u->conditions);
1598 u->conditions = NULL;
1602 trigger = rvalue[0] == '|';
1606 negate = rvalue[0] == '!';
1610 r = unit_full_printf(u, rvalue, &p);
1612 log_syntax(unit, LOG_ERR, filename, line, -r,
1613 "Failed to resolve specifiers, ignoring: %s", rvalue);
1620 if (!path_is_absolute(p)) {
1621 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1622 "Path in condition not absolute, ignoring: %s", p);
1626 c = condition_new(cond, p, trigger, negate);
1630 LIST_PREPEND(conditions, u->conditions, c);
1634 int config_parse_unit_condition_string(const char *unit,
1635 const char *filename,
1637 const char *section,
1644 ConditionType cond = ltype;
1646 bool trigger, negate;
1648 _cleanup_free_ char *s = NULL;
1656 if (isempty(rvalue)) {
1657 /* Empty assignment resets the list */
1658 condition_free_list(u->conditions);
1659 u->conditions = NULL;
1663 trigger = rvalue[0] == '|';
1667 negate = rvalue[0] == '!';
1671 r = unit_full_printf(u, rvalue, &s);
1673 log_syntax(unit, LOG_ERR, filename, line, -r,
1674 "Failed to resolve specifiers, ignoring: %s", rvalue);
1681 c = condition_new(cond, s, trigger, negate);
1685 LIST_PREPEND(conditions, u->conditions, c);
1689 int config_parse_unit_condition_null(const char *unit,
1690 const char *filename,
1692 const char *section,
1701 bool trigger, negate;
1709 if (isempty(rvalue)) {
1710 /* Empty assignment resets the list */
1711 condition_free_list(u->conditions);
1712 u->conditions = NULL;
1716 trigger = rvalue[0] == '|';
1720 negate = rvalue[0] == '!';
1724 b = parse_boolean(rvalue);
1726 log_syntax(unit, LOG_ERR, filename, line, -b,
1727 "Failed to parse boolean value in condition, ignoring: %s",
1735 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1739 LIST_PREPEND(conditions, u->conditions, c);
1743 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1744 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1746 int config_parse_unit_requires_mounts_for(
1748 const char *filename,
1750 const char *section,
1767 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1769 _cleanup_free_ char *n;
1775 if (!utf8_is_valid(n)) {
1776 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1777 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
1781 r = unit_require_mounts_for(u, n);
1783 log_syntax(unit, LOG_ERR, filename, line, r,
1784 "Failed to add required mount for, ignoring: %s", rvalue);
1792 int config_parse_documentation(const char *unit,
1793 const char *filename,
1795 const char *section,
1811 if (isempty(rvalue)) {
1812 /* Empty assignment resets the list */
1813 strv_free(u->documentation);
1814 u->documentation = NULL;
1818 r = config_parse_unit_strv_printf(unit, filename, line, section, lvalue, ltype,
1819 rvalue, data, userdata);
1823 for (a = b = u->documentation; a && *a; a++) {
1825 if (is_valid_documentation_url(*a))
1828 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1829 "Invalid URL, ignoring: %s", *a);
1839 static void syscall_set(uint32_t *p, int nr) {
1840 nr = SYSCALL_TO_INDEX(nr);
1841 p[nr >> 4] |= 1 << (nr & 31);
1844 static void syscall_unset(uint32_t *p, int nr) {
1845 nr = SYSCALL_TO_INDEX(nr);
1846 p[nr >> 4] &= ~(1 << (nr & 31));
1849 int config_parse_syscall_filter(const char *unit,
1850 const char *filename,
1852 const char *section,
1859 ExecContext *c = data;
1861 bool invert = false;
1871 if (isempty(rvalue)) {
1872 /* Empty assignment resets the list */
1873 free(c->syscall_filter);
1874 c->syscall_filter = NULL;
1878 if (rvalue[0] == '~') {
1883 if (!c->syscall_filter) {
1886 n = (syscall_max() + 31) >> 4;
1887 c->syscall_filter = new(uint32_t, n);
1888 if (!c->syscall_filter)
1891 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
1893 /* Add these by default */
1894 syscall_set(c->syscall_filter, __NR_execve);
1895 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
1896 #ifdef __NR_sigreturn
1897 syscall_set(c->syscall_filter, __NR_sigreturn);
1899 syscall_set(c->syscall_filter, __NR_exit_group);
1900 syscall_set(c->syscall_filter, __NR_exit);
1903 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1905 _cleanup_free_ char *t = NULL;
1911 id = syscall_from_name(t);
1913 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1914 "Failed to parse syscall, ignoring: %s", t);
1919 syscall_unset(c->syscall_filter, id);
1921 syscall_set(c->syscall_filter, id);
1924 c->no_new_privileges = true;
1929 int config_parse_unit_slice(
1931 const char *filename,
1933 const char *section,
1940 _cleanup_free_ char *k = NULL;
1941 Unit *u = userdata, *slice;
1949 r = unit_name_printf(u, rvalue, &k);
1951 log_syntax(unit, LOG_ERR, filename, line, -r,
1952 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
1959 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
1961 log_syntax(unit, LOG_ERR, filename, line, -r,
1962 "Failed to load slice unit %s. Ignoring.", k);
1966 if (slice->type != UNIT_SLICE) {
1967 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1968 "Slice unit %s is not a slice. Ignoring.", k);
1972 unit_ref_set(&u->slice, slice);
1976 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
1978 int config_parse_cpu_shares(
1980 const char *filename,
1982 const char *section,
1989 CGroupContext *c = data;
1997 if (isempty(rvalue)) {
1998 c->cpu_shares = 1024;
2002 r = safe_atolu(rvalue, &lu);
2003 if (r < 0 || lu <= 0) {
2004 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2005 "CPU shares '%s' invalid. Ignoring.", rvalue);
2013 int config_parse_memory_limit(
2015 const char *filename,
2017 const char *section,
2024 CGroupContext *c = data;
2028 if (isempty(rvalue)) {
2029 c->memory_limit = (uint64_t) -1;
2033 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2035 r = parse_bytes(rvalue, &bytes);
2037 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2038 "Memory limit '%s' invalid. Ignoring.", rvalue);
2042 c->memory_limit = (uint64_t) bytes;
2046 int config_parse_device_allow(
2048 const char *filename,
2050 const char *section,
2057 _cleanup_free_ char *path = NULL;
2058 CGroupContext *c = data;
2059 CGroupDeviceAllow *a;
2063 if (isempty(rvalue)) {
2064 while (c->device_allow)
2065 cgroup_context_free_device_allow(c, c->device_allow);
2070 n = strcspn(rvalue, WHITESPACE);
2071 path = strndup(rvalue, n);
2075 if (!path_startswith(path, "/dev")) {
2076 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2077 "Invalid device node path '%s'. Ignoring.", path);
2081 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2085 if (!in_charset(m, "rwm")) {
2086 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2087 "Invalid device rights '%s'. Ignoring.", m);
2091 a = new0(CGroupDeviceAllow, 1);
2097 a->r = !!strchr(m, 'r');
2098 a->w = !!strchr(m, 'w');
2099 a->m = !!strchr(m, 'm');
2101 LIST_PREPEND(device_allow, c->device_allow, a);
2105 int config_parse_blockio_weight(
2107 const char *filename,
2109 const char *section,
2116 CGroupContext *c = data;
2124 if (isempty(rvalue)) {
2125 c->blockio_weight = 1000;
2129 r = safe_atolu(rvalue, &lu);
2130 if (r < 0 || lu < 10 || lu > 1000) {
2131 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2132 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2136 c->blockio_weight = lu;
2141 int config_parse_blockio_device_weight(
2143 const char *filename,
2145 const char *section,
2152 _cleanup_free_ char *path = NULL;
2153 CGroupBlockIODeviceWeight *w;
2154 CGroupContext *c = data;
2164 if (isempty(rvalue)) {
2165 while (c->blockio_device_weights)
2166 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2171 n = strcspn(rvalue, WHITESPACE);
2172 weight = rvalue + n;
2174 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2175 "Expected block device and device weight. Ignoring.");
2179 path = strndup(rvalue, n);
2183 if (!path_startswith(path, "/dev")) {
2184 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2185 "Invalid device node path '%s'. Ignoring.", path);
2189 weight += strspn(weight, WHITESPACE);
2190 r = safe_atolu(weight, &lu);
2191 if (r < 0 || lu < 10 || lu > 1000) {
2192 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2193 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2198 w = new0(CGroupBlockIODeviceWeight, 1);
2207 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2211 int config_parse_blockio_bandwidth(
2213 const char *filename,
2215 const char *section,
2222 _cleanup_free_ char *path = NULL;
2223 CGroupBlockIODeviceBandwidth *b;
2224 CGroupContext *c = data;
2225 const char *bandwidth;
2235 read = streq("BlockIOReadBandwidth", lvalue);
2237 if (isempty(rvalue)) {
2238 CGroupBlockIODeviceBandwidth *next;
2240 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2241 if (b->read == read)
2242 cgroup_context_free_blockio_device_bandwidth(c, b);
2247 n = strcspn(rvalue, WHITESPACE);
2248 bandwidth = rvalue + n;
2249 bandwidth += strspn(bandwidth, WHITESPACE);
2252 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2253 "Expected space separated pair of device node and bandwidth. Ignoring.");
2257 path = strndup(rvalue, n);
2261 if (!path_startswith(path, "/dev")) {
2262 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2263 "Invalid device node path '%s'. Ignoring.", path);
2267 r = parse_bytes(bandwidth, &bytes);
2268 if (r < 0 || bytes <= 0) {
2269 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2270 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2274 b = new0(CGroupBlockIODeviceBandwidth, 1);
2280 b->bandwidth = (uint64_t) bytes;
2283 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2288 #define FOLLOW_MAX 8
2290 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2301 /* This will update the filename pointer if the loaded file is
2302 * reached by a symlink. The old string will be freed. */
2305 char *target, *name;
2307 if (c++ >= FOLLOW_MAX)
2310 path_kill_slashes(*filename);
2312 /* Add the file name we are currently looking at to
2313 * the names of this unit, but only if it is a valid
2315 name = path_get_file_name(*filename);
2317 if (unit_name_is_valid(name, true)) {
2319 id = set_get(names, name);
2325 r = set_consume(names, id);
2331 /* Try to open the file name, but don't if its a symlink */
2332 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2339 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2340 r = readlink_and_make_absolute(*filename, &target);
2348 f = fdopen(fd, "re");
2351 close_nointr_nofail(fd);
2360 static int merge_by_names(Unit **u, Set *names, const char *id) {
2368 /* Let's try to add in all symlink names we found */
2369 while ((k = set_steal_first(names))) {
2371 /* First try to merge in the other name into our
2373 r = unit_merge_by_name(*u, k);
2377 /* Hmm, we couldn't merge the other unit into
2378 * ours? Then let's try it the other way
2381 other = manager_get_unit((*u)->manager, k);
2385 r = unit_merge(other, *u);
2388 return merge_by_names(u, names, NULL);
2396 unit_choose_id(*u, id);
2404 static int load_from_path(Unit *u, const char *path) {
2406 _cleanup_set_free_free_ Set *symlink_names = NULL;
2407 _cleanup_fclose_ FILE *f = NULL;
2408 _cleanup_free_ char *filename = NULL;
2416 symlink_names = set_new(string_hash_func, string_compare_func);
2420 if (path_is_absolute(path)) {
2422 filename = strdup(path);
2426 r = open_follow(&filename, &f, symlink_names, &id);
2438 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2440 /* Instead of opening the path right away, we manually
2441 * follow all symlinks and add their name to our unit
2442 * name set while doing so */
2443 filename = path_make_absolute(path, *p);
2447 if (u->manager->unit_path_cache &&
2448 !set_get(u->manager->unit_path_cache, filename))
2451 r = open_follow(&filename, &f, symlink_names, &id);
2460 /* Empty the symlink names for the next run */
2461 set_clear_free(symlink_names);
2470 /* Hmm, no suitable file found? */
2474 r = merge_by_names(&merged, symlink_names, id);
2479 u->load_state = UNIT_MERGED;
2483 if (fstat(fileno(f), &st) < 0)
2486 if (null_or_empty(&st))
2487 u->load_state = UNIT_MASKED;
2489 u->load_state = UNIT_LOADED;
2491 /* Now, parse the file contents */
2492 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2493 config_item_perf_lookup,
2494 (void*) load_fragment_gperf_lookup, false, true, u);
2499 free(u->fragment_path);
2500 u->fragment_path = filename;
2503 u->fragment_mtime = timespec_load(&st.st_mtim);
2505 if (u->source_path) {
2506 if (stat(u->source_path, &st) >= 0)
2507 u->source_mtime = timespec_load(&st.st_mtim);
2509 u->source_mtime = 0;
2515 int unit_load_fragment(Unit *u) {
2521 assert(u->load_state == UNIT_STUB);
2524 /* First, try to find the unit under its id. We always look
2525 * for unit files in the default directories, to make it easy
2526 * to override things by placing things in /etc/systemd/system */
2527 r = load_from_path(u, u->id);
2531 /* Try to find an alias we can load this with */
2532 if (u->load_state == UNIT_STUB)
2533 SET_FOREACH(t, u->names, i) {
2538 r = load_from_path(u, t);
2542 if (u->load_state != UNIT_STUB)
2546 /* And now, try looking for it under the suggested (originally linked) path */
2547 if (u->load_state == UNIT_STUB && u->fragment_path) {
2549 r = load_from_path(u, u->fragment_path);
2553 if (u->load_state == UNIT_STUB) {
2554 /* Hmm, this didn't work? Then let's get rid
2555 * of the fragment path stored for us, so that
2556 * we don't point to an invalid location. */
2557 free(u->fragment_path);
2558 u->fragment_path = NULL;
2562 /* Look for a template */
2563 if (u->load_state == UNIT_STUB && u->instance) {
2566 k = unit_name_template(u->id);
2570 r = load_from_path(u, k);
2576 if (u->load_state == UNIT_STUB)
2577 SET_FOREACH(t, u->names, i) {
2582 k = unit_name_template(t);
2586 r = load_from_path(u, k);
2592 if (u->load_state != UNIT_STUB)
2600 void unit_dump_config_items(FILE *f) {
2601 static const struct {
2602 const ConfigParserCallback callback;
2605 { config_parse_int, "INTEGER" },
2606 { config_parse_unsigned, "UNSIGNED" },
2607 { config_parse_bytes_size, "SIZE" },
2608 { config_parse_bool, "BOOLEAN" },
2609 { config_parse_string, "STRING" },
2610 { config_parse_path, "PATH" },
2611 { config_parse_unit_path_printf, "PATH" },
2612 { config_parse_strv, "STRING [...]" },
2613 { config_parse_exec_nice, "NICE" },
2614 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2615 { config_parse_exec_io_class, "IOCLASS" },
2616 { config_parse_exec_io_priority, "IOPRIORITY" },
2617 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2618 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2619 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2620 { config_parse_mode, "MODE" },
2621 { config_parse_unit_env_file, "FILE" },
2622 { config_parse_output, "OUTPUT" },
2623 { config_parse_input, "INPUT" },
2624 { config_parse_facility, "FACILITY" },
2625 { config_parse_level, "LEVEL" },
2626 { config_parse_exec_capabilities, "CAPABILITIES" },
2627 { config_parse_exec_secure_bits, "SECUREBITS" },
2628 { config_parse_bounding_set, "BOUNDINGSET" },
2629 { config_parse_limit, "LIMIT" },
2630 { config_parse_unit_deps, "UNIT [...]" },
2631 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2632 { config_parse_service_type, "SERVICETYPE" },
2633 { config_parse_service_restart, "SERVICERESTART" },
2634 #ifdef HAVE_SYSV_COMPAT
2635 { config_parse_sysv_priority, "SYSVPRIORITY" },
2637 { config_parse_warn_compat, "NOTSUPPORTED" },
2639 { config_parse_kill_mode, "KILLMODE" },
2640 { config_parse_kill_signal, "SIGNAL" },
2641 { config_parse_socket_listen, "SOCKET [...]" },
2642 { config_parse_socket_bind, "SOCKETBIND" },
2643 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2644 { config_parse_sec, "SECONDS" },
2645 { config_parse_nsec, "NANOSECONDS" },
2646 { config_parse_path_strv, "PATH [...]" },
2647 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2648 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2649 { config_parse_unit_string_printf, "STRING" },
2650 { config_parse_trigger_unit, "UNIT" },
2651 { config_parse_timer, "TIMER" },
2652 { config_parse_path_spec, "PATH" },
2653 { config_parse_notify_access, "ACCESS" },
2654 { config_parse_ip_tos, "TOS" },
2655 { config_parse_unit_condition_path, "CONDITION" },
2656 { config_parse_unit_condition_string, "CONDITION" },
2657 { config_parse_unit_condition_null, "CONDITION" },
2658 { config_parse_unit_slice, "SLICE" },
2659 { config_parse_documentation, "URL" },
2660 { config_parse_service_timeout, "SECONDS" },
2661 { config_parse_start_limit_action, "ACTION" },
2662 { config_parse_set_status, "STATUS" },
2663 { config_parse_service_sockets, "SOCKETS" },
2664 { config_parse_environ, "ENVIRON" },
2665 { config_parse_syscall_filter, "SYSCALL" },
2666 { config_parse_cpu_shares, "SHARES" },
2667 { config_parse_memory_limit, "LIMIT" },
2668 { config_parse_device_allow, "DEVICE" },
2669 { config_parse_device_policy, "POLICY" },
2670 { config_parse_blockio_bandwidth, "BANDWIDTH" },
2671 { config_parse_blockio_weight, "WEIGHT" },
2672 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
2673 { config_parse_long, "LONG" },
2674 { config_parse_socket_service, "SERVICE" },
2677 const char *prev = NULL;
2682 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2683 const char *rvalue = "OTHER", *lvalue;
2687 const ConfigPerfItem *p;
2689 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2691 dot = strchr(i, '.');
2692 lvalue = dot ? dot + 1 : i;
2696 if (!prev || !strneq(prev, i, prefix_len+1)) {
2700 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2703 for (j = 0; j < ELEMENTSOF(table); j++)
2704 if (p->parse == table[j].callback) {
2705 rvalue = table[j].rvalue;
2709 fprintf(f, "%s=%s\n", lvalue, rvalue);