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);
303 LIST_FIND_TAIL(port, s->ports, tail);
304 LIST_INSERT_AFTER(port, s->ports, tail, p);
306 LIST_PREPEND(port, s->ports, p);
311 int config_parse_socket_bind(const char *unit,
312 const char *filename,
322 SocketAddressBindIPv6Only b;
331 b = socket_address_bind_ipv6_only_from_string(rvalue);
335 r = parse_boolean(rvalue);
337 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
338 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
342 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
344 s->bind_ipv6_only = b;
349 int config_parse_exec_nice(const char *unit,
350 const char *filename,
359 ExecContext *c = data;
367 r = safe_atoi(rvalue, &priority);
369 log_syntax(unit, LOG_ERR, filename, line, -r,
370 "Failed to parse nice priority, ignoring: %s. ", rvalue);
374 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
375 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
376 "Nice priority out of range, ignoring: %s", rvalue);
386 int config_parse_exec_oom_score_adjust(const char* unit,
387 const char *filename,
396 ExecContext *c = data;
404 r = safe_atoi(rvalue, &oa);
406 log_syntax(unit, LOG_ERR, filename, line, -r,
407 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
411 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
412 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
413 "OOM score adjust value out of range, ignoring: %s", rvalue);
417 c->oom_score_adjust = oa;
418 c->oom_score_adjust_set = true;
423 int config_parse_exec(const char *unit,
424 const char *filename,
433 ExecCommand **e = data, *nce;
445 if (isempty(rvalue)) {
446 /* An empty assignment resets the list */
447 exec_command_free_list(*e);
452 /* We accept an absolute path as first argument, or
453 * alternatively an absolute prefixed with @ to allow
454 * overriding of argv[0]. */
460 bool honour_argv0 = false, ignore = false;
466 rvalue += strspn(rvalue, WHITESPACE);
471 for (i = 0; i < 2; i++) {
472 if (rvalue[0] == '-' && !ignore) {
477 if (rvalue[0] == '@' && !honour_argv0) {
483 if (*rvalue != '/') {
484 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
485 "Executable path is not absolute, ignoring: %s", rvalue);
490 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
491 if (strneq(w, ";", MAX(l, 1U)))
497 n = new(char*, k + !honour_argv0);
502 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
503 if (strneq(w, ";", MAX(l, 1U)))
505 else if (strneq(w, "\\;", MAX(l, 1U)))
508 if (honour_argv0 && w == rvalue) {
511 path = strndup(w, l);
517 if (!utf8_is_valid(path)) {
518 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
519 "Path is not UTF-8 clean, ignoring assignment: %s",
528 c = n[k++] = cunescape_length(w, l);
534 if (!utf8_is_valid(c)) {
535 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
536 "Path is not UTF-8 clean, ignoring assignment: %s",
547 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
548 "Invalid command line, ignoring: %s", rvalue);
561 assert(path_is_absolute(path));
563 nce = new0(ExecCommand, 1);
571 nce->ignore = ignore;
573 path_kill_slashes(nce->path);
575 exec_command_append_list(e, nce);
591 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
592 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
594 int config_parse_socket_bindtodevice(const char* unit,
595 const char *filename,
612 if (rvalue[0] && !streq(rvalue, "*")) {
619 free(s->bind_to_device);
620 s->bind_to_device = n;
625 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
626 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
628 int config_parse_exec_io_class(const char *unit,
629 const char *filename,
638 ExecContext *c = data;
646 x = ioprio_class_from_string(rvalue);
648 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
649 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
653 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
654 c->ioprio_set = true;
659 int config_parse_exec_io_priority(const char *unit,
660 const char *filename,
669 ExecContext *c = data;
677 r = safe_atoi(rvalue, &i);
678 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
679 log_syntax(unit, LOG_ERR, filename, line, -r,
680 "Failed to parse IO priority, ignoring: %s", rvalue);
684 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
685 c->ioprio_set = true;
690 int config_parse_exec_cpu_sched_policy(const char *unit,
691 const char *filename,
701 ExecContext *c = data;
709 x = sched_policy_from_string(rvalue);
711 log_syntax(unit, LOG_ERR, filename, line, -x,
712 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
716 c->cpu_sched_policy = x;
717 /* Moving to or from real-time policy? We need to adjust the priority */
718 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
719 c->cpu_sched_set = true;
724 int config_parse_exec_cpu_sched_prio(const char *unit,
725 const char *filename,
734 ExecContext *c = data;
742 r = safe_atoi(rvalue, &i);
744 log_syntax(unit, LOG_ERR, filename, line, -r,
745 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
749 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
750 min = sched_get_priority_min(c->cpu_sched_policy);
751 max = sched_get_priority_max(c->cpu_sched_policy);
753 if (i < min || i > max) {
754 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
755 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
759 c->cpu_sched_priority = i;
760 c->cpu_sched_set = true;
765 int config_parse_exec_cpu_affinity(const char *unit,
766 const char *filename,
775 ExecContext *c = data;
785 if (isempty(rvalue)) {
786 /* An empty assignment resets the CPU list */
793 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
794 _cleanup_free_ char *t = NULL;
802 r = safe_atou(t, &cpu);
805 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
810 if (r < 0 || cpu >= c->cpuset_ncpus) {
811 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
812 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
816 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
822 int config_parse_exec_capabilities(const char *unit,
823 const char *filename,
832 ExecContext *c = data;
840 cap = cap_from_text(rvalue);
842 log_syntax(unit, LOG_ERR, filename, line, errno,
843 "Failed to parse capabilities, ignoring: %s", rvalue);
848 cap_free(c->capabilities);
849 c->capabilities = cap;
854 int config_parse_exec_secure_bits(const char *unit,
855 const char *filename,
864 ExecContext *c = data;
874 if (isempty(rvalue)) {
875 /* An empty assignment resets the field */
880 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
881 if (first_word(w, "keep-caps"))
882 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
883 else if (first_word(w, "keep-caps-locked"))
884 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
885 else if (first_word(w, "no-setuid-fixup"))
886 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
887 else if (first_word(w, "no-setuid-fixup-locked"))
888 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
889 else if (first_word(w, "noroot"))
890 c->secure_bits |= 1<<SECURE_NOROOT;
891 else if (first_word(w, "noroot-locked"))
892 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
894 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
895 "Failed to parse secure bits, ignoring: %s", rvalue);
903 int config_parse_bounding_set(const char *unit,
904 const char *filename,
913 uint64_t *capability_bounding_set_drop = data;
925 if (rvalue[0] == '~') {
930 /* Note that we store this inverted internally, since the
931 * kernel wants it like this. But we actually expose it
932 * non-inverted everywhere to have a fully normalized
935 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
936 _cleanup_free_ char *t = NULL;
944 r = cap_from_name(t, &cap);
946 log_syntax(unit, LOG_ERR, filename, line, errno,
947 "Failed to parse capability in bounding set, ignoring: %s", t);
951 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
955 *capability_bounding_set_drop |= sum;
957 *capability_bounding_set_drop |= ~sum;
962 int config_parse_limit(const char *unit,
963 const char *filename,
972 struct rlimit **rl = data;
973 unsigned long long u;
982 if (streq(rvalue, "infinity"))
983 u = (unsigned long long) RLIM_INFINITY;
987 r = safe_atollu(rvalue, &u);
989 log_syntax(unit, LOG_ERR, filename, line, -r,
990 "Failed to parse resource value, ignoring: %s", rvalue);
996 *rl = new(struct rlimit, 1);
1001 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1005 #ifdef HAVE_SYSV_COMPAT
1006 int config_parse_sysv_priority(const char *unit,
1007 const char *filename,
1009 const char *section,
1016 int *priority = data;
1024 r = safe_atoi(rvalue, &i);
1025 if (r < 0 || i < 0) {
1026 log_syntax(unit, LOG_ERR, filename, line, -r,
1027 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1031 *priority = (int) i;
1036 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1038 int config_parse_kill_signal(const char *unit,
1039 const char *filename,
1041 const char *section,
1056 r = signal_from_string_try_harder(rvalue);
1058 log_syntax(unit, LOG_ERR, filename, line, -r,
1059 "Failed to parse kill signal, ignoring: %s", rvalue);
1067 int config_parse_exec_mount_flags(const char *unit,
1068 const char *filename,
1070 const char *section,
1077 ExecContext *c = data;
1081 unsigned long flags = 0;
1088 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1089 _cleanup_free_ char *t;
1095 if (streq(t, "shared"))
1097 else if (streq(t, "slave"))
1099 else if (streq(w, "private"))
1100 flags |= MS_PRIVATE;
1102 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1103 "Failed to parse mount flag %s, ignoring: %s",
1109 c->mount_flags = flags;
1113 int config_parse_timer(const char *unit,
1114 const char *filename,
1116 const char *section,
1127 CalendarSpec *c = NULL;
1135 if (isempty(rvalue)) {
1136 /* Empty assignment resets list */
1137 timer_free_values(t);
1141 b = timer_base_from_string(lvalue);
1143 log_syntax(unit, LOG_ERR, filename, line, -b,
1144 "Failed to parse timer base, ignoring: %s", lvalue);
1148 if (b == TIMER_CALENDAR) {
1149 if (calendar_spec_from_string(rvalue, &c) < 0) {
1150 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1151 "Failed to parse calendar specification, ignoring: %s",
1156 id = CLOCK_REALTIME;
1158 if (parse_sec(rvalue, &u) < 0) {
1159 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1160 "Failed to parse timer value, ignoring: %s",
1165 id = CLOCK_MONOTONIC;
1168 v = new0(TimerValue, 1);
1175 v->calendar_spec = c;
1177 LIST_PREPEND(value, t->values, v);
1182 int config_parse_trigger_unit(
1184 const char *filename,
1186 const char *section,
1193 _cleanup_free_ char *p = NULL;
1203 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1204 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1205 "Multiple units to trigger specified, ignoring: %s", rvalue);
1209 r = unit_name_printf(u, rvalue, &p);
1211 log_syntax(unit, LOG_ERR, filename, line, -r,
1212 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1214 type = unit_name_to_type(p ?: rvalue);
1216 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1217 "Unit type not valid, ignoring: %s", rvalue);
1221 if (type == u->type) {
1222 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1223 "Trigger cannot be of same type, ignoring: %s", rvalue);
1227 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1229 log_syntax(unit, LOG_ERR, filename, line, -r,
1230 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1237 int config_parse_path_spec(const char *unit,
1238 const char *filename,
1240 const char *section,
1250 _cleanup_free_ char *k = NULL;
1258 if (isempty(rvalue)) {
1259 /* Empty assignment clears list */
1264 b = path_type_from_string(lvalue);
1266 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1267 "Failed to parse path type, ignoring: %s", lvalue);
1271 r = unit_full_printf(UNIT(p), rvalue, &k);
1277 log_syntax(unit, LOG_ERR, filename, line, -r,
1278 "Failed to resolve unit specifiers on %s. Ignoring.",
1282 if (!path_is_absolute(k)) {
1283 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1284 "Path is not absolute, ignoring: %s", k);
1288 s = new0(PathSpec, 1);
1293 s->path = path_kill_slashes(k);
1298 LIST_PREPEND(spec, p->specs, s);
1303 int config_parse_socket_service(const char *unit,
1304 const char *filename,
1306 const char *section,
1313 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1317 _cleanup_free_ char *p = NULL;
1324 r = unit_name_printf(UNIT(s), rvalue, &p);
1326 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1328 if (!endswith(p ?: rvalue, ".service")) {
1329 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1333 r = manager_load_unit(UNIT(s)->manager, p ?: rvalue, NULL, &error, &x);
1335 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1339 unit_ref_set(&s->service, x);
1344 int config_parse_service_sockets(const char *unit,
1345 const char *filename,
1347 const char *section,
1364 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1365 _cleanup_free_ char *t = NULL, *k = NULL;
1371 r = unit_name_printf(UNIT(s), t, &k);
1373 log_syntax(unit, LOG_ERR, filename, line, -r,
1374 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1376 if (!endswith(k ?: t, ".socket")) {
1377 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1378 "Unit must be of type socket, ignoring: %s", k ?: t);
1382 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1384 log_syntax(unit, LOG_ERR, filename, line, -r,
1385 "Failed to add dependency on %s, ignoring: %s",
1386 k ?: t, strerror(-r));
1388 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1396 int config_parse_service_timeout(const char *unit,
1397 const char *filename,
1399 const char *section,
1406 Service *s = userdata;
1414 r = config_parse_sec(unit, filename, line, section, lvalue, ltype,
1415 rvalue, data, userdata);
1419 if (streq(lvalue, "TimeoutSec")) {
1420 s->start_timeout_defined = true;
1421 s->timeout_stop_usec = s->timeout_start_usec;
1422 } else if (streq(lvalue, "TimeoutStartSec"))
1423 s->start_timeout_defined = true;
1428 int config_parse_unit_env_file(const char *unit,
1429 const char *filename,
1431 const char *section,
1440 _cleanup_free_ char *n = NULL;
1449 if (isempty(rvalue)) {
1450 /* Empty assignment frees the list */
1456 r = unit_full_printf(u, rvalue, &n);
1458 log_syntax(unit, LOG_ERR, filename, line, r,
1459 "Failed to resolve specifiers, ignoring: %s", rvalue);
1462 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1463 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1464 "Path '%s' is not absolute, ignoring.", s);
1468 r = strv_extend(env, s);
1475 int config_parse_environ(const char *unit,
1476 const char *filename,
1478 const char *section,
1486 char*** env = data, *w, *state;
1488 _cleanup_free_ char *k = NULL;
1496 if (isempty(rvalue)) {
1497 /* Empty assignment resets the list */
1504 r = unit_full_printf(u, rvalue, &k);
1506 log_syntax(unit, LOG_ERR, filename, line, -r,
1507 "Failed to resolve specifiers, ignoring: %s", rvalue);
1515 FOREACH_WORD_QUOTED(w, l, k, state) {
1516 _cleanup_free_ char *n;
1519 n = cunescape_length(w, l);
1523 if (!env_assignment_is_valid(n)) {
1524 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1525 "Invalid environment assignment, ignoring: %s", rvalue);
1529 x = strv_env_set(*env, n);
1540 int config_parse_ip_tos(const char *unit,
1541 const char *filename,
1543 const char *section,
1550 int *ip_tos = data, x;
1557 x = ip_tos_from_string(rvalue);
1559 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1560 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1568 int config_parse_unit_condition_path(const char *unit,
1569 const char *filename,
1571 const char *section,
1578 ConditionType cond = ltype;
1580 bool trigger, negate;
1582 _cleanup_free_ char *p = NULL;
1590 if (isempty(rvalue)) {
1591 /* Empty assignment resets the list */
1592 condition_free_list(u->conditions);
1593 u->conditions = NULL;
1597 trigger = rvalue[0] == '|';
1601 negate = rvalue[0] == '!';
1605 r = unit_full_printf(u, rvalue, &p);
1607 log_syntax(unit, LOG_ERR, filename, line, -r,
1608 "Failed to resolve specifiers, ignoring: %s", rvalue);
1615 if (!path_is_absolute(p)) {
1616 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1617 "Path in condition not absolute, ignoring: %s", p);
1621 c = condition_new(cond, p, trigger, negate);
1625 LIST_PREPEND(conditions, u->conditions, c);
1629 int config_parse_unit_condition_string(const char *unit,
1630 const char *filename,
1632 const char *section,
1639 ConditionType cond = ltype;
1641 bool trigger, negate;
1643 _cleanup_free_ char *s = NULL;
1651 if (isempty(rvalue)) {
1652 /* Empty assignment resets the list */
1653 condition_free_list(u->conditions);
1654 u->conditions = NULL;
1658 trigger = rvalue[0] == '|';
1662 negate = rvalue[0] == '!';
1666 r = unit_full_printf(u, rvalue, &s);
1668 log_syntax(unit, LOG_ERR, filename, line, -r,
1669 "Failed to resolve specifiers, ignoring: %s", rvalue);
1676 c = condition_new(cond, s, trigger, negate);
1680 LIST_PREPEND(conditions, u->conditions, c);
1684 int config_parse_unit_condition_null(const char *unit,
1685 const char *filename,
1687 const char *section,
1696 bool trigger, negate;
1704 if (isempty(rvalue)) {
1705 /* Empty assignment resets the list */
1706 condition_free_list(u->conditions);
1707 u->conditions = NULL;
1711 trigger = rvalue[0] == '|';
1715 negate = rvalue[0] == '!';
1719 b = parse_boolean(rvalue);
1721 log_syntax(unit, LOG_ERR, filename, line, -b,
1722 "Failed to parse boolean value in condition, ignoring: %s",
1730 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1734 LIST_PREPEND(conditions, u->conditions, c);
1738 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1739 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1741 int config_parse_unit_requires_mounts_for(
1743 const char *filename,
1745 const char *section,
1762 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1764 _cleanup_free_ char *n;
1770 if (!utf8_is_valid(n)) {
1771 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1772 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
1776 r = unit_require_mounts_for(u, n);
1778 log_syntax(unit, LOG_ERR, filename, line, r,
1779 "Failed to add required mount for, ignoring: %s", rvalue);
1787 int config_parse_documentation(const char *unit,
1788 const char *filename,
1790 const char *section,
1806 if (isempty(rvalue)) {
1807 /* Empty assignment resets the list */
1808 strv_free(u->documentation);
1809 u->documentation = NULL;
1813 r = config_parse_unit_strv_printf(unit, filename, line, section, lvalue, ltype,
1814 rvalue, data, userdata);
1818 for (a = b = u->documentation; a && *a; a++) {
1820 if (is_valid_documentation_url(*a))
1823 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1824 "Invalid URL, ignoring: %s", *a);
1834 static void syscall_set(uint32_t *p, int nr) {
1835 nr = SYSCALL_TO_INDEX(nr);
1836 p[nr >> 4] |= 1 << (nr & 31);
1839 static void syscall_unset(uint32_t *p, int nr) {
1840 nr = SYSCALL_TO_INDEX(nr);
1841 p[nr >> 4] &= ~(1 << (nr & 31));
1844 int config_parse_syscall_filter(const char *unit,
1845 const char *filename,
1847 const char *section,
1854 ExecContext *c = data;
1856 bool invert = false;
1866 if (isempty(rvalue)) {
1867 /* Empty assignment resets the list */
1868 free(c->syscall_filter);
1869 c->syscall_filter = NULL;
1873 if (rvalue[0] == '~') {
1878 if (!c->syscall_filter) {
1881 n = (syscall_max() + 31) >> 4;
1882 c->syscall_filter = new(uint32_t, n);
1883 if (!c->syscall_filter)
1886 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
1888 /* Add these by default */
1889 syscall_set(c->syscall_filter, __NR_execve);
1890 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
1891 #ifdef __NR_sigreturn
1892 syscall_set(c->syscall_filter, __NR_sigreturn);
1894 syscall_set(c->syscall_filter, __NR_exit_group);
1895 syscall_set(c->syscall_filter, __NR_exit);
1898 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1900 _cleanup_free_ char *t = NULL;
1906 id = syscall_from_name(t);
1908 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1909 "Failed to parse syscall, ignoring: %s", t);
1914 syscall_unset(c->syscall_filter, id);
1916 syscall_set(c->syscall_filter, id);
1919 c->no_new_privileges = true;
1924 int config_parse_unit_slice(
1926 const char *filename,
1928 const char *section,
1935 _cleanup_free_ char *k = NULL;
1936 Unit *u = userdata, *slice;
1944 r = unit_name_printf(u, rvalue, &k);
1946 log_syntax(unit, LOG_ERR, filename, line, -r,
1947 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
1954 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
1956 log_syntax(unit, LOG_ERR, filename, line, -r,
1957 "Failed to load slice unit %s. Ignoring.", k);
1961 if (slice->type != UNIT_SLICE) {
1962 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1963 "Slice unit %s is not a slice. Ignoring.", k);
1967 unit_ref_set(&u->slice, slice);
1971 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
1973 int config_parse_cpu_shares(
1975 const char *filename,
1977 const char *section,
1984 CGroupContext *c = data;
1992 if (isempty(rvalue)) {
1993 c->cpu_shares = 1024;
1997 r = safe_atolu(rvalue, &lu);
1998 if (r < 0 || lu <= 0) {
1999 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2000 "CPU shares '%s' invalid. Ignoring.", rvalue);
2008 int config_parse_memory_limit(
2010 const char *filename,
2012 const char *section,
2019 CGroupContext *c = data;
2023 if (isempty(rvalue)) {
2024 c->memory_limit = (uint64_t) -1;
2028 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2030 r = parse_bytes(rvalue, &bytes);
2032 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2033 "Memory limit '%s' invalid. Ignoring.", rvalue);
2037 c->memory_limit = (uint64_t) bytes;
2041 int config_parse_device_allow(
2043 const char *filename,
2045 const char *section,
2052 _cleanup_free_ char *path = NULL;
2053 CGroupContext *c = data;
2054 CGroupDeviceAllow *a;
2058 if (isempty(rvalue)) {
2059 while (c->device_allow)
2060 cgroup_context_free_device_allow(c, c->device_allow);
2065 n = strcspn(rvalue, WHITESPACE);
2066 path = strndup(rvalue, n);
2070 if (!path_startswith(path, "/dev")) {
2071 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2072 "Invalid device node path '%s'. Ignoring.", path);
2076 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2080 if (!in_charset(m, "rwm")) {
2081 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2082 "Invalid device rights '%s'. Ignoring.", m);
2086 a = new0(CGroupDeviceAllow, 1);
2092 a->r = !!strchr(m, 'r');
2093 a->w = !!strchr(m, 'w');
2094 a->m = !!strchr(m, 'm');
2096 LIST_PREPEND(device_allow, c->device_allow, a);
2100 int config_parse_blockio_weight(
2102 const char *filename,
2104 const char *section,
2111 CGroupContext *c = data;
2119 if (isempty(rvalue)) {
2120 c->blockio_weight = 1000;
2124 r = safe_atolu(rvalue, &lu);
2125 if (r < 0 || lu < 10 || lu > 1000) {
2126 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2127 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2131 c->blockio_weight = lu;
2136 int config_parse_blockio_device_weight(
2138 const char *filename,
2140 const char *section,
2147 _cleanup_free_ char *path = NULL;
2148 CGroupBlockIODeviceWeight *w;
2149 CGroupContext *c = data;
2159 if (isempty(rvalue)) {
2160 while (c->blockio_device_weights)
2161 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2166 n = strcspn(rvalue, WHITESPACE);
2167 weight = rvalue + n;
2169 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2170 "Expected block device and device weight. Ignoring.");
2174 path = strndup(rvalue, n);
2178 if (!path_startswith(path, "/dev")) {
2179 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2180 "Invalid device node path '%s'. Ignoring.", path);
2184 weight += strspn(weight, WHITESPACE);
2185 r = safe_atolu(weight, &lu);
2186 if (r < 0 || lu < 10 || lu > 1000) {
2187 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2188 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2193 w = new0(CGroupBlockIODeviceWeight, 1);
2202 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2206 int config_parse_blockio_bandwidth(
2208 const char *filename,
2210 const char *section,
2217 _cleanup_free_ char *path = NULL;
2218 CGroupBlockIODeviceBandwidth *b;
2219 CGroupContext *c = data;
2220 const char *bandwidth;
2230 read = streq("BlockIOReadBandwidth", lvalue);
2232 if (isempty(rvalue)) {
2233 CGroupBlockIODeviceBandwidth *next;
2235 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2236 if (b->read == read)
2237 cgroup_context_free_blockio_device_bandwidth(c, b);
2242 n = strcspn(rvalue, WHITESPACE);
2243 bandwidth = rvalue + n;
2244 bandwidth += strspn(bandwidth, WHITESPACE);
2247 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2248 "Expected space separated pair of device node and bandwidth. Ignoring.");
2252 path = strndup(rvalue, n);
2256 if (!path_startswith(path, "/dev")) {
2257 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2258 "Invalid device node path '%s'. Ignoring.", path);
2262 r = parse_bytes(bandwidth, &bytes);
2263 if (r < 0 || bytes <= 0) {
2264 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2265 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2269 b = new0(CGroupBlockIODeviceBandwidth, 1);
2275 b->bandwidth = (uint64_t) bytes;
2278 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2283 #define FOLLOW_MAX 8
2285 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2296 /* This will update the filename pointer if the loaded file is
2297 * reached by a symlink. The old string will be freed. */
2300 char *target, *name;
2302 if (c++ >= FOLLOW_MAX)
2305 path_kill_slashes(*filename);
2307 /* Add the file name we are currently looking at to
2308 * the names of this unit, but only if it is a valid
2310 name = path_get_file_name(*filename);
2312 if (unit_name_is_valid(name, true)) {
2314 id = set_get(names, name);
2320 r = set_consume(names, id);
2326 /* Try to open the file name, but don't if its a symlink */
2327 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2334 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2335 r = readlink_and_make_absolute(*filename, &target);
2343 f = fdopen(fd, "re");
2346 close_nointr_nofail(fd);
2355 static int merge_by_names(Unit **u, Set *names, const char *id) {
2363 /* Let's try to add in all symlink names we found */
2364 while ((k = set_steal_first(names))) {
2366 /* First try to merge in the other name into our
2368 r = unit_merge_by_name(*u, k);
2372 /* Hmm, we couldn't merge the other unit into
2373 * ours? Then let's try it the other way
2376 other = manager_get_unit((*u)->manager, k);
2380 r = unit_merge(other, *u);
2383 return merge_by_names(u, names, NULL);
2391 unit_choose_id(*u, id);
2399 static int load_from_path(Unit *u, const char *path) {
2401 _cleanup_set_free_free_ Set *symlink_names = NULL;
2402 _cleanup_fclose_ FILE *f = NULL;
2403 _cleanup_free_ char *filename = NULL;
2411 symlink_names = set_new(string_hash_func, string_compare_func);
2415 if (path_is_absolute(path)) {
2417 filename = strdup(path);
2421 r = open_follow(&filename, &f, symlink_names, &id);
2433 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2435 /* Instead of opening the path right away, we manually
2436 * follow all symlinks and add their name to our unit
2437 * name set while doing so */
2438 filename = path_make_absolute(path, *p);
2442 if (u->manager->unit_path_cache &&
2443 !set_get(u->manager->unit_path_cache, filename))
2446 r = open_follow(&filename, &f, symlink_names, &id);
2455 /* Empty the symlink names for the next run */
2456 set_clear_free(symlink_names);
2465 /* Hmm, no suitable file found? */
2469 r = merge_by_names(&merged, symlink_names, id);
2474 u->load_state = UNIT_MERGED;
2478 if (fstat(fileno(f), &st) < 0)
2481 if (null_or_empty(&st))
2482 u->load_state = UNIT_MASKED;
2484 u->load_state = UNIT_LOADED;
2486 /* Now, parse the file contents */
2487 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2488 config_item_perf_lookup,
2489 (void*) load_fragment_gperf_lookup, false, true, u);
2494 free(u->fragment_path);
2495 u->fragment_path = filename;
2498 u->fragment_mtime = timespec_load(&st.st_mtim);
2500 if (u->source_path) {
2501 if (stat(u->source_path, &st) >= 0)
2502 u->source_mtime = timespec_load(&st.st_mtim);
2504 u->source_mtime = 0;
2510 int unit_load_fragment(Unit *u) {
2516 assert(u->load_state == UNIT_STUB);
2519 /* First, try to find the unit under its id. We always look
2520 * for unit files in the default directories, to make it easy
2521 * to override things by placing things in /etc/systemd/system */
2522 r = load_from_path(u, u->id);
2526 /* Try to find an alias we can load this with */
2527 if (u->load_state == UNIT_STUB)
2528 SET_FOREACH(t, u->names, i) {
2533 r = load_from_path(u, t);
2537 if (u->load_state != UNIT_STUB)
2541 /* And now, try looking for it under the suggested (originally linked) path */
2542 if (u->load_state == UNIT_STUB && u->fragment_path) {
2544 r = load_from_path(u, u->fragment_path);
2548 if (u->load_state == UNIT_STUB) {
2549 /* Hmm, this didn't work? Then let's get rid
2550 * of the fragment path stored for us, so that
2551 * we don't point to an invalid location. */
2552 free(u->fragment_path);
2553 u->fragment_path = NULL;
2557 /* Look for a template */
2558 if (u->load_state == UNIT_STUB && u->instance) {
2561 k = unit_name_template(u->id);
2565 r = load_from_path(u, k);
2571 if (u->load_state == UNIT_STUB)
2572 SET_FOREACH(t, u->names, i) {
2577 k = unit_name_template(t);
2581 r = load_from_path(u, k);
2587 if (u->load_state != UNIT_STUB)
2595 void unit_dump_config_items(FILE *f) {
2596 static const struct {
2597 const ConfigParserCallback callback;
2600 { config_parse_int, "INTEGER" },
2601 { config_parse_unsigned, "UNSIGNED" },
2602 { config_parse_bytes_size, "SIZE" },
2603 { config_parse_bool, "BOOLEAN" },
2604 { config_parse_string, "STRING" },
2605 { config_parse_path, "PATH" },
2606 { config_parse_unit_path_printf, "PATH" },
2607 { config_parse_strv, "STRING [...]" },
2608 { config_parse_exec_nice, "NICE" },
2609 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2610 { config_parse_exec_io_class, "IOCLASS" },
2611 { config_parse_exec_io_priority, "IOPRIORITY" },
2612 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2613 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2614 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2615 { config_parse_mode, "MODE" },
2616 { config_parse_unit_env_file, "FILE" },
2617 { config_parse_output, "OUTPUT" },
2618 { config_parse_input, "INPUT" },
2619 { config_parse_facility, "FACILITY" },
2620 { config_parse_level, "LEVEL" },
2621 { config_parse_exec_capabilities, "CAPABILITIES" },
2622 { config_parse_exec_secure_bits, "SECUREBITS" },
2623 { config_parse_bounding_set, "BOUNDINGSET" },
2624 { config_parse_limit, "LIMIT" },
2625 { config_parse_unit_deps, "UNIT [...]" },
2626 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2627 { config_parse_service_type, "SERVICETYPE" },
2628 { config_parse_service_restart, "SERVICERESTART" },
2629 #ifdef HAVE_SYSV_COMPAT
2630 { config_parse_sysv_priority, "SYSVPRIORITY" },
2632 { config_parse_warn_compat, "NOTSUPPORTED" },
2634 { config_parse_kill_mode, "KILLMODE" },
2635 { config_parse_kill_signal, "SIGNAL" },
2636 { config_parse_socket_listen, "SOCKET [...]" },
2637 { config_parse_socket_bind, "SOCKETBIND" },
2638 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2639 { config_parse_sec, "SECONDS" },
2640 { config_parse_nsec, "NANOSECONDS" },
2641 { config_parse_path_strv, "PATH [...]" },
2642 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2643 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2644 { config_parse_unit_string_printf, "STRING" },
2645 { config_parse_trigger_unit, "UNIT" },
2646 { config_parse_timer, "TIMER" },
2647 { config_parse_path_spec, "PATH" },
2648 { config_parse_notify_access, "ACCESS" },
2649 { config_parse_ip_tos, "TOS" },
2650 { config_parse_unit_condition_path, "CONDITION" },
2651 { config_parse_unit_condition_string, "CONDITION" },
2652 { config_parse_unit_condition_null, "CONDITION" },
2653 { config_parse_unit_slice, "SLICE" },
2654 { config_parse_documentation, "URL" },
2655 { config_parse_service_timeout, "SECONDS" },
2656 { config_parse_start_limit_action, "ACTION" },
2657 { config_parse_set_status, "STATUS" },
2658 { config_parse_service_sockets, "SOCKETS" },
2659 { config_parse_environ, "ENVIRON" },
2660 { config_parse_syscall_filter, "SYSCALL" },
2661 { config_parse_cpu_shares, "SHARES" },
2662 { config_parse_memory_limit, "LIMIT" },
2663 { config_parse_device_allow, "DEVICE" },
2664 { config_parse_device_policy, "POLICY" },
2665 { config_parse_blockio_bandwidth, "BANDWIDTH" },
2666 { config_parse_blockio_weight, "WEIGHT" },
2667 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
2668 { config_parse_long, "LONG" },
2669 { config_parse_socket_service, "SERVICE" },
2672 const char *prev = NULL;
2677 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2678 const char *rvalue = "OTHER", *lvalue;
2682 const ConfigPerfItem *p;
2684 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2686 dot = strchr(i, '.');
2687 lvalue = dot ? dot + 1 : i;
2691 if (!prev || !strneq(prev, i, prefix_len+1)) {
2695 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2698 for (j = 0; j < ELEMENTSOF(table); j++)
2699 if (p->parse == table[j].callback) {
2700 rvalue = table[j].rvalue;
2704 fprintf(f, "%s=%s\n", lvalue, rvalue);