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"))
1134 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1139 c->mount_flags = flags;
1143 int config_parse_exec_selinux_context(
1145 const char *filename,
1147 const char *section,
1148 unsigned section_line,
1155 ExecContext *c = data;
1166 if (isempty(rvalue)) {
1167 free(c->selinux_context);
1168 c->selinux_context = NULL;
1169 c->selinux_context_ignore = false;
1173 if (rvalue[0] == '-') {
1179 r = unit_name_printf(u, rvalue, &k);
1181 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1185 free(c->selinux_context);
1186 c->selinux_context = k;
1187 c->selinux_context_ignore = ignore;
1192 int config_parse_exec_apparmor_profile(
1194 const char *filename,
1196 const char *section,
1197 unsigned section_line,
1204 ExecContext *c = data;
1215 if (isempty(rvalue)) {
1216 free(c->apparmor_profile);
1217 c->apparmor_profile = NULL;
1218 c->apparmor_profile_ignore = false;
1222 if (rvalue[0] == '-') {
1228 r = unit_name_printf(u, rvalue, &k);
1230 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1234 free(c->apparmor_profile);
1235 c->apparmor_profile = k;
1236 c->apparmor_profile_ignore = ignore;
1241 int config_parse_timer(const char *unit,
1242 const char *filename,
1244 const char *section,
1245 unsigned section_line,
1256 CalendarSpec *c = NULL;
1264 if (isempty(rvalue)) {
1265 /* Empty assignment resets list */
1266 timer_free_values(t);
1270 b = timer_base_from_string(lvalue);
1272 log_syntax(unit, LOG_ERR, filename, line, -b,
1273 "Failed to parse timer base, ignoring: %s", lvalue);
1277 if (b == TIMER_CALENDAR) {
1278 if (calendar_spec_from_string(rvalue, &c) < 0) {
1279 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1280 "Failed to parse calendar specification, ignoring: %s",
1285 id = CLOCK_REALTIME;
1287 if (parse_sec(rvalue, &u) < 0) {
1288 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1289 "Failed to parse timer value, ignoring: %s",
1294 id = CLOCK_MONOTONIC;
1297 v = new0(TimerValue, 1);
1304 v->calendar_spec = c;
1306 LIST_PREPEND(value, t->values, v);
1311 int config_parse_trigger_unit(
1313 const char *filename,
1315 const char *section,
1316 unsigned section_line,
1323 _cleanup_free_ char *p = NULL;
1333 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1334 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1335 "Multiple units to trigger specified, ignoring: %s", rvalue);
1339 r = unit_name_printf(u, rvalue, &p);
1341 log_syntax(unit, LOG_ERR, filename, line, -r,
1342 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1344 type = unit_name_to_type(p ?: rvalue);
1346 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1347 "Unit type not valid, ignoring: %s", rvalue);
1351 if (type == u->type) {
1352 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1353 "Trigger cannot be of same type, ignoring: %s", rvalue);
1357 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1359 log_syntax(unit, LOG_ERR, filename, line, -r,
1360 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1367 int config_parse_path_spec(const char *unit,
1368 const char *filename,
1370 const char *section,
1371 unsigned section_line,
1381 _cleanup_free_ char *k = NULL;
1389 if (isempty(rvalue)) {
1390 /* Empty assignment clears list */
1395 b = path_type_from_string(lvalue);
1397 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1398 "Failed to parse path type, ignoring: %s", lvalue);
1402 r = unit_full_printf(UNIT(p), rvalue, &k);
1408 log_syntax(unit, LOG_ERR, filename, line, -r,
1409 "Failed to resolve unit specifiers on %s. Ignoring.",
1413 if (!path_is_absolute(k)) {
1414 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1415 "Path is not absolute, ignoring: %s", k);
1419 s = new0(PathSpec, 1);
1424 s->path = path_kill_slashes(k);
1429 LIST_PREPEND(spec, p->specs, s);
1434 int config_parse_socket_service(const char *unit,
1435 const char *filename,
1437 const char *section,
1438 unsigned section_line,
1445 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1449 _cleanup_free_ char *p = NULL;
1456 r = unit_name_printf(UNIT(s), rvalue, &p);
1458 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1462 if (!endswith(p, ".service")) {
1463 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1467 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1469 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1473 unit_ref_set(&s->service, x);
1478 int config_parse_service_sockets(const char *unit,
1479 const char *filename,
1481 const char *section,
1482 unsigned section_line,
1499 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1500 _cleanup_free_ char *t = NULL, *k = NULL;
1506 r = unit_name_printf(UNIT(s), t, &k);
1508 log_syntax(unit, LOG_ERR, filename, line, -r,
1509 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1511 if (!endswith(k ?: t, ".socket")) {
1512 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1513 "Unit must be of type socket, ignoring: %s", k ?: t);
1517 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1519 log_syntax(unit, LOG_ERR, filename, line, -r,
1520 "Failed to add dependency on %s, ignoring: %s",
1521 k ?: t, strerror(-r));
1523 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1531 int config_parse_service_timeout(const char *unit,
1532 const char *filename,
1534 const char *section,
1535 unsigned section_line,
1542 Service *s = userdata;
1550 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1551 rvalue, data, userdata);
1555 if (streq(lvalue, "TimeoutSec")) {
1556 s->start_timeout_defined = true;
1557 s->timeout_stop_usec = s->timeout_start_usec;
1558 } else if (streq(lvalue, "TimeoutStartSec"))
1559 s->start_timeout_defined = true;
1564 int config_parse_busname_service(
1566 const char *filename,
1568 const char *section,
1569 unsigned section_line,
1576 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1580 _cleanup_free_ char *p = NULL;
1587 r = unit_name_printf(UNIT(n), rvalue, &p);
1589 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1593 if (!endswith(p, ".service")) {
1594 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1598 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1600 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1604 unit_ref_set(&n->service, x);
1609 int config_parse_bus_policy(
1611 const char *filename,
1613 const char *section,
1614 unsigned section_line,
1621 _cleanup_free_ BusNamePolicy *p = NULL;
1622 _cleanup_free_ char *id_str = NULL;
1623 BusName *busname = data;
1632 p = new0(BusNamePolicy, 1);
1636 if (streq(lvalue, "AllowUser"))
1637 p->type = BUSNAME_POLICY_TYPE_USER;
1638 else if (streq(lvalue, "AllowGroup"))
1639 p->type = BUSNAME_POLICY_TYPE_GROUP;
1640 else if (streq(lvalue, "AllowWorld"))
1641 p->type = BUSNAME_POLICY_TYPE_WORLD;
1643 assert_not_reached("Unknown lvalue");
1645 id_str = strdup(rvalue);
1649 if (p->type != BUSNAME_POLICY_TYPE_WORLD) {
1650 access_str = strchr(id_str, ' ');
1652 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy value '%s'", rvalue);
1659 if (p->type == BUSNAME_POLICY_TYPE_USER) {
1660 const char *user = id_str;
1662 r = get_user_creds(&user, &p->uid, NULL, NULL, NULL);
1664 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to parse uid from '%s'", id_str);
1668 const char *group = id_str;
1670 r = get_group_creds(&group, &p->gid);
1672 log_syntax(unit, LOG_ERR, filename, line, -errno, "Unable to parse gid from '%s'", id_str);
1677 access_str = id_str;
1680 p->access = busname_policy_access_from_string(access_str);
1681 if (p->access < 0) {
1682 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy access type '%s'", access_str);
1686 LIST_PREPEND(policy, busname->policy, p);
1692 int config_parse_unit_env_file(const char *unit,
1693 const char *filename,
1695 const char *section,
1696 unsigned section_line,
1705 _cleanup_free_ char *n = NULL;
1714 if (isempty(rvalue)) {
1715 /* Empty assignment frees the list */
1721 r = unit_full_printf(u, rvalue, &n);
1723 log_syntax(unit, LOG_ERR, filename, line, r,
1724 "Failed to resolve specifiers, ignoring: %s", rvalue);
1727 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1728 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1729 "Path '%s' is not absolute, ignoring.", s);
1733 r = strv_extend(env, s);
1740 int config_parse_environ(const char *unit,
1741 const char *filename,
1743 const char *section,
1744 unsigned section_line,
1752 char*** env = data, *w, *state;
1754 _cleanup_free_ char *k = NULL;
1762 if (isempty(rvalue)) {
1763 /* Empty assignment resets the list */
1770 r = unit_full_printf(u, rvalue, &k);
1772 log_syntax(unit, LOG_ERR, filename, line, -r,
1773 "Failed to resolve specifiers, ignoring: %s", rvalue);
1781 FOREACH_WORD_QUOTED(w, l, k, state) {
1782 _cleanup_free_ char *n;
1785 n = cunescape_length(w, l);
1789 if (!env_assignment_is_valid(n)) {
1790 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1791 "Invalid environment assignment, ignoring: %s", rvalue);
1795 x = strv_env_set(*env, n);
1806 int config_parse_ip_tos(const char *unit,
1807 const char *filename,
1809 const char *section,
1810 unsigned section_line,
1817 int *ip_tos = data, x;
1824 x = ip_tos_from_string(rvalue);
1826 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1827 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1835 int config_parse_unit_condition_path(const char *unit,
1836 const char *filename,
1838 const char *section,
1839 unsigned section_line,
1846 ConditionType cond = ltype;
1848 bool trigger, negate;
1850 _cleanup_free_ char *p = NULL;
1858 if (isempty(rvalue)) {
1859 /* Empty assignment resets the list */
1860 condition_free_list(u->conditions);
1861 u->conditions = NULL;
1865 trigger = rvalue[0] == '|';
1869 negate = rvalue[0] == '!';
1873 r = unit_full_printf(u, rvalue, &p);
1875 log_syntax(unit, LOG_ERR, filename, line, -r,
1876 "Failed to resolve specifiers, ignoring: %s", rvalue);
1883 if (!path_is_absolute(p)) {
1884 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1885 "Path in condition not absolute, ignoring: %s", p);
1889 c = condition_new(cond, p, trigger, negate);
1893 LIST_PREPEND(conditions, u->conditions, c);
1897 int config_parse_unit_condition_string(const char *unit,
1898 const char *filename,
1900 const char *section,
1901 unsigned section_line,
1908 ConditionType cond = ltype;
1910 bool trigger, negate;
1912 _cleanup_free_ char *s = NULL;
1920 if (isempty(rvalue)) {
1921 /* Empty assignment resets the list */
1922 condition_free_list(u->conditions);
1923 u->conditions = NULL;
1927 trigger = rvalue[0] == '|';
1931 negate = rvalue[0] == '!';
1935 r = unit_full_printf(u, rvalue, &s);
1937 log_syntax(unit, LOG_ERR, filename, line, -r,
1938 "Failed to resolve specifiers, ignoring: %s", rvalue);
1945 c = condition_new(cond, s, trigger, negate);
1949 LIST_PREPEND(conditions, u->conditions, c);
1953 int config_parse_unit_condition_null(const char *unit,
1954 const char *filename,
1956 const char *section,
1957 unsigned section_line,
1966 bool trigger, negate;
1974 if (isempty(rvalue)) {
1975 /* Empty assignment resets the list */
1976 condition_free_list(u->conditions);
1977 u->conditions = NULL;
1981 trigger = rvalue[0] == '|';
1985 negate = rvalue[0] == '!';
1989 b = parse_boolean(rvalue);
1991 log_syntax(unit, LOG_ERR, filename, line, -b,
1992 "Failed to parse boolean value in condition, ignoring: %s",
2000 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2004 LIST_PREPEND(conditions, u->conditions, c);
2008 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2009 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
2011 int config_parse_unit_requires_mounts_for(
2013 const char *filename,
2015 const char *section,
2016 unsigned section_line,
2033 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2035 _cleanup_free_ char *n;
2041 if (!utf8_is_valid(n)) {
2042 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2046 r = unit_require_mounts_for(u, n);
2048 log_syntax(unit, LOG_ERR, filename, line, r,
2049 "Failed to add required mount for, ignoring: %s", rvalue);
2057 int config_parse_documentation(const char *unit,
2058 const char *filename,
2060 const char *section,
2061 unsigned section_line,
2077 if (isempty(rvalue)) {
2078 /* Empty assignment resets the list */
2079 strv_free(u->documentation);
2080 u->documentation = NULL;
2084 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2085 rvalue, data, userdata);
2089 for (a = b = u->documentation; a && *a; a++) {
2091 if (is_valid_documentation_url(*a))
2094 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2095 "Invalid URL, ignoring: %s", *a);
2106 int config_parse_syscall_filter(
2108 const char *filename,
2110 const char *section,
2111 unsigned section_line,
2118 static const char default_syscalls[] =
2125 ExecContext *c = data;
2127 bool invert = false;
2137 if (isempty(rvalue)) {
2138 /* Empty assignment resets the list */
2139 set_free(c->syscall_filter);
2140 c->syscall_filter = NULL;
2141 c->syscall_whitelist = false;
2145 if (rvalue[0] == '~') {
2150 if (!c->syscall_filter) {
2151 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2152 if (!c->syscall_filter)
2156 /* Allow everything but the ones listed */
2157 c->syscall_whitelist = false;
2161 /* Allow nothing but the ones listed */
2162 c->syscall_whitelist = true;
2164 /* Accept default syscalls if we are on a whitelist */
2165 NULSTR_FOREACH(i, default_syscalls) {
2168 id = seccomp_syscall_resolve_name(i);
2172 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2181 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2182 _cleanup_free_ char *t = NULL;
2189 id = seccomp_syscall_resolve_name(t);
2191 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2195 /* If we previously wanted to forbid a syscall and now
2196 * we want to allow it, then remove it from the list
2198 if (!invert == c->syscall_whitelist) {
2199 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2205 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2208 /* Turn on NNP, but only if it wasn't configured explicitly
2209 * before, and only if we are in user mode. */
2210 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2211 c->no_new_privileges = true;
2216 int config_parse_syscall_archs(
2218 const char *filename,
2220 const char *section,
2221 unsigned section_line,
2233 if (isempty(rvalue)) {
2239 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2243 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2244 _cleanup_free_ char *t = NULL;
2251 r = seccomp_arch_from_string(t, &a);
2253 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2257 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2267 int config_parse_syscall_errno(
2269 const char *filename,
2271 const char *section,
2272 unsigned section_line,
2279 ExecContext *c = data;
2286 if (isempty(rvalue)) {
2287 /* Empty assignment resets to KILL */
2288 c->syscall_errno = 0;
2292 e = errno_from_name(rvalue);
2294 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2298 c->syscall_errno = e;
2302 int config_parse_address_families(
2304 const char *filename,
2306 const char *section,
2307 unsigned section_line,
2314 ExecContext *c = data;
2316 bool invert = false;
2326 if (isempty(rvalue)) {
2327 /* Empty assignment resets the list */
2328 set_free(c->address_families);
2329 c->address_families = NULL;
2330 c->address_families_whitelist = false;
2334 if (rvalue[0] == '~') {
2339 if (!c->address_families) {
2340 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2341 if (!c->address_families)
2344 c->address_families_whitelist = !invert;
2347 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2348 _cleanup_free_ char *t = NULL;
2355 af = af_from_name(t);
2357 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
2361 /* If we previously wanted to forbid an address family and now
2362 * we want to allow it, then remove it from the list
2364 if (!invert == c->address_families_whitelist) {
2365 r = set_put(c->address_families, INT_TO_PTR(af));
2371 set_remove(c->address_families, INT_TO_PTR(af));
2378 int config_parse_unit_slice(
2380 const char *filename,
2382 const char *section,
2383 unsigned section_line,
2390 _cleanup_free_ char *k = NULL;
2391 Unit *u = userdata, *slice;
2399 r = unit_name_printf(u, rvalue, &k);
2401 log_syntax(unit, LOG_ERR, filename, line, -r,
2402 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2409 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2411 log_syntax(unit, LOG_ERR, filename, line, -r,
2412 "Failed to load slice unit %s. Ignoring.", k);
2416 if (slice->type != UNIT_SLICE) {
2417 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2418 "Slice unit %s is not a slice. Ignoring.", k);
2422 unit_ref_set(&u->slice, slice);
2426 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2428 int config_parse_cpu_shares(
2430 const char *filename,
2432 const char *section,
2433 unsigned section_line,
2440 CGroupContext *c = data;
2448 if (isempty(rvalue)) {
2449 c->cpu_shares = 1024;
2453 r = safe_atolu(rvalue, &lu);
2454 if (r < 0 || lu <= 0) {
2455 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2456 "CPU shares '%s' invalid. Ignoring.", rvalue);
2464 int config_parse_memory_limit(
2466 const char *filename,
2468 const char *section,
2469 unsigned section_line,
2476 CGroupContext *c = data;
2480 if (isempty(rvalue)) {
2481 c->memory_limit = (uint64_t) -1;
2485 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2487 r = parse_size(rvalue, 1024, &bytes);
2489 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
2493 c->memory_limit = (uint64_t) bytes;
2497 int config_parse_device_allow(
2499 const char *filename,
2501 const char *section,
2502 unsigned section_line,
2509 _cleanup_free_ char *path = NULL;
2510 CGroupContext *c = data;
2511 CGroupDeviceAllow *a;
2515 if (isempty(rvalue)) {
2516 while (c->device_allow)
2517 cgroup_context_free_device_allow(c, c->device_allow);
2522 n = strcspn(rvalue, WHITESPACE);
2523 path = strndup(rvalue, n);
2527 if (!startswith(path, "/dev/") &&
2528 !startswith(path, "block-") &&
2529 !startswith(path, "char-")) {
2530 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2534 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2538 if (!in_charset(m, "rwm")) {
2539 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
2543 a = new0(CGroupDeviceAllow, 1);
2549 a->r = !!strchr(m, 'r');
2550 a->w = !!strchr(m, 'w');
2551 a->m = !!strchr(m, 'm');
2553 LIST_PREPEND(device_allow, c->device_allow, a);
2557 int config_parse_blockio_weight(
2559 const char *filename,
2561 const char *section,
2562 unsigned section_line,
2569 CGroupContext *c = data;
2577 if (isempty(rvalue)) {
2578 c->blockio_weight = 1000;
2582 r = safe_atolu(rvalue, &lu);
2583 if (r < 0 || lu < 10 || lu > 1000) {
2584 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2585 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2589 c->blockio_weight = lu;
2594 int config_parse_blockio_device_weight(
2596 const char *filename,
2598 const char *section,
2599 unsigned section_line,
2606 _cleanup_free_ char *path = NULL;
2607 CGroupBlockIODeviceWeight *w;
2608 CGroupContext *c = data;
2618 if (isempty(rvalue)) {
2619 while (c->blockio_device_weights)
2620 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2625 n = strcspn(rvalue, WHITESPACE);
2626 weight = rvalue + n;
2628 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2629 "Expected block device and device weight. Ignoring.");
2633 path = strndup(rvalue, n);
2637 if (!path_startswith(path, "/dev")) {
2638 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2639 "Invalid device node path '%s'. Ignoring.", path);
2643 weight += strspn(weight, WHITESPACE);
2644 r = safe_atolu(weight, &lu);
2645 if (r < 0 || lu < 10 || lu > 1000) {
2646 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2647 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2652 w = new0(CGroupBlockIODeviceWeight, 1);
2661 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2665 int config_parse_blockio_bandwidth(
2667 const char *filename,
2669 const char *section,
2670 unsigned section_line,
2677 _cleanup_free_ char *path = NULL;
2678 CGroupBlockIODeviceBandwidth *b;
2679 CGroupContext *c = data;
2680 const char *bandwidth;
2690 read = streq("BlockIOReadBandwidth", lvalue);
2692 if (isempty(rvalue)) {
2693 CGroupBlockIODeviceBandwidth *next;
2695 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2696 if (b->read == read)
2697 cgroup_context_free_blockio_device_bandwidth(c, b);
2702 n = strcspn(rvalue, WHITESPACE);
2703 bandwidth = rvalue + n;
2704 bandwidth += strspn(bandwidth, WHITESPACE);
2707 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2708 "Expected space separated pair of device node and bandwidth. Ignoring.");
2712 path = strndup(rvalue, n);
2716 if (!path_startswith(path, "/dev")) {
2717 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2718 "Invalid device node path '%s'. Ignoring.", path);
2722 r = parse_size(bandwidth, 1000, &bytes);
2723 if (r < 0 || bytes <= 0) {
2724 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2728 b = new0(CGroupBlockIODeviceBandwidth, 1);
2734 b->bandwidth = (uint64_t) bytes;
2737 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2742 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2744 int config_parse_job_mode_isolate(
2746 const char *filename,
2748 const char *section,
2749 unsigned section_line,
2763 r = parse_boolean(rvalue);
2765 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2769 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2773 int config_parse_personality(
2775 const char *filename,
2777 const char *section,
2778 unsigned section_line,
2785 unsigned long *personality = data, p;
2790 assert(personality);
2792 p = personality_from_string(rvalue);
2793 if (p == 0xffffffffUL) {
2794 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2795 "Failed to parse personality, ignoring: %s", rvalue);
2803 int config_parse_runtime_directory(
2805 const char *filename,
2807 const char *section,
2808 unsigned section_line,
2815 char***rt = data, *w, *state;
2824 if (isempty(rvalue)) {
2825 /* Empty assignment resets the list */
2831 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2832 _cleanup_free_ char *n;
2838 if (!filename_is_safe(n)) {
2839 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2843 r = strv_push(rt, n);
2853 int config_parse_set_status(
2855 const char *filename,
2857 const char *section,
2858 unsigned section_line,
2869 ExitStatusSet *status_set = data;
2876 if (isempty(rvalue)) {
2877 /* Empty assignment resets the list */
2879 set_free(status_set->signal);
2880 set_free(status_set->code);
2882 status_set->signal = status_set->code = NULL;
2886 FOREACH_WORD(w, l, rvalue, state) {
2887 _cleanup_free_ char *temp;
2890 temp = strndup(w, l);
2894 r = safe_atoi(temp, &val);
2896 val = signal_from_string_try_harder(temp);
2899 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
2903 r = set_put(status_set->signal, INT_TO_PTR(val));
2905 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2909 log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", w);
2913 if (val < 0 || val > 255)
2914 log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
2916 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
2920 r = set_put(status_set->code, INT_TO_PTR(val));
2922 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2932 int config_parse_namespace_path_strv(
2934 const char *filename,
2936 const char *section,
2937 unsigned section_line,
2944 char*** sv = data, *w, *state;
2953 if (isempty(rvalue)) {
2954 /* Empty assignment resets the list */
2960 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2961 _cleanup_free_ char *n;
2968 if (!utf8_is_valid(n)) {
2969 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2973 offset = n[0] == '-';
2974 if (!path_is_absolute(n + offset)) {
2975 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
2979 path_kill_slashes(n);
2981 r = strv_push(sv, n);
2991 int config_parse_no_new_priviliges(
2993 const char *filename,
2995 const char *section,
2996 unsigned section_line,
3003 ExecContext *c = data;
3011 k = parse_boolean(rvalue);
3013 log_syntax(unit, LOG_ERR, filename, line, -k, "Failed to parse boolean value, ignoring: %s", rvalue);
3017 c->no_new_privileges = !!k;
3018 c->no_new_privileges_set = true;
3023 #define FOLLOW_MAX 8
3025 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3036 /* This will update the filename pointer if the loaded file is
3037 * reached by a symlink. The old string will be freed. */
3040 char *target, *name;
3042 if (c++ >= FOLLOW_MAX)
3045 path_kill_slashes(*filename);
3047 /* Add the file name we are currently looking at to
3048 * the names of this unit, but only if it is a valid
3050 name = basename(*filename);
3052 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3054 id = set_get(names, name);
3060 r = set_consume(names, id);
3066 /* Try to open the file name, but don't if its a symlink */
3067 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3074 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3075 r = readlink_and_make_absolute(*filename, &target);
3083 f = fdopen(fd, "re");
3095 static int merge_by_names(Unit **u, Set *names, const char *id) {
3103 /* Let's try to add in all symlink names we found */
3104 while ((k = set_steal_first(names))) {
3106 /* First try to merge in the other name into our
3108 r = unit_merge_by_name(*u, k);
3112 /* Hmm, we couldn't merge the other unit into
3113 * ours? Then let's try it the other way
3116 other = manager_get_unit((*u)->manager, k);
3120 r = unit_merge(other, *u);
3123 return merge_by_names(u, names, NULL);
3131 unit_choose_id(*u, id);
3139 static int load_from_path(Unit *u, const char *path) {
3141 _cleanup_set_free_free_ Set *symlink_names = NULL;
3142 _cleanup_fclose_ FILE *f = NULL;
3143 _cleanup_free_ char *filename = NULL;
3151 symlink_names = set_new(string_hash_func, string_compare_func);
3155 if (path_is_absolute(path)) {
3157 filename = strdup(path);
3161 r = open_follow(&filename, &f, symlink_names, &id);
3173 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3175 /* Instead of opening the path right away, we manually
3176 * follow all symlinks and add their name to our unit
3177 * name set while doing so */
3178 filename = path_make_absolute(path, *p);
3182 if (u->manager->unit_path_cache &&
3183 !set_get(u->manager->unit_path_cache, filename))
3186 r = open_follow(&filename, &f, symlink_names, &id);
3195 /* Empty the symlink names for the next run */
3196 set_clear_free(symlink_names);
3205 /* Hmm, no suitable file found? */
3209 r = merge_by_names(&merged, symlink_names, id);
3214 u->load_state = UNIT_MERGED;
3218 if (fstat(fileno(f), &st) < 0)
3221 if (null_or_empty(&st))
3222 u->load_state = UNIT_MASKED;
3224 u->load_state = UNIT_LOADED;
3226 /* Now, parse the file contents */
3227 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
3228 config_item_perf_lookup,
3229 (void*) load_fragment_gperf_lookup, false, true, u);
3234 free(u->fragment_path);
3235 u->fragment_path = filename;
3238 u->fragment_mtime = timespec_load(&st.st_mtim);
3240 if (u->source_path) {
3241 if (stat(u->source_path, &st) >= 0)
3242 u->source_mtime = timespec_load(&st.st_mtim);
3244 u->source_mtime = 0;
3250 int unit_load_fragment(Unit *u) {
3256 assert(u->load_state == UNIT_STUB);
3259 /* First, try to find the unit under its id. We always look
3260 * for unit files in the default directories, to make it easy
3261 * to override things by placing things in /etc/systemd/system */
3262 r = load_from_path(u, u->id);
3266 /* Try to find an alias we can load this with */
3267 if (u->load_state == UNIT_STUB)
3268 SET_FOREACH(t, u->names, i) {
3273 r = load_from_path(u, t);
3277 if (u->load_state != UNIT_STUB)
3281 /* And now, try looking for it under the suggested (originally linked) path */
3282 if (u->load_state == UNIT_STUB && u->fragment_path) {
3284 r = load_from_path(u, u->fragment_path);
3288 if (u->load_state == UNIT_STUB) {
3289 /* Hmm, this didn't work? Then let's get rid
3290 * of the fragment path stored for us, so that
3291 * we don't point to an invalid location. */
3292 free(u->fragment_path);
3293 u->fragment_path = NULL;
3297 /* Look for a template */
3298 if (u->load_state == UNIT_STUB && u->instance) {
3299 _cleanup_free_ char *k;
3301 k = unit_name_template(u->id);
3305 r = load_from_path(u, k);
3309 if (u->load_state == UNIT_STUB)
3310 SET_FOREACH(t, u->names, i) {
3311 _cleanup_free_ char *z = NULL;
3316 z = unit_name_template(t);
3320 r = load_from_path(u, z);
3324 if (u->load_state != UNIT_STUB)
3332 void unit_dump_config_items(FILE *f) {
3333 static const struct {
3334 const ConfigParserCallback callback;
3337 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3338 { config_parse_warn_compat, "NOTSUPPORTED" },
3340 { config_parse_int, "INTEGER" },
3341 { config_parse_unsigned, "UNSIGNED" },
3342 { config_parse_iec_size, "SIZE" },
3343 { config_parse_iec_off, "SIZE" },
3344 { config_parse_si_size, "SIZE" },
3345 { config_parse_bool, "BOOLEAN" },
3346 { config_parse_string, "STRING" },
3347 { config_parse_path, "PATH" },
3348 { config_parse_unit_path_printf, "PATH" },
3349 { config_parse_strv, "STRING [...]" },
3350 { config_parse_exec_nice, "NICE" },
3351 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3352 { config_parse_exec_io_class, "IOCLASS" },
3353 { config_parse_exec_io_priority, "IOPRIORITY" },
3354 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3355 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3356 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3357 { config_parse_mode, "MODE" },
3358 { config_parse_unit_env_file, "FILE" },
3359 { config_parse_output, "OUTPUT" },
3360 { config_parse_input, "INPUT" },
3361 { config_parse_log_facility, "FACILITY" },
3362 { config_parse_log_level, "LEVEL" },
3363 { config_parse_exec_capabilities, "CAPABILITIES" },
3364 { config_parse_exec_secure_bits, "SECUREBITS" },
3365 { config_parse_bounding_set, "BOUNDINGSET" },
3366 { config_parse_limit, "LIMIT" },
3367 { config_parse_unit_deps, "UNIT [...]" },
3368 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3369 { config_parse_service_type, "SERVICETYPE" },
3370 { config_parse_service_restart, "SERVICERESTART" },
3371 #ifdef HAVE_SYSV_COMPAT
3372 { config_parse_sysv_priority, "SYSVPRIORITY" },
3374 { config_parse_kill_mode, "KILLMODE" },
3375 { config_parse_kill_signal, "SIGNAL" },
3376 { config_parse_socket_listen, "SOCKET [...]" },
3377 { config_parse_socket_bind, "SOCKETBIND" },
3378 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3379 { config_parse_sec, "SECONDS" },
3380 { config_parse_nsec, "NANOSECONDS" },
3381 { config_parse_namespace_path_strv, "PATH [...]" },
3382 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3383 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3384 { config_parse_unit_string_printf, "STRING" },
3385 { config_parse_trigger_unit, "UNIT" },
3386 { config_parse_timer, "TIMER" },
3387 { config_parse_path_spec, "PATH" },
3388 { config_parse_notify_access, "ACCESS" },
3389 { config_parse_ip_tos, "TOS" },
3390 { config_parse_unit_condition_path, "CONDITION" },
3391 { config_parse_unit_condition_string, "CONDITION" },
3392 { config_parse_unit_condition_null, "CONDITION" },
3393 { config_parse_unit_slice, "SLICE" },
3394 { config_parse_documentation, "URL" },
3395 { config_parse_service_timeout, "SECONDS" },
3396 { config_parse_start_limit_action, "ACTION" },
3397 { config_parse_set_status, "STATUS" },
3398 { config_parse_service_sockets, "SOCKETS" },
3399 { config_parse_environ, "ENVIRON" },
3401 { config_parse_syscall_filter, "SYSCALLS" },
3402 { config_parse_syscall_archs, "ARCHS" },
3403 { config_parse_syscall_errno, "ERRNO" },
3404 { config_parse_address_families, "FAMILIES" },
3406 { config_parse_cpu_shares, "SHARES" },
3407 { config_parse_memory_limit, "LIMIT" },
3408 { config_parse_device_allow, "DEVICE" },
3409 { config_parse_device_policy, "POLICY" },
3410 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3411 { config_parse_blockio_weight, "WEIGHT" },
3412 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3413 { config_parse_long, "LONG" },
3414 { config_parse_socket_service, "SERVICE" },
3416 { config_parse_exec_selinux_context, "LABEL" },
3418 { config_parse_job_mode, "MODE" },
3419 { config_parse_job_mode_isolate, "BOOLEAN" },
3420 { config_parse_personality, "PERSONALITY" },
3423 const char *prev = NULL;
3428 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3429 const char *rvalue = "OTHER", *lvalue;
3433 const ConfigPerfItem *p;
3435 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3437 dot = strchr(i, '.');
3438 lvalue = dot ? dot + 1 : i;
3442 if (!prev || !strneq(prev, i, prefix_len+1)) {
3446 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3449 for (j = 0; j < ELEMENTSOF(table); j++)
3450 if (p->parse == table[j].callback) {
3451 rvalue = table[j].rvalue;
3455 fprintf(f, "%s=%s\n", lvalue, rvalue);