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>
36 #include <sys/types.h>
43 #include "sd-messages.h"
46 #include "conf-parser.h"
47 #include "load-fragment.h"
50 #include "securebits.h"
52 #include "unit-name.h"
53 #include "unit-printf.h"
55 #include "path-util.h"
59 #include "bus-error.h"
60 #include "errno-list.h"
64 #include "seccomp-util.h"
67 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
68 int config_parse_warn_compat(
73 unsigned section_line,
80 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
81 "Support for option %s= has been disabled at compile time and is ignored",
87 int config_parse_unit_deps(const char* unit,
91 unsigned section_line,
98 UnitDependency d = ltype;
108 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
109 _cleanup_free_ char *t = NULL, *k = NULL;
116 r = unit_name_printf(u, t, &k);
118 log_syntax(unit, LOG_ERR, filename, line, -r,
119 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
123 r = unit_add_dependency_by_name(u, d, k, NULL, true);
125 log_syntax(unit, LOG_ERR, filename, line, -r,
126 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
132 int config_parse_unit_string_printf(const char *unit,
133 const char *filename,
136 unsigned section_line,
144 _cleanup_free_ char *k = NULL;
152 r = unit_full_printf(u, rvalue, &k);
154 log_syntax(unit, LOG_ERR, filename, line, -r,
155 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
157 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
158 k ? k : rvalue, data, userdata);
161 int config_parse_unit_strv_printf(const char *unit,
162 const char *filename,
165 unsigned section_line,
173 _cleanup_free_ char *k = NULL;
181 r = unit_full_printf(u, rvalue, &k);
183 log_syntax(unit, LOG_ERR, filename, line, -r,
184 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
186 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
187 k ? k : rvalue, data, userdata);
190 int config_parse_unit_path_printf(const char *unit,
191 const char *filename,
194 unsigned section_line,
202 _cleanup_free_ char *k = NULL;
210 r = unit_full_printf(u, rvalue, &k);
212 log_syntax(unit, LOG_ERR, filename, line, -r,
213 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
215 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype,
216 k ? k : rvalue, data, userdata);
219 int config_parse_socket_listen(const char *unit,
220 const char *filename,
223 unsigned section_line,
230 SocketPort *p, *tail;
241 if (isempty(rvalue)) {
242 /* An empty assignment removes all ports */
243 socket_free_ports(s);
247 p = new0(SocketPort, 1);
251 if (ltype != SOCKET_SOCKET) {
254 r = unit_full_printf(UNIT(s), rvalue, &p->path);
256 p->path = strdup(rvalue);
261 log_syntax(unit, LOG_ERR, filename, line, -r,
262 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
265 path_kill_slashes(p->path);
267 } else if (streq(lvalue, "ListenNetlink")) {
268 _cleanup_free_ char *k = NULL;
270 p->type = SOCKET_SOCKET;
271 r = unit_full_printf(UNIT(s), rvalue, &k);
273 log_syntax(unit, LOG_ERR, filename, line, -r,
274 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
276 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
278 log_syntax(unit, LOG_ERR, filename, line, -r,
279 "Failed to parse address value, ignoring: %s", rvalue);
285 _cleanup_free_ char *k = NULL;
287 p->type = SOCKET_SOCKET;
288 r = unit_full_printf(UNIT(s), rvalue, &k);
290 log_syntax(unit, LOG_ERR, filename, line, -r,
291 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
293 r = socket_address_parse(&p->address, k ? k : rvalue);
295 log_syntax(unit, LOG_ERR, filename, line, -r,
296 "Failed to parse address value, ignoring: %s", rvalue);
301 if (streq(lvalue, "ListenStream"))
302 p->address.type = SOCK_STREAM;
303 else if (streq(lvalue, "ListenDatagram"))
304 p->address.type = SOCK_DGRAM;
306 assert(streq(lvalue, "ListenSequentialPacket"));
307 p->address.type = SOCK_SEQPACKET;
310 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
311 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
312 "Address family not supported, ignoring: %s", rvalue);
322 LIST_FIND_TAIL(port, s->ports, tail);
323 LIST_INSERT_AFTER(port, s->ports, tail, p);
325 LIST_PREPEND(port, s->ports, p);
330 int config_parse_socket_bind(const char *unit,
331 const char *filename,
334 unsigned section_line,
342 SocketAddressBindIPv6Only b;
351 b = socket_address_bind_ipv6_only_from_string(rvalue);
355 r = parse_boolean(rvalue);
357 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
358 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
362 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
364 s->bind_ipv6_only = b;
369 int config_parse_exec_nice(const char *unit,
370 const char *filename,
373 unsigned section_line,
380 ExecContext *c = data;
388 r = safe_atoi(rvalue, &priority);
390 log_syntax(unit, LOG_ERR, filename, line, -r,
391 "Failed to parse nice priority, ignoring: %s. ", rvalue);
395 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
396 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
397 "Nice priority out of range, ignoring: %s", rvalue);
407 int config_parse_exec_oom_score_adjust(const char* unit,
408 const char *filename,
411 unsigned section_line,
418 ExecContext *c = data;
426 r = safe_atoi(rvalue, &oa);
428 log_syntax(unit, LOG_ERR, filename, line, -r,
429 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
433 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
434 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
435 "OOM score adjust value out of range, ignoring: %s", rvalue);
439 c->oom_score_adjust = oa;
440 c->oom_score_adjust_set = true;
445 int config_parse_exec(const char *unit,
446 const char *filename,
449 unsigned section_line,
456 ExecCommand **e = data, *nce;
468 if (isempty(rvalue)) {
469 /* An empty assignment resets the list */
470 exec_command_free_list(*e);
475 /* We accept an absolute path as first argument, or
476 * alternatively an absolute prefixed with @ to allow
477 * overriding of argv[0]. */
483 bool honour_argv0 = false, ignore = false;
489 rvalue += strspn(rvalue, WHITESPACE);
494 for (i = 0; i < 2; i++) {
495 if (rvalue[0] == '-' && !ignore) {
500 if (rvalue[0] == '@' && !honour_argv0) {
506 if (*rvalue != '/') {
507 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
508 "Executable path is not absolute, ignoring: %s", rvalue);
513 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
514 if (strneq(w, ";", MAX(l, 1U)))
520 n = new(char*, k + !honour_argv0);
525 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
526 if (strneq(w, ";", MAX(l, 1U)))
528 else if (strneq(w, "\\;", MAX(l, 1U)))
531 if (honour_argv0 && w == rvalue) {
534 path = strndup(w, l);
540 if (!utf8_is_valid(path)) {
541 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
549 c = n[k++] = cunescape_length(w, l);
555 if (!utf8_is_valid(c)) {
556 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
566 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
567 "Invalid command line, ignoring: %s", rvalue);
580 assert(path_is_absolute(path));
582 nce = new0(ExecCommand, 1);
590 nce->ignore = ignore;
592 path_kill_slashes(nce->path);
594 exec_command_append_list(e, nce);
610 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
611 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
613 int config_parse_socket_bindtodevice(const char* unit,
614 const char *filename,
617 unsigned section_line,
632 if (rvalue[0] && !streq(rvalue, "*")) {
639 free(s->bind_to_device);
640 s->bind_to_device = n;
645 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
646 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
648 int config_parse_exec_io_class(const char *unit,
649 const char *filename,
652 unsigned section_line,
659 ExecContext *c = data;
667 x = ioprio_class_from_string(rvalue);
669 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
670 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
674 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
675 c->ioprio_set = true;
680 int config_parse_exec_io_priority(const char *unit,
681 const char *filename,
684 unsigned section_line,
691 ExecContext *c = data;
699 r = safe_atoi(rvalue, &i);
700 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
701 log_syntax(unit, LOG_ERR, filename, line, -r,
702 "Failed to parse IO priority, ignoring: %s", rvalue);
706 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
707 c->ioprio_set = true;
712 int config_parse_exec_cpu_sched_policy(const char *unit,
713 const char *filename,
716 unsigned section_line,
724 ExecContext *c = data;
732 x = sched_policy_from_string(rvalue);
734 log_syntax(unit, LOG_ERR, filename, line, -x,
735 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
739 c->cpu_sched_policy = x;
740 /* Moving to or from real-time policy? We need to adjust the priority */
741 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
742 c->cpu_sched_set = true;
747 int config_parse_exec_cpu_sched_prio(const char *unit,
748 const char *filename,
751 unsigned section_line,
758 ExecContext *c = data;
766 r = safe_atoi(rvalue, &i);
768 log_syntax(unit, LOG_ERR, filename, line, -r,
769 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
773 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
774 min = sched_get_priority_min(c->cpu_sched_policy);
775 max = sched_get_priority_max(c->cpu_sched_policy);
777 if (i < min || i > max) {
778 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
779 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
783 c->cpu_sched_priority = i;
784 c->cpu_sched_set = true;
789 int config_parse_exec_cpu_affinity(const char *unit,
790 const char *filename,
793 unsigned section_line,
800 ExecContext *c = data;
810 if (isempty(rvalue)) {
811 /* An empty assignment resets the CPU list */
818 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
819 _cleanup_free_ char *t = NULL;
827 r = safe_atou(t, &cpu);
830 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
835 if (r < 0 || cpu >= c->cpuset_ncpus) {
836 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
837 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
841 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
847 int config_parse_exec_capabilities(const char *unit,
848 const char *filename,
851 unsigned section_line,
858 ExecContext *c = data;
866 cap = cap_from_text(rvalue);
868 log_syntax(unit, LOG_ERR, filename, line, errno,
869 "Failed to parse capabilities, ignoring: %s", rvalue);
874 cap_free(c->capabilities);
875 c->capabilities = cap;
880 int config_parse_exec_secure_bits(const char *unit,
881 const char *filename,
884 unsigned section_line,
891 ExecContext *c = data;
901 if (isempty(rvalue)) {
902 /* An empty assignment resets the field */
907 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
908 if (first_word(w, "keep-caps"))
909 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
910 else if (first_word(w, "keep-caps-locked"))
911 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
912 else if (first_word(w, "no-setuid-fixup"))
913 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
914 else if (first_word(w, "no-setuid-fixup-locked"))
915 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
916 else if (first_word(w, "noroot"))
917 c->secure_bits |= 1<<SECURE_NOROOT;
918 else if (first_word(w, "noroot-locked"))
919 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
921 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
922 "Failed to parse secure bits, ignoring: %s", rvalue);
930 int config_parse_bounding_set(const char *unit,
931 const char *filename,
934 unsigned section_line,
941 uint64_t *capability_bounding_set_drop = data;
953 if (rvalue[0] == '~') {
958 /* Note that we store this inverted internally, since the
959 * kernel wants it like this. But we actually expose it
960 * non-inverted everywhere to have a fully normalized
963 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
964 _cleanup_free_ char *t = NULL;
972 r = cap_from_name(t, &cap);
974 log_syntax(unit, LOG_ERR, filename, line, errno,
975 "Failed to parse capability in bounding set, ignoring: %s", t);
979 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
983 *capability_bounding_set_drop |= sum;
985 *capability_bounding_set_drop |= ~sum;
990 int config_parse_limit(const char *unit,
991 const char *filename,
994 unsigned section_line,
1001 struct rlimit **rl = data;
1002 unsigned long long u;
1011 if (streq(rvalue, "infinity"))
1012 u = (unsigned long long) RLIM_INFINITY;
1016 r = safe_atollu(rvalue, &u);
1018 log_syntax(unit, LOG_ERR, filename, line, -r,
1019 "Failed to parse resource value, ignoring: %s", rvalue);
1025 *rl = new(struct rlimit, 1);
1030 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1034 #ifdef HAVE_SYSV_COMPAT
1035 int config_parse_sysv_priority(const char *unit,
1036 const char *filename,
1038 const char *section,
1039 unsigned section_line,
1046 int *priority = data;
1054 r = safe_atoi(rvalue, &i);
1055 if (r < 0 || i < 0) {
1056 log_syntax(unit, LOG_ERR, filename, line, -r,
1057 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1061 *priority = (int) i;
1066 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1068 int config_parse_kill_signal(const char *unit,
1069 const char *filename,
1071 const char *section,
1072 unsigned section_line,
1087 r = signal_from_string_try_harder(rvalue);
1089 log_syntax(unit, LOG_ERR, filename, line, -r,
1090 "Failed to parse kill signal, ignoring: %s", rvalue);
1098 int config_parse_exec_mount_flags(const char *unit,
1099 const char *filename,
1101 const char *section,
1102 unsigned section_line,
1109 ExecContext *c = data;
1113 unsigned long flags = 0;
1120 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1121 _cleanup_free_ char *t;
1127 if (streq(t, "shared"))
1129 else if (streq(t, "slave"))
1131 else if (streq(w, "private"))
1132 flags |= MS_PRIVATE;
1134 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1135 "Failed to parse mount flag %s, ignoring: %s",
1141 c->mount_flags = flags;
1145 int config_parse_exec_selinux_context(
1147 const char *filename,
1149 const char *section,
1150 unsigned section_line,
1157 ExecContext *c = data;
1168 if (isempty(rvalue)) {
1169 free(c->selinux_context);
1170 c->selinux_context = NULL;
1171 c->selinux_context_ignore = false;
1175 if (rvalue[0] == '-') {
1181 r = unit_name_printf(u, rvalue, &k);
1183 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1187 free(c->selinux_context);
1188 c->selinux_context = k;
1189 c->selinux_context_ignore = ignore;
1194 int config_parse_exec_apparmor_profile(
1196 const char *filename,
1198 const char *section,
1199 unsigned section_line,
1206 ExecContext *c = data;
1217 if (isempty(rvalue)) {
1218 free(c->apparmor_profile);
1219 c->apparmor_profile = NULL;
1220 c->apparmor_profile_ignore = false;
1224 if (rvalue[0] == '-') {
1230 r = unit_name_printf(u, rvalue, &k);
1232 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1236 free(c->apparmor_profile);
1237 c->apparmor_profile = k;
1238 c->apparmor_profile_ignore = ignore;
1243 int config_parse_timer(const char *unit,
1244 const char *filename,
1246 const char *section,
1247 unsigned section_line,
1258 CalendarSpec *c = NULL;
1266 if (isempty(rvalue)) {
1267 /* Empty assignment resets list */
1268 timer_free_values(t);
1272 b = timer_base_from_string(lvalue);
1274 log_syntax(unit, LOG_ERR, filename, line, -b,
1275 "Failed to parse timer base, ignoring: %s", lvalue);
1279 if (b == TIMER_CALENDAR) {
1280 if (calendar_spec_from_string(rvalue, &c) < 0) {
1281 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1282 "Failed to parse calendar specification, ignoring: %s",
1287 id = CLOCK_REALTIME;
1289 if (parse_sec(rvalue, &u) < 0) {
1290 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1291 "Failed to parse timer value, ignoring: %s",
1296 id = CLOCK_MONOTONIC;
1299 v = new0(TimerValue, 1);
1306 v->calendar_spec = c;
1308 LIST_PREPEND(value, t->values, v);
1313 int config_parse_trigger_unit(
1315 const char *filename,
1317 const char *section,
1318 unsigned section_line,
1325 _cleanup_free_ char *p = NULL;
1335 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1336 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1337 "Multiple units to trigger specified, ignoring: %s", rvalue);
1341 r = unit_name_printf(u, rvalue, &p);
1343 log_syntax(unit, LOG_ERR, filename, line, -r,
1344 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1346 type = unit_name_to_type(p ?: rvalue);
1348 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1349 "Unit type not valid, ignoring: %s", rvalue);
1353 if (type == u->type) {
1354 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1355 "Trigger cannot be of same type, ignoring: %s", rvalue);
1359 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1361 log_syntax(unit, LOG_ERR, filename, line, -r,
1362 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1369 int config_parse_path_spec(const char *unit,
1370 const char *filename,
1372 const char *section,
1373 unsigned section_line,
1383 _cleanup_free_ char *k = NULL;
1391 if (isempty(rvalue)) {
1392 /* Empty assignment clears list */
1397 b = path_type_from_string(lvalue);
1399 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1400 "Failed to parse path type, ignoring: %s", lvalue);
1404 r = unit_full_printf(UNIT(p), rvalue, &k);
1410 log_syntax(unit, LOG_ERR, filename, line, -r,
1411 "Failed to resolve unit specifiers on %s. Ignoring.",
1415 if (!path_is_absolute(k)) {
1416 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1417 "Path is not absolute, ignoring: %s", k);
1421 s = new0(PathSpec, 1);
1426 s->path = path_kill_slashes(k);
1431 LIST_PREPEND(spec, p->specs, s);
1436 int config_parse_socket_service(const char *unit,
1437 const char *filename,
1439 const char *section,
1440 unsigned section_line,
1447 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1451 _cleanup_free_ char *p = NULL;
1458 r = unit_name_printf(UNIT(s), rvalue, &p);
1460 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1464 if (!endswith(p, ".service")) {
1465 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1469 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1471 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1475 unit_ref_set(&s->service, x);
1480 int config_parse_service_sockets(const char *unit,
1481 const char *filename,
1483 const char *section,
1484 unsigned section_line,
1501 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1502 _cleanup_free_ char *t = NULL, *k = NULL;
1508 r = unit_name_printf(UNIT(s), t, &k);
1510 log_syntax(unit, LOG_ERR, filename, line, -r,
1511 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1513 if (!endswith(k ?: t, ".socket")) {
1514 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1515 "Unit must be of type socket, ignoring: %s", k ?: t);
1519 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1521 log_syntax(unit, LOG_ERR, filename, line, -r,
1522 "Failed to add dependency on %s, ignoring: %s",
1523 k ?: t, strerror(-r));
1525 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1533 int config_parse_service_timeout(const char *unit,
1534 const char *filename,
1536 const char *section,
1537 unsigned section_line,
1544 Service *s = userdata;
1552 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1553 rvalue, data, userdata);
1557 if (streq(lvalue, "TimeoutSec")) {
1558 s->start_timeout_defined = true;
1559 s->timeout_stop_usec = s->timeout_start_usec;
1560 } else if (streq(lvalue, "TimeoutStartSec"))
1561 s->start_timeout_defined = true;
1566 int config_parse_busname_service(
1568 const char *filename,
1570 const char *section,
1571 unsigned section_line,
1578 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1582 _cleanup_free_ char *p = NULL;
1589 r = unit_name_printf(UNIT(n), rvalue, &p);
1591 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1595 if (!endswith(p, ".service")) {
1596 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1600 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1602 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1606 unit_ref_set(&n->service, x);
1611 int config_parse_bus_policy(
1613 const char *filename,
1615 const char *section,
1616 unsigned section_line,
1623 _cleanup_free_ BusNamePolicy *p = NULL;
1624 _cleanup_free_ char *id_str = NULL;
1625 BusName *busname = data;
1634 p = new0(BusNamePolicy, 1);
1638 if (streq(lvalue, "AllowUser"))
1639 p->type = BUSNAME_POLICY_TYPE_USER;
1640 else if (streq(lvalue, "AllowGroup"))
1641 p->type = BUSNAME_POLICY_TYPE_GROUP;
1642 else if (streq(lvalue, "AllowWorld"))
1643 p->type = BUSNAME_POLICY_TYPE_WORLD;
1645 assert_not_reached("Unknown lvalue");
1647 id_str = strdup(rvalue);
1651 if (p->type != BUSNAME_POLICY_TYPE_WORLD) {
1652 access_str = strchr(id_str, ' ');
1654 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy value '%s'", rvalue);
1661 if (p->type == BUSNAME_POLICY_TYPE_USER) {
1662 const char *user = id_str;
1664 r = get_user_creds(&user, &p->uid, NULL, NULL, NULL);
1666 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to parse uid from '%s'", id_str);
1670 const char *group = id_str;
1672 r = get_group_creds(&group, &p->gid);
1674 log_syntax(unit, LOG_ERR, filename, line, -errno, "Unable to parse gid from '%s'", id_str);
1679 access_str = id_str;
1682 p->access = busname_policy_access_from_string(access_str);
1683 if (p->access < 0) {
1684 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy access type '%s'", access_str);
1688 LIST_PREPEND(policy, busname->policy, p);
1694 int config_parse_unit_env_file(const char *unit,
1695 const char *filename,
1697 const char *section,
1698 unsigned section_line,
1707 _cleanup_free_ char *n = NULL;
1716 if (isempty(rvalue)) {
1717 /* Empty assignment frees the list */
1723 r = unit_full_printf(u, rvalue, &n);
1725 log_syntax(unit, LOG_ERR, filename, line, r,
1726 "Failed to resolve specifiers, ignoring: %s", rvalue);
1729 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1730 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1731 "Path '%s' is not absolute, ignoring.", s);
1735 r = strv_extend(env, s);
1742 int config_parse_environ(const char *unit,
1743 const char *filename,
1745 const char *section,
1746 unsigned section_line,
1754 char*** env = data, *w, *state;
1756 _cleanup_free_ char *k = NULL;
1764 if (isempty(rvalue)) {
1765 /* Empty assignment resets the list */
1772 r = unit_full_printf(u, rvalue, &k);
1774 log_syntax(unit, LOG_ERR, filename, line, -r,
1775 "Failed to resolve specifiers, ignoring: %s", rvalue);
1783 FOREACH_WORD_QUOTED(w, l, k, state) {
1784 _cleanup_free_ char *n;
1787 n = cunescape_length(w, l);
1791 if (!env_assignment_is_valid(n)) {
1792 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1793 "Invalid environment assignment, ignoring: %s", rvalue);
1797 x = strv_env_set(*env, n);
1808 int config_parse_ip_tos(const char *unit,
1809 const char *filename,
1811 const char *section,
1812 unsigned section_line,
1819 int *ip_tos = data, x;
1826 x = ip_tos_from_string(rvalue);
1828 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1829 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1837 int config_parse_unit_condition_path(const char *unit,
1838 const char *filename,
1840 const char *section,
1841 unsigned section_line,
1848 ConditionType cond = ltype;
1850 bool trigger, negate;
1852 _cleanup_free_ char *p = NULL;
1860 if (isempty(rvalue)) {
1861 /* Empty assignment resets the list */
1862 condition_free_list(u->conditions);
1863 u->conditions = NULL;
1867 trigger = rvalue[0] == '|';
1871 negate = rvalue[0] == '!';
1875 r = unit_full_printf(u, rvalue, &p);
1877 log_syntax(unit, LOG_ERR, filename, line, -r,
1878 "Failed to resolve specifiers, ignoring: %s", rvalue);
1885 if (!path_is_absolute(p)) {
1886 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1887 "Path in condition not absolute, ignoring: %s", p);
1891 c = condition_new(cond, p, trigger, negate);
1895 LIST_PREPEND(conditions, u->conditions, c);
1899 int config_parse_unit_condition_string(const char *unit,
1900 const char *filename,
1902 const char *section,
1903 unsigned section_line,
1910 ConditionType cond = ltype;
1912 bool trigger, negate;
1914 _cleanup_free_ char *s = NULL;
1922 if (isempty(rvalue)) {
1923 /* Empty assignment resets the list */
1924 condition_free_list(u->conditions);
1925 u->conditions = NULL;
1929 trigger = rvalue[0] == '|';
1933 negate = rvalue[0] == '!';
1937 r = unit_full_printf(u, rvalue, &s);
1939 log_syntax(unit, LOG_ERR, filename, line, -r,
1940 "Failed to resolve specifiers, ignoring: %s", rvalue);
1947 c = condition_new(cond, s, trigger, negate);
1951 LIST_PREPEND(conditions, u->conditions, c);
1955 int config_parse_unit_condition_null(const char *unit,
1956 const char *filename,
1958 const char *section,
1959 unsigned section_line,
1968 bool trigger, negate;
1976 if (isempty(rvalue)) {
1977 /* Empty assignment resets the list */
1978 condition_free_list(u->conditions);
1979 u->conditions = NULL;
1983 trigger = rvalue[0] == '|';
1987 negate = rvalue[0] == '!';
1991 b = parse_boolean(rvalue);
1993 log_syntax(unit, LOG_ERR, filename, line, -b,
1994 "Failed to parse boolean value in condition, ignoring: %s",
2002 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2006 LIST_PREPEND(conditions, u->conditions, c);
2010 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2011 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
2013 int config_parse_unit_requires_mounts_for(
2015 const char *filename,
2017 const char *section,
2018 unsigned section_line,
2035 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2037 _cleanup_free_ char *n;
2043 if (!utf8_is_valid(n)) {
2044 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2048 r = unit_require_mounts_for(u, n);
2050 log_syntax(unit, LOG_ERR, filename, line, r,
2051 "Failed to add required mount for, ignoring: %s", rvalue);
2059 int config_parse_documentation(const char *unit,
2060 const char *filename,
2062 const char *section,
2063 unsigned section_line,
2079 if (isempty(rvalue)) {
2080 /* Empty assignment resets the list */
2081 strv_free(u->documentation);
2082 u->documentation = NULL;
2086 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2087 rvalue, data, userdata);
2091 for (a = b = u->documentation; a && *a; a++) {
2093 if (is_valid_documentation_url(*a))
2096 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2097 "Invalid URL, ignoring: %s", *a);
2108 int config_parse_syscall_filter(
2110 const char *filename,
2112 const char *section,
2113 unsigned section_line,
2120 static const char default_syscalls[] =
2127 ExecContext *c = data;
2129 bool invert = false;
2139 if (isempty(rvalue)) {
2140 /* Empty assignment resets the list */
2141 set_free(c->syscall_filter);
2142 c->syscall_filter = NULL;
2143 c->syscall_whitelist = false;
2147 if (rvalue[0] == '~') {
2152 if (!c->syscall_filter) {
2153 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2154 if (!c->syscall_filter)
2158 /* Allow everything but the ones listed */
2159 c->syscall_whitelist = false;
2163 /* Allow nothing but the ones listed */
2164 c->syscall_whitelist = true;
2166 /* Accept default syscalls if we are on a whitelist */
2167 NULSTR_FOREACH(i, default_syscalls) {
2170 id = seccomp_syscall_resolve_name(i);
2174 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2183 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2184 _cleanup_free_ char *t = NULL;
2191 id = seccomp_syscall_resolve_name(t);
2193 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2197 /* If we previously wanted to forbid a syscall and now
2198 * we want to allow it, then remove it from the list
2200 if (!invert == c->syscall_whitelist) {
2201 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2207 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2210 /* Turn on NNP, but only if it wasn't configured explicitly
2211 * before, and only if we are in user mode. */
2212 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2213 c->no_new_privileges = true;
2218 int config_parse_syscall_archs(
2220 const char *filename,
2222 const char *section,
2223 unsigned section_line,
2235 if (isempty(rvalue)) {
2241 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2245 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2246 _cleanup_free_ char *t = NULL;
2253 r = seccomp_arch_from_string(t, &a);
2255 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2259 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2269 int config_parse_syscall_errno(
2271 const char *filename,
2273 const char *section,
2274 unsigned section_line,
2281 ExecContext *c = data;
2288 if (isempty(rvalue)) {
2289 /* Empty assignment resets to KILL */
2290 c->syscall_errno = 0;
2294 e = errno_from_name(rvalue);
2296 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2300 c->syscall_errno = e;
2304 int config_parse_address_families(
2306 const char *filename,
2308 const char *section,
2309 unsigned section_line,
2316 ExecContext *c = data;
2318 bool invert = false;
2328 if (isempty(rvalue)) {
2329 /* Empty assignment resets the list */
2330 set_free(c->address_families);
2331 c->address_families = NULL;
2332 c->address_families_whitelist = false;
2336 if (rvalue[0] == '~') {
2341 if (!c->address_families) {
2342 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2343 if (!c->address_families)
2346 c->address_families_whitelist = !invert;
2349 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2350 _cleanup_free_ char *t = NULL;
2357 af = af_from_name(t);
2359 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
2363 /* If we previously wanted to forbid an address family and now
2364 * we want to allow it, then remove it from the list
2366 if (!invert == c->address_families_whitelist) {
2367 r = set_put(c->address_families, INT_TO_PTR(af));
2373 set_remove(c->address_families, INT_TO_PTR(af));
2380 int config_parse_unit_slice(
2382 const char *filename,
2384 const char *section,
2385 unsigned section_line,
2392 _cleanup_free_ char *k = NULL;
2393 Unit *u = userdata, *slice;
2401 r = unit_name_printf(u, rvalue, &k);
2403 log_syntax(unit, LOG_ERR, filename, line, -r,
2404 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2411 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2413 log_syntax(unit, LOG_ERR, filename, line, -r,
2414 "Failed to load slice unit %s. Ignoring.", k);
2418 if (slice->type != UNIT_SLICE) {
2419 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2420 "Slice unit %s is not a slice. Ignoring.", k);
2424 unit_ref_set(&u->slice, slice);
2428 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2430 int config_parse_cpu_shares(
2432 const char *filename,
2434 const char *section,
2435 unsigned section_line,
2442 CGroupContext *c = data;
2450 if (isempty(rvalue)) {
2451 c->cpu_shares = 1024;
2455 r = safe_atolu(rvalue, &lu);
2456 if (r < 0 || lu <= 0) {
2457 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2458 "CPU shares '%s' invalid. Ignoring.", rvalue);
2466 int config_parse_memory_limit(
2468 const char *filename,
2470 const char *section,
2471 unsigned section_line,
2478 CGroupContext *c = data;
2482 if (isempty(rvalue)) {
2483 c->memory_limit = (uint64_t) -1;
2487 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2489 r = parse_size(rvalue, 1024, &bytes);
2491 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
2495 c->memory_limit = (uint64_t) bytes;
2499 int config_parse_device_allow(
2501 const char *filename,
2503 const char *section,
2504 unsigned section_line,
2511 _cleanup_free_ char *path = NULL;
2512 CGroupContext *c = data;
2513 CGroupDeviceAllow *a;
2517 if (isempty(rvalue)) {
2518 while (c->device_allow)
2519 cgroup_context_free_device_allow(c, c->device_allow);
2524 n = strcspn(rvalue, WHITESPACE);
2525 path = strndup(rvalue, n);
2529 if (!startswith(path, "/dev/") &&
2530 !startswith(path, "block-") &&
2531 !startswith(path, "char-")) {
2532 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2536 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2540 if (!in_charset(m, "rwm")) {
2541 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
2545 a = new0(CGroupDeviceAllow, 1);
2551 a->r = !!strchr(m, 'r');
2552 a->w = !!strchr(m, 'w');
2553 a->m = !!strchr(m, 'm');
2555 LIST_PREPEND(device_allow, c->device_allow, a);
2559 int config_parse_blockio_weight(
2561 const char *filename,
2563 const char *section,
2564 unsigned section_line,
2571 CGroupContext *c = data;
2579 if (isempty(rvalue)) {
2580 c->blockio_weight = 1000;
2584 r = safe_atolu(rvalue, &lu);
2585 if (r < 0 || lu < 10 || lu > 1000) {
2586 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2587 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2591 c->blockio_weight = lu;
2596 int config_parse_blockio_device_weight(
2598 const char *filename,
2600 const char *section,
2601 unsigned section_line,
2608 _cleanup_free_ char *path = NULL;
2609 CGroupBlockIODeviceWeight *w;
2610 CGroupContext *c = data;
2620 if (isempty(rvalue)) {
2621 while (c->blockio_device_weights)
2622 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2627 n = strcspn(rvalue, WHITESPACE);
2628 weight = rvalue + n;
2630 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2631 "Expected block device and device weight. Ignoring.");
2635 path = strndup(rvalue, n);
2639 if (!path_startswith(path, "/dev")) {
2640 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2641 "Invalid device node path '%s'. Ignoring.", path);
2645 weight += strspn(weight, WHITESPACE);
2646 r = safe_atolu(weight, &lu);
2647 if (r < 0 || lu < 10 || lu > 1000) {
2648 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2649 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2654 w = new0(CGroupBlockIODeviceWeight, 1);
2663 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2667 int config_parse_blockio_bandwidth(
2669 const char *filename,
2671 const char *section,
2672 unsigned section_line,
2679 _cleanup_free_ char *path = NULL;
2680 CGroupBlockIODeviceBandwidth *b;
2681 CGroupContext *c = data;
2682 const char *bandwidth;
2692 read = streq("BlockIOReadBandwidth", lvalue);
2694 if (isempty(rvalue)) {
2695 CGroupBlockIODeviceBandwidth *next;
2697 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2698 if (b->read == read)
2699 cgroup_context_free_blockio_device_bandwidth(c, b);
2704 n = strcspn(rvalue, WHITESPACE);
2705 bandwidth = rvalue + n;
2706 bandwidth += strspn(bandwidth, WHITESPACE);
2709 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2710 "Expected space separated pair of device node and bandwidth. Ignoring.");
2714 path = strndup(rvalue, n);
2718 if (!path_startswith(path, "/dev")) {
2719 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2720 "Invalid device node path '%s'. Ignoring.", path);
2724 r = parse_size(bandwidth, 1000, &bytes);
2725 if (r < 0 || bytes <= 0) {
2726 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2730 b = new0(CGroupBlockIODeviceBandwidth, 1);
2736 b->bandwidth = (uint64_t) bytes;
2739 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2744 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2746 int config_parse_job_mode_isolate(
2748 const char *filename,
2750 const char *section,
2751 unsigned section_line,
2765 r = parse_boolean(rvalue);
2767 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2771 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2775 int config_parse_personality(
2777 const char *filename,
2779 const char *section,
2780 unsigned section_line,
2787 unsigned long *personality = data, p;
2792 assert(personality);
2794 p = personality_from_string(rvalue);
2795 if (p == 0xffffffffUL) {
2796 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2797 "Failed to parse personality, ignoring: %s", rvalue);
2805 int config_parse_runtime_directory(
2807 const char *filename,
2809 const char *section,
2810 unsigned section_line,
2817 char***rt = data, *w, *state;
2826 if (isempty(rvalue)) {
2827 /* Empty assignment resets the list */
2833 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2834 _cleanup_free_ char *n;
2840 if (!filename_is_safe(n)) {
2841 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2845 r = strv_push(rt, n);
2855 int config_parse_set_status(
2857 const char *filename,
2859 const char *section,
2860 unsigned section_line,
2871 ExitStatusSet *status_set = data;
2878 if (isempty(rvalue)) {
2879 /* Empty assignment resets the list */
2881 set_free(status_set->signal);
2882 set_free(status_set->code);
2884 status_set->signal = status_set->code = NULL;
2888 FOREACH_WORD(w, l, rvalue, state) {
2889 _cleanup_free_ char *temp;
2892 temp = strndup(w, l);
2896 r = safe_atoi(temp, &val);
2898 val = signal_from_string_try_harder(temp);
2901 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
2905 r = set_put(status_set->signal, INT_TO_PTR(val));
2907 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2911 log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", w);
2915 if (val < 0 || val > 255)
2916 log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
2918 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
2922 r = set_put(status_set->code, INT_TO_PTR(val));
2924 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2934 int config_parse_namespace_path_strv(
2936 const char *filename,
2938 const char *section,
2939 unsigned section_line,
2946 char*** sv = data, *w, *state;
2955 if (isempty(rvalue)) {
2956 /* Empty assignment resets the list */
2962 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2963 _cleanup_free_ char *n;
2970 if (!utf8_is_valid(n)) {
2971 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2975 offset = n[0] == '-';
2976 if (!path_is_absolute(n + offset)) {
2977 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
2981 path_kill_slashes(n);
2983 r = strv_push(sv, n);
2993 int config_parse_no_new_priviliges(
2995 const char *filename,
2997 const char *section,
2998 unsigned section_line,
3005 ExecContext *c = data;
3013 k = parse_boolean(rvalue);
3015 log_syntax(unit, LOG_ERR, filename, line, -k, "Failed to parse boolean value, ignoring: %s", rvalue);
3019 c->no_new_privileges = !!k;
3020 c->no_new_privileges_set = true;
3025 #define FOLLOW_MAX 8
3027 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3038 /* This will update the filename pointer if the loaded file is
3039 * reached by a symlink. The old string will be freed. */
3042 char *target, *name;
3044 if (c++ >= FOLLOW_MAX)
3047 path_kill_slashes(*filename);
3049 /* Add the file name we are currently looking at to
3050 * the names of this unit, but only if it is a valid
3052 name = basename(*filename);
3054 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3056 id = set_get(names, name);
3062 r = set_consume(names, id);
3068 /* Try to open the file name, but don't if its a symlink */
3069 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3076 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3077 r = readlink_and_make_absolute(*filename, &target);
3085 f = fdopen(fd, "re");
3088 close_nointr_nofail(fd);
3097 static int merge_by_names(Unit **u, Set *names, const char *id) {
3105 /* Let's try to add in all symlink names we found */
3106 while ((k = set_steal_first(names))) {
3108 /* First try to merge in the other name into our
3110 r = unit_merge_by_name(*u, k);
3114 /* Hmm, we couldn't merge the other unit into
3115 * ours? Then let's try it the other way
3118 other = manager_get_unit((*u)->manager, k);
3122 r = unit_merge(other, *u);
3125 return merge_by_names(u, names, NULL);
3133 unit_choose_id(*u, id);
3141 static int load_from_path(Unit *u, const char *path) {
3143 _cleanup_set_free_free_ Set *symlink_names = NULL;
3144 _cleanup_fclose_ FILE *f = NULL;
3145 _cleanup_free_ char *filename = NULL;
3153 symlink_names = set_new(string_hash_func, string_compare_func);
3157 if (path_is_absolute(path)) {
3159 filename = strdup(path);
3163 r = open_follow(&filename, &f, symlink_names, &id);
3175 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3177 /* Instead of opening the path right away, we manually
3178 * follow all symlinks and add their name to our unit
3179 * name set while doing so */
3180 filename = path_make_absolute(path, *p);
3184 if (u->manager->unit_path_cache &&
3185 !set_get(u->manager->unit_path_cache, filename))
3188 r = open_follow(&filename, &f, symlink_names, &id);
3197 /* Empty the symlink names for the next run */
3198 set_clear_free(symlink_names);
3207 /* Hmm, no suitable file found? */
3211 r = merge_by_names(&merged, symlink_names, id);
3216 u->load_state = UNIT_MERGED;
3220 if (fstat(fileno(f), &st) < 0)
3223 if (null_or_empty(&st))
3224 u->load_state = UNIT_MASKED;
3226 u->load_state = UNIT_LOADED;
3228 /* Now, parse the file contents */
3229 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
3230 config_item_perf_lookup,
3231 (void*) load_fragment_gperf_lookup, false, true, u);
3236 free(u->fragment_path);
3237 u->fragment_path = filename;
3240 u->fragment_mtime = timespec_load(&st.st_mtim);
3242 if (u->source_path) {
3243 if (stat(u->source_path, &st) >= 0)
3244 u->source_mtime = timespec_load(&st.st_mtim);
3246 u->source_mtime = 0;
3252 int unit_load_fragment(Unit *u) {
3258 assert(u->load_state == UNIT_STUB);
3261 /* First, try to find the unit under its id. We always look
3262 * for unit files in the default directories, to make it easy
3263 * to override things by placing things in /etc/systemd/system */
3264 r = load_from_path(u, u->id);
3268 /* Try to find an alias we can load this with */
3269 if (u->load_state == UNIT_STUB)
3270 SET_FOREACH(t, u->names, i) {
3275 r = load_from_path(u, t);
3279 if (u->load_state != UNIT_STUB)
3283 /* And now, try looking for it under the suggested (originally linked) path */
3284 if (u->load_state == UNIT_STUB && u->fragment_path) {
3286 r = load_from_path(u, u->fragment_path);
3290 if (u->load_state == UNIT_STUB) {
3291 /* Hmm, this didn't work? Then let's get rid
3292 * of the fragment path stored for us, so that
3293 * we don't point to an invalid location. */
3294 free(u->fragment_path);
3295 u->fragment_path = NULL;
3299 /* Look for a template */
3300 if (u->load_state == UNIT_STUB && u->instance) {
3301 _cleanup_free_ char *k;
3303 k = unit_name_template(u->id);
3307 r = load_from_path(u, k);
3311 if (u->load_state == UNIT_STUB)
3312 SET_FOREACH(t, u->names, i) {
3313 _cleanup_free_ char *z = NULL;
3318 z = unit_name_template(t);
3322 r = load_from_path(u, z);
3326 if (u->load_state != UNIT_STUB)
3334 void unit_dump_config_items(FILE *f) {
3335 static const struct {
3336 const ConfigParserCallback callback;
3339 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3340 { config_parse_warn_compat, "NOTSUPPORTED" },
3342 { config_parse_int, "INTEGER" },
3343 { config_parse_unsigned, "UNSIGNED" },
3344 { config_parse_iec_size, "SIZE" },
3345 { config_parse_iec_off, "SIZE" },
3346 { config_parse_si_size, "SIZE" },
3347 { config_parse_bool, "BOOLEAN" },
3348 { config_parse_string, "STRING" },
3349 { config_parse_path, "PATH" },
3350 { config_parse_unit_path_printf, "PATH" },
3351 { config_parse_strv, "STRING [...]" },
3352 { config_parse_exec_nice, "NICE" },
3353 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3354 { config_parse_exec_io_class, "IOCLASS" },
3355 { config_parse_exec_io_priority, "IOPRIORITY" },
3356 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3357 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3358 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3359 { config_parse_mode, "MODE" },
3360 { config_parse_unit_env_file, "FILE" },
3361 { config_parse_output, "OUTPUT" },
3362 { config_parse_input, "INPUT" },
3363 { config_parse_log_facility, "FACILITY" },
3364 { config_parse_log_level, "LEVEL" },
3365 { config_parse_exec_capabilities, "CAPABILITIES" },
3366 { config_parse_exec_secure_bits, "SECUREBITS" },
3367 { config_parse_bounding_set, "BOUNDINGSET" },
3368 { config_parse_limit, "LIMIT" },
3369 { config_parse_unit_deps, "UNIT [...]" },
3370 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3371 { config_parse_service_type, "SERVICETYPE" },
3372 { config_parse_service_restart, "SERVICERESTART" },
3373 #ifdef HAVE_SYSV_COMPAT
3374 { config_parse_sysv_priority, "SYSVPRIORITY" },
3376 { config_parse_kill_mode, "KILLMODE" },
3377 { config_parse_kill_signal, "SIGNAL" },
3378 { config_parse_socket_listen, "SOCKET [...]" },
3379 { config_parse_socket_bind, "SOCKETBIND" },
3380 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3381 { config_parse_sec, "SECONDS" },
3382 { config_parse_nsec, "NANOSECONDS" },
3383 { config_parse_namespace_path_strv, "PATH [...]" },
3384 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3385 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3386 { config_parse_unit_string_printf, "STRING" },
3387 { config_parse_trigger_unit, "UNIT" },
3388 { config_parse_timer, "TIMER" },
3389 { config_parse_path_spec, "PATH" },
3390 { config_parse_notify_access, "ACCESS" },
3391 { config_parse_ip_tos, "TOS" },
3392 { config_parse_unit_condition_path, "CONDITION" },
3393 { config_parse_unit_condition_string, "CONDITION" },
3394 { config_parse_unit_condition_null, "CONDITION" },
3395 { config_parse_unit_slice, "SLICE" },
3396 { config_parse_documentation, "URL" },
3397 { config_parse_service_timeout, "SECONDS" },
3398 { config_parse_start_limit_action, "ACTION" },
3399 { config_parse_set_status, "STATUS" },
3400 { config_parse_service_sockets, "SOCKETS" },
3401 { config_parse_environ, "ENVIRON" },
3403 { config_parse_syscall_filter, "SYSCALLS" },
3404 { config_parse_syscall_archs, "ARCHS" },
3405 { config_parse_syscall_errno, "ERRNO" },
3406 { config_parse_address_families, "FAMILIES" },
3408 { config_parse_cpu_shares, "SHARES" },
3409 { config_parse_memory_limit, "LIMIT" },
3410 { config_parse_device_allow, "DEVICE" },
3411 { config_parse_device_policy, "POLICY" },
3412 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3413 { config_parse_blockio_weight, "WEIGHT" },
3414 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3415 { config_parse_long, "LONG" },
3416 { config_parse_socket_service, "SERVICE" },
3418 { config_parse_exec_selinux_context, "LABEL" },
3420 { config_parse_job_mode, "MODE" },
3421 { config_parse_job_mode_isolate, "BOOLEAN" },
3422 { config_parse_personality, "PERSONALITY" },
3425 const char *prev = NULL;
3430 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3431 const char *rvalue = "OTHER", *lvalue;
3435 const ConfigPerfItem *p;
3437 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3439 dot = strchr(i, '.');
3440 lvalue = dot ? dot + 1 : i;
3444 if (!prev || !strneq(prev, i, prefix_len+1)) {
3448 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3451 for (j = 0; j < ELEMENTSOF(table); j++)
3452 if (p->parse == table[j].callback) {
3453 rvalue = table[j].rvalue;
3457 fprintf(f, "%s=%s\n", lvalue, rvalue);