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"
49 #include "path-util.h"
50 #include "syscall-list.h"
54 #include "bus-error.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);
304 LIST_FIND_TAIL(port, s->ports, tail);
305 LIST_INSERT_AFTER(port, s->ports, tail, p);
307 LIST_PREPEND(port, s->ports, p);
312 int config_parse_socket_bind(const char *unit,
313 const char *filename,
323 SocketAddressBindIPv6Only b;
332 b = socket_address_bind_ipv6_only_from_string(rvalue);
336 r = parse_boolean(rvalue);
338 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
339 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
343 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
345 s->bind_ipv6_only = b;
350 int config_parse_exec_nice(const char *unit,
351 const char *filename,
360 ExecContext *c = data;
368 r = safe_atoi(rvalue, &priority);
370 log_syntax(unit, LOG_ERR, filename, line, -r,
371 "Failed to parse nice priority, ignoring: %s. ", rvalue);
375 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
376 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
377 "Nice priority out of range, ignoring: %s", rvalue);
387 int config_parse_exec_oom_score_adjust(const char* unit,
388 const char *filename,
397 ExecContext *c = data;
405 r = safe_atoi(rvalue, &oa);
407 log_syntax(unit, LOG_ERR, filename, line, -r,
408 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
412 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
413 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
414 "OOM score adjust value out of range, ignoring: %s", rvalue);
418 c->oom_score_adjust = oa;
419 c->oom_score_adjust_set = true;
424 int config_parse_exec(const char *unit,
425 const char *filename,
434 ExecCommand **e = data, *nce;
446 if (isempty(rvalue)) {
447 /* An empty assignment resets the list */
448 exec_command_free_list(*e);
453 /* We accept an absolute path as first argument, or
454 * alternatively an absolute prefixed with @ to allow
455 * overriding of argv[0]. */
461 bool honour_argv0 = false, ignore = false;
467 rvalue += strspn(rvalue, WHITESPACE);
472 for (i = 0; i < 2; i++) {
473 if (rvalue[0] == '-' && !ignore) {
478 if (rvalue[0] == '@' && !honour_argv0) {
484 if (*rvalue != '/') {
485 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
486 "Executable path is not absolute, ignoring: %s", rvalue);
491 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
492 if (strneq(w, ";", MAX(l, 1U)))
498 n = new(char*, k + !honour_argv0);
503 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
504 if (strneq(w, ";", MAX(l, 1U)))
506 else if (strneq(w, "\\;", MAX(l, 1U)))
509 if (honour_argv0 && w == rvalue) {
512 path = strndup(w, l);
518 if (!utf8_is_valid(path)) {
519 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
520 "Path is not UTF-8 clean, ignoring assignment: %s",
529 c = n[k++] = cunescape_length(w, l);
535 if (!utf8_is_valid(c)) {
536 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
537 "Path is not UTF-8 clean, ignoring assignment: %s",
548 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
549 "Invalid command line, ignoring: %s", rvalue);
562 assert(path_is_absolute(path));
564 nce = new0(ExecCommand, 1);
572 nce->ignore = ignore;
574 path_kill_slashes(nce->path);
576 exec_command_append_list(e, nce);
592 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
593 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
595 int config_parse_socket_bindtodevice(const char* unit,
596 const char *filename,
613 if (rvalue[0] && !streq(rvalue, "*")) {
620 free(s->bind_to_device);
621 s->bind_to_device = n;
626 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
627 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
629 int config_parse_exec_io_class(const char *unit,
630 const char *filename,
639 ExecContext *c = data;
647 x = ioprio_class_from_string(rvalue);
649 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
650 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
654 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
655 c->ioprio_set = true;
660 int config_parse_exec_io_priority(const char *unit,
661 const char *filename,
670 ExecContext *c = data;
678 r = safe_atoi(rvalue, &i);
679 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
680 log_syntax(unit, LOG_ERR, filename, line, -r,
681 "Failed to parse IO priority, ignoring: %s", rvalue);
685 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
686 c->ioprio_set = true;
691 int config_parse_exec_cpu_sched_policy(const char *unit,
692 const char *filename,
702 ExecContext *c = data;
710 x = sched_policy_from_string(rvalue);
712 log_syntax(unit, LOG_ERR, filename, line, -x,
713 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
717 c->cpu_sched_policy = x;
718 /* Moving to or from real-time policy? We need to adjust the priority */
719 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
720 c->cpu_sched_set = true;
725 int config_parse_exec_cpu_sched_prio(const char *unit,
726 const char *filename,
735 ExecContext *c = data;
743 r = safe_atoi(rvalue, &i);
745 log_syntax(unit, LOG_ERR, filename, line, -r,
746 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
750 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
751 min = sched_get_priority_min(c->cpu_sched_policy);
752 max = sched_get_priority_max(c->cpu_sched_policy);
754 if (i < min || i > max) {
755 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
756 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
760 c->cpu_sched_priority = i;
761 c->cpu_sched_set = true;
766 int config_parse_exec_cpu_affinity(const char *unit,
767 const char *filename,
776 ExecContext *c = data;
786 if (isempty(rvalue)) {
787 /* An empty assignment resets the CPU list */
794 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
795 _cleanup_free_ char *t = NULL;
803 r = safe_atou(t, &cpu);
806 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
811 if (r < 0 || cpu >= c->cpuset_ncpus) {
812 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
813 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
817 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
823 int config_parse_exec_capabilities(const char *unit,
824 const char *filename,
833 ExecContext *c = data;
841 cap = cap_from_text(rvalue);
843 log_syntax(unit, LOG_ERR, filename, line, errno,
844 "Failed to parse capabilities, ignoring: %s", rvalue);
849 cap_free(c->capabilities);
850 c->capabilities = cap;
855 int config_parse_exec_secure_bits(const char *unit,
856 const char *filename,
865 ExecContext *c = data;
875 if (isempty(rvalue)) {
876 /* An empty assignment resets the field */
881 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
882 if (first_word(w, "keep-caps"))
883 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
884 else if (first_word(w, "keep-caps-locked"))
885 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
886 else if (first_word(w, "no-setuid-fixup"))
887 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
888 else if (first_word(w, "no-setuid-fixup-locked"))
889 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
890 else if (first_word(w, "noroot"))
891 c->secure_bits |= 1<<SECURE_NOROOT;
892 else if (first_word(w, "noroot-locked"))
893 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
895 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
896 "Failed to parse secure bits, ignoring: %s", rvalue);
904 int config_parse_bounding_set(const char *unit,
905 const char *filename,
914 uint64_t *capability_bounding_set_drop = data;
926 if (rvalue[0] == '~') {
931 /* Note that we store this inverted internally, since the
932 * kernel wants it like this. But we actually expose it
933 * non-inverted everywhere to have a fully normalized
936 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
937 _cleanup_free_ char *t = NULL;
945 r = cap_from_name(t, &cap);
947 log_syntax(unit, LOG_ERR, filename, line, errno,
948 "Failed to parse capability in bounding set, ignoring: %s", t);
952 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
956 *capability_bounding_set_drop |= sum;
958 *capability_bounding_set_drop |= ~sum;
963 int config_parse_limit(const char *unit,
964 const char *filename,
973 struct rlimit **rl = data;
974 unsigned long long u;
983 if (streq(rvalue, "infinity"))
984 u = (unsigned long long) RLIM_INFINITY;
988 r = safe_atollu(rvalue, &u);
990 log_syntax(unit, LOG_ERR, filename, line, -r,
991 "Failed to parse resource value, ignoring: %s", rvalue);
997 *rl = new(struct rlimit, 1);
1002 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1006 #ifdef HAVE_SYSV_COMPAT
1007 int config_parse_sysv_priority(const char *unit,
1008 const char *filename,
1010 const char *section,
1017 int *priority = data;
1025 r = safe_atoi(rvalue, &i);
1026 if (r < 0 || i < 0) {
1027 log_syntax(unit, LOG_ERR, filename, line, -r,
1028 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1032 *priority = (int) i;
1037 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1039 int config_parse_kill_signal(const char *unit,
1040 const char *filename,
1042 const char *section,
1057 r = signal_from_string_try_harder(rvalue);
1059 log_syntax(unit, LOG_ERR, filename, line, -r,
1060 "Failed to parse kill signal, ignoring: %s", rvalue);
1068 int config_parse_exec_mount_flags(const char *unit,
1069 const char *filename,
1071 const char *section,
1078 ExecContext *c = data;
1082 unsigned long flags = 0;
1089 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1090 _cleanup_free_ char *t;
1096 if (streq(t, "shared"))
1098 else if (streq(t, "slave"))
1100 else if (streq(w, "private"))
1101 flags |= MS_PRIVATE;
1103 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1104 "Failed to parse mount flag %s, ignoring: %s",
1110 c->mount_flags = flags;
1114 int config_parse_timer(const char *unit,
1115 const char *filename,
1117 const char *section,
1128 CalendarSpec *c = NULL;
1136 if (isempty(rvalue)) {
1137 /* Empty assignment resets list */
1138 timer_free_values(t);
1142 b = timer_base_from_string(lvalue);
1144 log_syntax(unit, LOG_ERR, filename, line, -b,
1145 "Failed to parse timer base, ignoring: %s", lvalue);
1149 if (b == TIMER_CALENDAR) {
1150 if (calendar_spec_from_string(rvalue, &c) < 0) {
1151 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1152 "Failed to parse calendar specification, ignoring: %s",
1157 id = CLOCK_REALTIME;
1159 if (parse_sec(rvalue, &u) < 0) {
1160 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1161 "Failed to parse timer value, ignoring: %s",
1166 id = CLOCK_MONOTONIC;
1169 v = new0(TimerValue, 1);
1176 v->calendar_spec = c;
1178 LIST_PREPEND(value, t->values, v);
1183 int config_parse_trigger_unit(
1185 const char *filename,
1187 const char *section,
1194 _cleanup_free_ char *p = NULL;
1204 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1205 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1206 "Multiple units to trigger specified, ignoring: %s", rvalue);
1210 r = unit_name_printf(u, rvalue, &p);
1212 log_syntax(unit, LOG_ERR, filename, line, -r,
1213 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1215 type = unit_name_to_type(p ?: rvalue);
1217 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1218 "Unit type not valid, ignoring: %s", rvalue);
1222 if (type == u->type) {
1223 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1224 "Trigger cannot be of same type, ignoring: %s", rvalue);
1228 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1230 log_syntax(unit, LOG_ERR, filename, line, -r,
1231 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1238 int config_parse_path_spec(const char *unit,
1239 const char *filename,
1241 const char *section,
1251 _cleanup_free_ char *k = NULL;
1259 if (isempty(rvalue)) {
1260 /* Empty assignment clears list */
1265 b = path_type_from_string(lvalue);
1267 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1268 "Failed to parse path type, ignoring: %s", lvalue);
1272 r = unit_full_printf(UNIT(p), rvalue, &k);
1278 log_syntax(unit, LOG_ERR, filename, line, -r,
1279 "Failed to resolve unit specifiers on %s. Ignoring.",
1283 if (!path_is_absolute(k)) {
1284 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1285 "Path is not absolute, ignoring: %s", k);
1289 s = new0(PathSpec, 1);
1294 s->path = path_kill_slashes(k);
1299 LIST_PREPEND(spec, p->specs, s);
1304 int config_parse_socket_service(const char *unit,
1305 const char *filename,
1307 const char *section,
1314 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1318 _cleanup_free_ char *p = NULL;
1325 r = unit_name_printf(UNIT(s), rvalue, &p);
1327 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1329 if (!endswith(p ?: rvalue, ".service")) {
1330 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1334 r = manager_load_unit(UNIT(s)->manager, p ?: rvalue, NULL, &error, &x);
1336 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1340 unit_ref_set(&s->service, x);
1345 int config_parse_service_sockets(const char *unit,
1346 const char *filename,
1348 const char *section,
1365 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1366 _cleanup_free_ char *t = NULL, *k = NULL;
1372 r = unit_name_printf(UNIT(s), t, &k);
1374 log_syntax(unit, LOG_ERR, filename, line, -r,
1375 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1377 if (!endswith(k ?: t, ".socket")) {
1378 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1379 "Unit must be of type socket, ignoring: %s", k ?: t);
1383 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1385 log_syntax(unit, LOG_ERR, filename, line, -r,
1386 "Failed to add dependency on %s, ignoring: %s",
1387 k ?: t, strerror(-r));
1389 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1397 int config_parse_service_timeout(const char *unit,
1398 const char *filename,
1400 const char *section,
1407 Service *s = userdata;
1415 r = config_parse_sec(unit, filename, line, section, lvalue, ltype,
1416 rvalue, data, userdata);
1420 if (streq(lvalue, "TimeoutSec")) {
1421 s->start_timeout_defined = true;
1422 s->timeout_stop_usec = s->timeout_start_usec;
1423 } else if (streq(lvalue, "TimeoutStartSec"))
1424 s->start_timeout_defined = true;
1429 int config_parse_unit_env_file(const char *unit,
1430 const char *filename,
1432 const char *section,
1441 _cleanup_free_ char *n = NULL;
1450 if (isempty(rvalue)) {
1451 /* Empty assignment frees the list */
1457 r = unit_full_printf(u, rvalue, &n);
1459 log_syntax(unit, LOG_ERR, filename, line, r,
1460 "Failed to resolve specifiers, ignoring: %s", rvalue);
1463 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1464 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1465 "Path '%s' is not absolute, ignoring.", s);
1469 r = strv_extend(env, s);
1476 int config_parse_environ(const char *unit,
1477 const char *filename,
1479 const char *section,
1487 char*** env = data, *w, *state;
1489 _cleanup_free_ char *k = NULL;
1497 if (isempty(rvalue)) {
1498 /* Empty assignment resets the list */
1505 r = unit_full_printf(u, rvalue, &k);
1507 log_syntax(unit, LOG_ERR, filename, line, -r,
1508 "Failed to resolve specifiers, ignoring: %s", rvalue);
1516 FOREACH_WORD_QUOTED(w, l, k, state) {
1517 _cleanup_free_ char *n;
1520 n = cunescape_length(w, l);
1524 if (!env_assignment_is_valid(n)) {
1525 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1526 "Invalid environment assignment, ignoring: %s", rvalue);
1530 x = strv_env_set(*env, n);
1541 int config_parse_ip_tos(const char *unit,
1542 const char *filename,
1544 const char *section,
1551 int *ip_tos = data, x;
1558 x = ip_tos_from_string(rvalue);
1560 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1561 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1569 int config_parse_unit_condition_path(const char *unit,
1570 const char *filename,
1572 const char *section,
1579 ConditionType cond = ltype;
1581 bool trigger, negate;
1583 _cleanup_free_ char *p = NULL;
1591 if (isempty(rvalue)) {
1592 /* Empty assignment resets the list */
1593 condition_free_list(u->conditions);
1594 u->conditions = NULL;
1598 trigger = rvalue[0] == '|';
1602 negate = rvalue[0] == '!';
1606 r = unit_full_printf(u, rvalue, &p);
1608 log_syntax(unit, LOG_ERR, filename, line, -r,
1609 "Failed to resolve specifiers, ignoring: %s", rvalue);
1616 if (!path_is_absolute(p)) {
1617 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1618 "Path in condition not absolute, ignoring: %s", p);
1622 c = condition_new(cond, p, trigger, negate);
1626 LIST_PREPEND(conditions, u->conditions, c);
1630 int config_parse_unit_condition_string(const char *unit,
1631 const char *filename,
1633 const char *section,
1640 ConditionType cond = ltype;
1642 bool trigger, negate;
1644 _cleanup_free_ char *s = NULL;
1652 if (isempty(rvalue)) {
1653 /* Empty assignment resets the list */
1654 condition_free_list(u->conditions);
1655 u->conditions = NULL;
1659 trigger = rvalue[0] == '|';
1663 negate = rvalue[0] == '!';
1667 r = unit_full_printf(u, rvalue, &s);
1669 log_syntax(unit, LOG_ERR, filename, line, -r,
1670 "Failed to resolve specifiers, ignoring: %s", rvalue);
1677 c = condition_new(cond, s, trigger, negate);
1681 LIST_PREPEND(conditions, u->conditions, c);
1685 int config_parse_unit_condition_null(const char *unit,
1686 const char *filename,
1688 const char *section,
1697 bool trigger, negate;
1705 if (isempty(rvalue)) {
1706 /* Empty assignment resets the list */
1707 condition_free_list(u->conditions);
1708 u->conditions = NULL;
1712 trigger = rvalue[0] == '|';
1716 negate = rvalue[0] == '!';
1720 b = parse_boolean(rvalue);
1722 log_syntax(unit, LOG_ERR, filename, line, -b,
1723 "Failed to parse boolean value in condition, ignoring: %s",
1731 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1735 LIST_PREPEND(conditions, u->conditions, c);
1739 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1740 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1742 int config_parse_unit_requires_mounts_for(
1744 const char *filename,
1746 const char *section,
1763 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1765 _cleanup_free_ char *n;
1771 if (!utf8_is_valid(n)) {
1772 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1773 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
1777 r = unit_require_mounts_for(u, n);
1779 log_syntax(unit, LOG_ERR, filename, line, r,
1780 "Failed to add required mount for, ignoring: %s", rvalue);
1788 int config_parse_documentation(const char *unit,
1789 const char *filename,
1791 const char *section,
1807 if (isempty(rvalue)) {
1808 /* Empty assignment resets the list */
1809 strv_free(u->documentation);
1810 u->documentation = NULL;
1814 r = config_parse_unit_strv_printf(unit, filename, line, section, lvalue, ltype,
1815 rvalue, data, userdata);
1819 for (a = b = u->documentation; a && *a; a++) {
1821 if (is_valid_documentation_url(*a))
1824 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1825 "Invalid URL, ignoring: %s", *a);
1835 static void syscall_set(uint32_t *p, int nr) {
1836 nr = SYSCALL_TO_INDEX(nr);
1837 p[nr >> 4] |= 1 << (nr & 31);
1840 static void syscall_unset(uint32_t *p, int nr) {
1841 nr = SYSCALL_TO_INDEX(nr);
1842 p[nr >> 4] &= ~(1 << (nr & 31));
1845 int config_parse_syscall_filter(const char *unit,
1846 const char *filename,
1848 const char *section,
1855 ExecContext *c = data;
1857 bool invert = false;
1867 if (isempty(rvalue)) {
1868 /* Empty assignment resets the list */
1869 free(c->syscall_filter);
1870 c->syscall_filter = NULL;
1874 if (rvalue[0] == '~') {
1879 if (!c->syscall_filter) {
1882 n = (syscall_max() + 31) >> 4;
1883 c->syscall_filter = new(uint32_t, n);
1884 if (!c->syscall_filter)
1887 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
1889 /* Add these by default */
1890 syscall_set(c->syscall_filter, __NR_execve);
1891 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
1892 #ifdef __NR_sigreturn
1893 syscall_set(c->syscall_filter, __NR_sigreturn);
1895 syscall_set(c->syscall_filter, __NR_exit_group);
1896 syscall_set(c->syscall_filter, __NR_exit);
1899 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1901 _cleanup_free_ char *t = NULL;
1907 id = syscall_from_name(t);
1909 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1910 "Failed to parse syscall, ignoring: %s", t);
1915 syscall_unset(c->syscall_filter, id);
1917 syscall_set(c->syscall_filter, id);
1920 c->no_new_privileges = true;
1925 int config_parse_unit_slice(
1927 const char *filename,
1929 const char *section,
1936 _cleanup_free_ char *k = NULL;
1937 Unit *u = userdata, *slice;
1945 r = unit_name_printf(u, rvalue, &k);
1947 log_syntax(unit, LOG_ERR, filename, line, -r,
1948 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
1955 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
1957 log_syntax(unit, LOG_ERR, filename, line, -r,
1958 "Failed to load slice unit %s. Ignoring.", k);
1962 if (slice->type != UNIT_SLICE) {
1963 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1964 "Slice unit %s is not a slice. Ignoring.", k);
1968 unit_ref_set(&u->slice, slice);
1972 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
1974 int config_parse_cpu_shares(
1976 const char *filename,
1978 const char *section,
1985 CGroupContext *c = data;
1993 if (isempty(rvalue)) {
1994 c->cpu_shares = 1024;
1998 r = safe_atolu(rvalue, &lu);
1999 if (r < 0 || lu <= 0) {
2000 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2001 "CPU shares '%s' invalid. Ignoring.", rvalue);
2009 int config_parse_memory_limit(
2011 const char *filename,
2013 const char *section,
2020 CGroupContext *c = data;
2024 if (isempty(rvalue)) {
2025 c->memory_limit = (uint64_t) -1;
2029 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2031 r = parse_bytes(rvalue, &bytes);
2033 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2034 "Memory limit '%s' invalid. Ignoring.", rvalue);
2038 c->memory_limit = (uint64_t) bytes;
2042 int config_parse_device_allow(
2044 const char *filename,
2046 const char *section,
2053 _cleanup_free_ char *path = NULL;
2054 CGroupContext *c = data;
2055 CGroupDeviceAllow *a;
2059 if (isempty(rvalue)) {
2060 while (c->device_allow)
2061 cgroup_context_free_device_allow(c, c->device_allow);
2066 n = strcspn(rvalue, WHITESPACE);
2067 path = strndup(rvalue, n);
2071 if (!path_startswith(path, "/dev")) {
2072 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2073 "Invalid device node path '%s'. Ignoring.", path);
2077 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2081 if (!in_charset(m, "rwm")) {
2082 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2083 "Invalid device rights '%s'. Ignoring.", m);
2087 a = new0(CGroupDeviceAllow, 1);
2093 a->r = !!strchr(m, 'r');
2094 a->w = !!strchr(m, 'w');
2095 a->m = !!strchr(m, 'm');
2097 LIST_PREPEND(device_allow, c->device_allow, a);
2101 int config_parse_blockio_weight(
2103 const char *filename,
2105 const char *section,
2112 CGroupContext *c = data;
2120 if (isempty(rvalue)) {
2121 c->blockio_weight = 1000;
2125 r = safe_atolu(rvalue, &lu);
2126 if (r < 0 || lu < 10 || lu > 1000) {
2127 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2128 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2132 c->blockio_weight = lu;
2137 int config_parse_blockio_device_weight(
2139 const char *filename,
2141 const char *section,
2148 _cleanup_free_ char *path = NULL;
2149 CGroupBlockIODeviceWeight *w;
2150 CGroupContext *c = data;
2160 if (isempty(rvalue)) {
2161 while (c->blockio_device_weights)
2162 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2167 n = strcspn(rvalue, WHITESPACE);
2168 weight = rvalue + n;
2170 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2171 "Expected block device and device weight. Ignoring.");
2175 path = strndup(rvalue, n);
2179 if (!path_startswith(path, "/dev")) {
2180 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2181 "Invalid device node path '%s'. Ignoring.", path);
2185 weight += strspn(weight, WHITESPACE);
2186 r = safe_atolu(weight, &lu);
2187 if (r < 0 || lu < 10 || lu > 1000) {
2188 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2189 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2194 w = new0(CGroupBlockIODeviceWeight, 1);
2203 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2207 int config_parse_blockio_bandwidth(
2209 const char *filename,
2211 const char *section,
2218 _cleanup_free_ char *path = NULL;
2219 CGroupBlockIODeviceBandwidth *b;
2220 CGroupContext *c = data;
2221 const char *bandwidth;
2231 read = streq("BlockIOReadBandwidth", lvalue);
2233 if (isempty(rvalue)) {
2234 CGroupBlockIODeviceBandwidth *next;
2236 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2237 if (b->read == read)
2238 cgroup_context_free_blockio_device_bandwidth(c, b);
2243 n = strcspn(rvalue, WHITESPACE);
2244 bandwidth = rvalue + n;
2245 bandwidth += strspn(bandwidth, WHITESPACE);
2248 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2249 "Expected space separated pair of device node and bandwidth. Ignoring.");
2253 path = strndup(rvalue, n);
2257 if (!path_startswith(path, "/dev")) {
2258 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2259 "Invalid device node path '%s'. Ignoring.", path);
2263 r = parse_bytes(bandwidth, &bytes);
2264 if (r < 0 || bytes <= 0) {
2265 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2266 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2270 b = new0(CGroupBlockIODeviceBandwidth, 1);
2276 b->bandwidth = (uint64_t) bytes;
2279 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2284 #define FOLLOW_MAX 8
2286 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2297 /* This will update the filename pointer if the loaded file is
2298 * reached by a symlink. The old string will be freed. */
2301 char *target, *name;
2303 if (c++ >= FOLLOW_MAX)
2306 path_kill_slashes(*filename);
2308 /* Add the file name we are currently looking at to
2309 * the names of this unit, but only if it is a valid
2311 name = path_get_file_name(*filename);
2313 if (unit_name_is_valid(name, true)) {
2315 id = set_get(names, name);
2321 r = set_consume(names, id);
2327 /* Try to open the file name, but don't if its a symlink */
2328 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2335 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2336 r = readlink_and_make_absolute(*filename, &target);
2344 f = fdopen(fd, "re");
2347 close_nointr_nofail(fd);
2356 static int merge_by_names(Unit **u, Set *names, const char *id) {
2364 /* Let's try to add in all symlink names we found */
2365 while ((k = set_steal_first(names))) {
2367 /* First try to merge in the other name into our
2369 r = unit_merge_by_name(*u, k);
2373 /* Hmm, we couldn't merge the other unit into
2374 * ours? Then let's try it the other way
2377 other = manager_get_unit((*u)->manager, k);
2381 r = unit_merge(other, *u);
2384 return merge_by_names(u, names, NULL);
2392 unit_choose_id(*u, id);
2400 static int load_from_path(Unit *u, const char *path) {
2402 _cleanup_set_free_free_ Set *symlink_names = NULL;
2403 _cleanup_fclose_ FILE *f = NULL;
2404 _cleanup_free_ char *filename = NULL;
2412 symlink_names = set_new(string_hash_func, string_compare_func);
2416 if (path_is_absolute(path)) {
2418 filename = strdup(path);
2422 r = open_follow(&filename, &f, symlink_names, &id);
2434 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2436 /* Instead of opening the path right away, we manually
2437 * follow all symlinks and add their name to our unit
2438 * name set while doing so */
2439 filename = path_make_absolute(path, *p);
2443 if (u->manager->unit_path_cache &&
2444 !set_get(u->manager->unit_path_cache, filename))
2447 r = open_follow(&filename, &f, symlink_names, &id);
2456 /* Empty the symlink names for the next run */
2457 set_clear_free(symlink_names);
2466 /* Hmm, no suitable file found? */
2470 r = merge_by_names(&merged, symlink_names, id);
2475 u->load_state = UNIT_MERGED;
2479 if (fstat(fileno(f), &st) < 0)
2482 if (null_or_empty(&st))
2483 u->load_state = UNIT_MASKED;
2485 u->load_state = UNIT_LOADED;
2487 /* Now, parse the file contents */
2488 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2489 config_item_perf_lookup,
2490 (void*) load_fragment_gperf_lookup, false, true, u);
2495 free(u->fragment_path);
2496 u->fragment_path = filename;
2499 u->fragment_mtime = timespec_load(&st.st_mtim);
2501 if (u->source_path) {
2502 if (stat(u->source_path, &st) >= 0)
2503 u->source_mtime = timespec_load(&st.st_mtim);
2505 u->source_mtime = 0;
2511 int unit_load_fragment(Unit *u) {
2517 assert(u->load_state == UNIT_STUB);
2520 /* First, try to find the unit under its id. We always look
2521 * for unit files in the default directories, to make it easy
2522 * to override things by placing things in /etc/systemd/system */
2523 r = load_from_path(u, u->id);
2527 /* Try to find an alias we can load this with */
2528 if (u->load_state == UNIT_STUB)
2529 SET_FOREACH(t, u->names, i) {
2534 r = load_from_path(u, t);
2538 if (u->load_state != UNIT_STUB)
2542 /* And now, try looking for it under the suggested (originally linked) path */
2543 if (u->load_state == UNIT_STUB && u->fragment_path) {
2545 r = load_from_path(u, u->fragment_path);
2549 if (u->load_state == UNIT_STUB) {
2550 /* Hmm, this didn't work? Then let's get rid
2551 * of the fragment path stored for us, so that
2552 * we don't point to an invalid location. */
2553 free(u->fragment_path);
2554 u->fragment_path = NULL;
2558 /* Look for a template */
2559 if (u->load_state == UNIT_STUB && u->instance) {
2562 k = unit_name_template(u->id);
2566 r = load_from_path(u, k);
2572 if (u->load_state == UNIT_STUB)
2573 SET_FOREACH(t, u->names, i) {
2578 k = unit_name_template(t);
2582 r = load_from_path(u, k);
2588 if (u->load_state != UNIT_STUB)
2596 void unit_dump_config_items(FILE *f) {
2597 static const struct {
2598 const ConfigParserCallback callback;
2601 { config_parse_int, "INTEGER" },
2602 { config_parse_unsigned, "UNSIGNED" },
2603 { config_parse_bytes_size, "SIZE" },
2604 { config_parse_bool, "BOOLEAN" },
2605 { config_parse_string, "STRING" },
2606 { config_parse_path, "PATH" },
2607 { config_parse_unit_path_printf, "PATH" },
2608 { config_parse_strv, "STRING [...]" },
2609 { config_parse_exec_nice, "NICE" },
2610 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2611 { config_parse_exec_io_class, "IOCLASS" },
2612 { config_parse_exec_io_priority, "IOPRIORITY" },
2613 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2614 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2615 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2616 { config_parse_mode, "MODE" },
2617 { config_parse_unit_env_file, "FILE" },
2618 { config_parse_output, "OUTPUT" },
2619 { config_parse_input, "INPUT" },
2620 { config_parse_facility, "FACILITY" },
2621 { config_parse_level, "LEVEL" },
2622 { config_parse_exec_capabilities, "CAPABILITIES" },
2623 { config_parse_exec_secure_bits, "SECUREBITS" },
2624 { config_parse_bounding_set, "BOUNDINGSET" },
2625 { config_parse_limit, "LIMIT" },
2626 { config_parse_unit_deps, "UNIT [...]" },
2627 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2628 { config_parse_service_type, "SERVICETYPE" },
2629 { config_parse_service_restart, "SERVICERESTART" },
2630 #ifdef HAVE_SYSV_COMPAT
2631 { config_parse_sysv_priority, "SYSVPRIORITY" },
2633 { config_parse_warn_compat, "NOTSUPPORTED" },
2635 { config_parse_kill_mode, "KILLMODE" },
2636 { config_parse_kill_signal, "SIGNAL" },
2637 { config_parse_socket_listen, "SOCKET [...]" },
2638 { config_parse_socket_bind, "SOCKETBIND" },
2639 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2640 { config_parse_sec, "SECONDS" },
2641 { config_parse_nsec, "NANOSECONDS" },
2642 { config_parse_path_strv, "PATH [...]" },
2643 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2644 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2645 { config_parse_unit_string_printf, "STRING" },
2646 { config_parse_trigger_unit, "UNIT" },
2647 { config_parse_timer, "TIMER" },
2648 { config_parse_path_spec, "PATH" },
2649 { config_parse_notify_access, "ACCESS" },
2650 { config_parse_ip_tos, "TOS" },
2651 { config_parse_unit_condition_path, "CONDITION" },
2652 { config_parse_unit_condition_string, "CONDITION" },
2653 { config_parse_unit_condition_null, "CONDITION" },
2654 { config_parse_unit_slice, "SLICE" },
2655 { config_parse_documentation, "URL" },
2656 { config_parse_service_timeout, "SECONDS" },
2657 { config_parse_start_limit_action, "ACTION" },
2658 { config_parse_set_status, "STATUS" },
2659 { config_parse_service_sockets, "SOCKETS" },
2660 { config_parse_environ, "ENVIRON" },
2661 { config_parse_syscall_filter, "SYSCALL" },
2662 { config_parse_cpu_shares, "SHARES" },
2663 { config_parse_memory_limit, "LIMIT" },
2664 { config_parse_device_allow, "DEVICE" },
2665 { config_parse_device_policy, "POLICY" },
2666 { config_parse_blockio_bandwidth, "BANDWIDTH" },
2667 { config_parse_blockio_weight, "WEIGHT" },
2668 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
2669 { config_parse_long, "LONG" },
2670 { config_parse_socket_service, "SERVICE" },
2673 const char *prev = NULL;
2678 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2679 const char *rvalue = "OTHER", *lvalue;
2683 const ConfigPerfItem *p;
2685 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2687 dot = strchr(i, '.');
2688 lvalue = dot ? dot + 1 : i;
2692 if (!prev || !strneq(prev, i, prefix_len+1)) {
2696 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2699 for (j = 0; j < ELEMENTSOF(table); j++)
2700 if (p->parse == table[j].callback) {
2701 rvalue = table[j].rvalue;
2705 fprintf(f, "%s=%s\n", lvalue, rvalue);