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_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;
1263 if (isempty(rvalue)) {
1264 /* Empty assignment resets list */
1265 timer_free_values(t);
1269 b = timer_base_from_string(lvalue);
1271 log_syntax(unit, LOG_ERR, filename, line, -b,
1272 "Failed to parse timer base, ignoring: %s", lvalue);
1276 if (b == TIMER_CALENDAR) {
1277 if (calendar_spec_from_string(rvalue, &c) < 0) {
1278 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1279 "Failed to parse calendar specification, ignoring: %s",
1284 if (parse_sec(rvalue, &u) < 0) {
1285 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1286 "Failed to parse timer value, ignoring: %s",
1292 v = new0(TimerValue, 1);
1298 v->calendar_spec = c;
1300 LIST_PREPEND(value, t->values, v);
1305 int config_parse_trigger_unit(
1307 const char *filename,
1309 const char *section,
1310 unsigned section_line,
1317 _cleanup_free_ char *p = NULL;
1327 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1328 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1329 "Multiple units to trigger specified, ignoring: %s", rvalue);
1333 r = unit_name_printf(u, rvalue, &p);
1335 log_syntax(unit, LOG_ERR, filename, line, -r,
1336 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1338 type = unit_name_to_type(p ?: rvalue);
1340 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1341 "Unit type not valid, ignoring: %s", rvalue);
1345 if (type == u->type) {
1346 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1347 "Trigger cannot be of same type, ignoring: %s", rvalue);
1351 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1353 log_syntax(unit, LOG_ERR, filename, line, -r,
1354 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1361 int config_parse_path_spec(const char *unit,
1362 const char *filename,
1364 const char *section,
1365 unsigned section_line,
1375 _cleanup_free_ char *k = NULL;
1383 if (isempty(rvalue)) {
1384 /* Empty assignment clears list */
1389 b = path_type_from_string(lvalue);
1391 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1392 "Failed to parse path type, ignoring: %s", lvalue);
1396 r = unit_full_printf(UNIT(p), rvalue, &k);
1402 log_syntax(unit, LOG_ERR, filename, line, -r,
1403 "Failed to resolve unit specifiers on %s. Ignoring.",
1407 if (!path_is_absolute(k)) {
1408 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1409 "Path is not absolute, ignoring: %s", k);
1413 s = new0(PathSpec, 1);
1418 s->path = path_kill_slashes(k);
1423 LIST_PREPEND(spec, p->specs, s);
1428 int config_parse_socket_service(const char *unit,
1429 const char *filename,
1431 const char *section,
1432 unsigned section_line,
1439 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1443 _cleanup_free_ char *p = NULL;
1450 r = unit_name_printf(UNIT(s), rvalue, &p);
1452 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1456 if (!endswith(p, ".service")) {
1457 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1461 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1463 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1467 unit_ref_set(&s->service, x);
1472 int config_parse_service_sockets(const char *unit,
1473 const char *filename,
1475 const char *section,
1476 unsigned section_line,
1493 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1494 _cleanup_free_ char *t = NULL, *k = NULL;
1500 r = unit_name_printf(UNIT(s), t, &k);
1502 log_syntax(unit, LOG_ERR, filename, line, -r,
1503 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1505 if (!endswith(k ?: t, ".socket")) {
1506 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1507 "Unit must be of type socket, ignoring: %s", k ?: t);
1511 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1513 log_syntax(unit, LOG_ERR, filename, line, -r,
1514 "Failed to add dependency on %s, ignoring: %s",
1515 k ?: t, strerror(-r));
1517 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1525 int config_parse_service_timeout(const char *unit,
1526 const char *filename,
1528 const char *section,
1529 unsigned section_line,
1536 Service *s = userdata;
1544 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1545 rvalue, data, userdata);
1549 if (streq(lvalue, "TimeoutSec")) {
1550 s->start_timeout_defined = true;
1551 s->timeout_stop_usec = s->timeout_start_usec;
1552 } else if (streq(lvalue, "TimeoutStartSec"))
1553 s->start_timeout_defined = true;
1558 int config_parse_busname_service(
1560 const char *filename,
1562 const char *section,
1563 unsigned section_line,
1570 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1574 _cleanup_free_ char *p = NULL;
1581 r = unit_name_printf(UNIT(n), rvalue, &p);
1583 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1587 if (!endswith(p, ".service")) {
1588 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1592 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1594 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1598 unit_ref_set(&n->service, x);
1603 int config_parse_bus_policy(
1605 const char *filename,
1607 const char *section,
1608 unsigned section_line,
1615 _cleanup_free_ BusNamePolicy *p = NULL;
1616 _cleanup_free_ char *id_str = NULL;
1617 BusName *busname = data;
1626 p = new0(BusNamePolicy, 1);
1630 if (streq(lvalue, "AllowUser"))
1631 p->type = BUSNAME_POLICY_TYPE_USER;
1632 else if (streq(lvalue, "AllowGroup"))
1633 p->type = BUSNAME_POLICY_TYPE_GROUP;
1634 else if (streq(lvalue, "AllowWorld"))
1635 p->type = BUSNAME_POLICY_TYPE_WORLD;
1637 assert_not_reached("Unknown lvalue");
1639 id_str = strdup(rvalue);
1643 if (p->type != BUSNAME_POLICY_TYPE_WORLD) {
1644 access_str = strchr(id_str, ' ');
1646 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy value '%s'", rvalue);
1653 if (p->type == BUSNAME_POLICY_TYPE_USER) {
1654 const char *user = id_str;
1656 r = get_user_creds(&user, &p->uid, NULL, NULL, NULL);
1658 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to parse uid from '%s'", id_str);
1662 const char *group = id_str;
1664 r = get_group_creds(&group, &p->gid);
1666 log_syntax(unit, LOG_ERR, filename, line, -errno, "Unable to parse gid from '%s'", id_str);
1671 access_str = id_str;
1674 p->access = busname_policy_access_from_string(access_str);
1675 if (p->access < 0) {
1676 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy access type '%s'", access_str);
1680 LIST_PREPEND(policy, busname->policy, p);
1686 int config_parse_unit_env_file(const char *unit,
1687 const char *filename,
1689 const char *section,
1690 unsigned section_line,
1699 _cleanup_free_ char *n = NULL;
1708 if (isempty(rvalue)) {
1709 /* Empty assignment frees the list */
1715 r = unit_full_printf(u, rvalue, &n);
1717 log_syntax(unit, LOG_ERR, filename, line, r,
1718 "Failed to resolve specifiers, ignoring: %s", rvalue);
1721 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1722 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1723 "Path '%s' is not absolute, ignoring.", s);
1727 r = strv_extend(env, s);
1734 int config_parse_environ(const char *unit,
1735 const char *filename,
1737 const char *section,
1738 unsigned section_line,
1746 char*** env = data, *w, *state;
1748 _cleanup_free_ char *k = NULL;
1756 if (isempty(rvalue)) {
1757 /* Empty assignment resets the list */
1764 r = unit_full_printf(u, rvalue, &k);
1766 log_syntax(unit, LOG_ERR, filename, line, -r,
1767 "Failed to resolve specifiers, ignoring: %s", rvalue);
1775 FOREACH_WORD_QUOTED(w, l, k, state) {
1776 _cleanup_free_ char *n;
1779 n = cunescape_length(w, l);
1783 if (!env_assignment_is_valid(n)) {
1784 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1785 "Invalid environment assignment, ignoring: %s", rvalue);
1789 x = strv_env_set(*env, n);
1800 int config_parse_ip_tos(const char *unit,
1801 const char *filename,
1803 const char *section,
1804 unsigned section_line,
1811 int *ip_tos = data, x;
1818 x = ip_tos_from_string(rvalue);
1820 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1821 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1829 int config_parse_unit_condition_path(const char *unit,
1830 const char *filename,
1832 const char *section,
1833 unsigned section_line,
1840 ConditionType cond = ltype;
1842 bool trigger, negate;
1844 _cleanup_free_ char *p = NULL;
1852 if (isempty(rvalue)) {
1853 /* Empty assignment resets the list */
1854 condition_free_list(u->conditions);
1855 u->conditions = NULL;
1859 trigger = rvalue[0] == '|';
1863 negate = rvalue[0] == '!';
1867 r = unit_full_printf(u, rvalue, &p);
1869 log_syntax(unit, LOG_ERR, filename, line, -r,
1870 "Failed to resolve specifiers, ignoring: %s", rvalue);
1877 if (!path_is_absolute(p)) {
1878 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1879 "Path in condition not absolute, ignoring: %s", p);
1883 c = condition_new(cond, p, trigger, negate);
1887 LIST_PREPEND(conditions, u->conditions, c);
1891 int config_parse_unit_condition_string(const char *unit,
1892 const char *filename,
1894 const char *section,
1895 unsigned section_line,
1902 ConditionType cond = ltype;
1904 bool trigger, negate;
1906 _cleanup_free_ char *s = NULL;
1914 if (isempty(rvalue)) {
1915 /* Empty assignment resets the list */
1916 condition_free_list(u->conditions);
1917 u->conditions = NULL;
1921 trigger = rvalue[0] == '|';
1925 negate = rvalue[0] == '!';
1929 r = unit_full_printf(u, rvalue, &s);
1931 log_syntax(unit, LOG_ERR, filename, line, -r,
1932 "Failed to resolve specifiers, ignoring: %s", rvalue);
1939 c = condition_new(cond, s, trigger, negate);
1943 LIST_PREPEND(conditions, u->conditions, c);
1947 int config_parse_unit_condition_null(const char *unit,
1948 const char *filename,
1950 const char *section,
1951 unsigned section_line,
1960 bool trigger, negate;
1968 if (isempty(rvalue)) {
1969 /* Empty assignment resets the list */
1970 condition_free_list(u->conditions);
1971 u->conditions = NULL;
1975 trigger = rvalue[0] == '|';
1979 negate = rvalue[0] == '!';
1983 b = parse_boolean(rvalue);
1985 log_syntax(unit, LOG_ERR, filename, line, -b,
1986 "Failed to parse boolean value in condition, ignoring: %s",
1994 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1998 LIST_PREPEND(conditions, u->conditions, c);
2002 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2003 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2005 int config_parse_unit_requires_mounts_for(
2007 const char *filename,
2009 const char *section,
2010 unsigned section_line,
2027 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2029 _cleanup_free_ char *n;
2035 if (!utf8_is_valid(n)) {
2036 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2040 r = unit_require_mounts_for(u, n);
2042 log_syntax(unit, LOG_ERR, filename, line, r,
2043 "Failed to add required mount for, ignoring: %s", rvalue);
2051 int config_parse_documentation(const char *unit,
2052 const char *filename,
2054 const char *section,
2055 unsigned section_line,
2071 if (isempty(rvalue)) {
2072 /* Empty assignment resets the list */
2073 strv_free(u->documentation);
2074 u->documentation = NULL;
2078 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2079 rvalue, data, userdata);
2083 for (a = b = u->documentation; a && *a; a++) {
2085 if (is_valid_documentation_url(*a))
2088 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2089 "Invalid URL, ignoring: %s", *a);
2100 int config_parse_syscall_filter(
2102 const char *filename,
2104 const char *section,
2105 unsigned section_line,
2112 static const char default_syscalls[] =
2119 ExecContext *c = data;
2121 bool invert = false;
2131 if (isempty(rvalue)) {
2132 /* Empty assignment resets the list */
2133 set_free(c->syscall_filter);
2134 c->syscall_filter = NULL;
2135 c->syscall_whitelist = false;
2139 if (rvalue[0] == '~') {
2144 if (!c->syscall_filter) {
2145 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2146 if (!c->syscall_filter)
2150 /* Allow everything but the ones listed */
2151 c->syscall_whitelist = false;
2155 /* Allow nothing but the ones listed */
2156 c->syscall_whitelist = true;
2158 /* Accept default syscalls if we are on a whitelist */
2159 NULSTR_FOREACH(i, default_syscalls) {
2162 id = seccomp_syscall_resolve_name(i);
2166 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2175 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2176 _cleanup_free_ char *t = NULL;
2183 id = seccomp_syscall_resolve_name(t);
2185 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2189 /* If we previously wanted to forbid a syscall and now
2190 * we want to allow it, then remove it from the list
2192 if (!invert == c->syscall_whitelist) {
2193 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2199 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2202 /* Turn on NNP, but only if it wasn't configured explicitly
2203 * before, and only if we are in user mode. */
2204 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2205 c->no_new_privileges = true;
2210 int config_parse_syscall_archs(
2212 const char *filename,
2214 const char *section,
2215 unsigned section_line,
2227 if (isempty(rvalue)) {
2233 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2237 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2238 _cleanup_free_ char *t = NULL;
2245 r = seccomp_arch_from_string(t, &a);
2247 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2251 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2261 int config_parse_syscall_errno(
2263 const char *filename,
2265 const char *section,
2266 unsigned section_line,
2273 ExecContext *c = data;
2280 if (isempty(rvalue)) {
2281 /* Empty assignment resets to KILL */
2282 c->syscall_errno = 0;
2286 e = errno_from_name(rvalue);
2288 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2292 c->syscall_errno = e;
2296 int config_parse_address_families(
2298 const char *filename,
2300 const char *section,
2301 unsigned section_line,
2308 ExecContext *c = data;
2310 bool invert = false;
2320 if (isempty(rvalue)) {
2321 /* Empty assignment resets the list */
2322 set_free(c->address_families);
2323 c->address_families = NULL;
2324 c->address_families_whitelist = false;
2328 if (rvalue[0] == '~') {
2333 if (!c->address_families) {
2334 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2335 if (!c->address_families)
2338 c->address_families_whitelist = !invert;
2341 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2342 _cleanup_free_ char *t = NULL;
2349 af = af_from_name(t);
2351 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
2355 /* If we previously wanted to forbid an address family and now
2356 * we want to allow it, then remove it from the list
2358 if (!invert == c->address_families_whitelist) {
2359 r = set_put(c->address_families, INT_TO_PTR(af));
2365 set_remove(c->address_families, INT_TO_PTR(af));
2372 int config_parse_unit_slice(
2374 const char *filename,
2376 const char *section,
2377 unsigned section_line,
2384 _cleanup_free_ char *k = NULL;
2385 Unit *u = userdata, *slice;
2393 r = unit_name_printf(u, rvalue, &k);
2395 log_syntax(unit, LOG_ERR, filename, line, -r,
2396 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2403 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2405 log_syntax(unit, LOG_ERR, filename, line, -r,
2406 "Failed to load slice unit %s. Ignoring.", k);
2410 if (slice->type != UNIT_SLICE) {
2411 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2412 "Slice unit %s is not a slice. Ignoring.", k);
2416 unit_ref_set(&u->slice, slice);
2420 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2422 int config_parse_cpu_shares(
2424 const char *filename,
2426 const char *section,
2427 unsigned section_line,
2434 CGroupContext *c = data;
2442 if (isempty(rvalue)) {
2443 c->cpu_shares = 1024;
2447 r = safe_atolu(rvalue, &lu);
2448 if (r < 0 || lu <= 0) {
2449 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2450 "CPU shares '%s' invalid. Ignoring.", rvalue);
2458 int config_parse_cpu_quota(
2460 const char *filename,
2462 const char *section,
2463 unsigned section_line,
2470 CGroupContext *c = data;
2477 if (isempty(rvalue)) {
2478 c->cpu_quota_per_sec_usec = (usec_t) -1;
2479 c->cpu_quota_usec = (usec_t) -1;
2483 if (endswith(rvalue, "%")) {
2486 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2487 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' invalid. Ignoring.", rvalue);
2491 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2492 c->cpu_quota_usec = (usec_t) -1;
2494 r = parse_sec(rvalue, &c->cpu_quota_usec);
2496 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' invalid. Ignoring.", rvalue);
2500 c->cpu_quota_per_sec_usec = (usec_t) -1;
2506 int config_parse_memory_limit(
2508 const char *filename,
2510 const char *section,
2511 unsigned section_line,
2518 CGroupContext *c = data;
2522 if (isempty(rvalue)) {
2523 c->memory_limit = (uint64_t) -1;
2527 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2529 r = parse_size(rvalue, 1024, &bytes);
2531 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
2535 c->memory_limit = (uint64_t) bytes;
2539 int config_parse_device_allow(
2541 const char *filename,
2543 const char *section,
2544 unsigned section_line,
2551 _cleanup_free_ char *path = NULL;
2552 CGroupContext *c = data;
2553 CGroupDeviceAllow *a;
2557 if (isempty(rvalue)) {
2558 while (c->device_allow)
2559 cgroup_context_free_device_allow(c, c->device_allow);
2564 n = strcspn(rvalue, WHITESPACE);
2565 path = strndup(rvalue, n);
2569 if (!startswith(path, "/dev/") &&
2570 !startswith(path, "block-") &&
2571 !startswith(path, "char-")) {
2572 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2576 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2580 if (!in_charset(m, "rwm")) {
2581 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
2585 a = new0(CGroupDeviceAllow, 1);
2591 a->r = !!strchr(m, 'r');
2592 a->w = !!strchr(m, 'w');
2593 a->m = !!strchr(m, 'm');
2595 LIST_PREPEND(device_allow, c->device_allow, a);
2599 int config_parse_blockio_weight(
2601 const char *filename,
2603 const char *section,
2604 unsigned section_line,
2611 CGroupContext *c = data;
2619 if (isempty(rvalue)) {
2620 c->blockio_weight = 1000;
2624 r = safe_atolu(rvalue, &lu);
2625 if (r < 0 || lu < 10 || lu > 1000) {
2626 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2627 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2631 c->blockio_weight = lu;
2636 int config_parse_blockio_device_weight(
2638 const char *filename,
2640 const char *section,
2641 unsigned section_line,
2648 _cleanup_free_ char *path = NULL;
2649 CGroupBlockIODeviceWeight *w;
2650 CGroupContext *c = data;
2660 if (isempty(rvalue)) {
2661 while (c->blockio_device_weights)
2662 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2667 n = strcspn(rvalue, WHITESPACE);
2668 weight = rvalue + n;
2670 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2671 "Expected block device and device weight. Ignoring.");
2675 path = strndup(rvalue, n);
2679 if (!path_startswith(path, "/dev")) {
2680 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2681 "Invalid device node path '%s'. Ignoring.", path);
2685 weight += strspn(weight, WHITESPACE);
2686 r = safe_atolu(weight, &lu);
2687 if (r < 0 || lu < 10 || lu > 1000) {
2688 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2689 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2694 w = new0(CGroupBlockIODeviceWeight, 1);
2703 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2707 int config_parse_blockio_bandwidth(
2709 const char *filename,
2711 const char *section,
2712 unsigned section_line,
2719 _cleanup_free_ char *path = NULL;
2720 CGroupBlockIODeviceBandwidth *b;
2721 CGroupContext *c = data;
2722 const char *bandwidth;
2732 read = streq("BlockIOReadBandwidth", lvalue);
2734 if (isempty(rvalue)) {
2735 CGroupBlockIODeviceBandwidth *next;
2737 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2738 if (b->read == read)
2739 cgroup_context_free_blockio_device_bandwidth(c, b);
2744 n = strcspn(rvalue, WHITESPACE);
2745 bandwidth = rvalue + n;
2746 bandwidth += strspn(bandwidth, WHITESPACE);
2749 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2750 "Expected space separated pair of device node and bandwidth. Ignoring.");
2754 path = strndup(rvalue, n);
2758 if (!path_startswith(path, "/dev")) {
2759 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2760 "Invalid device node path '%s'. Ignoring.", path);
2764 r = parse_size(bandwidth, 1000, &bytes);
2765 if (r < 0 || bytes <= 0) {
2766 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2770 b = new0(CGroupBlockIODeviceBandwidth, 1);
2776 b->bandwidth = (uint64_t) bytes;
2779 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2784 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2786 int config_parse_job_mode_isolate(
2788 const char *filename,
2790 const char *section,
2791 unsigned section_line,
2805 r = parse_boolean(rvalue);
2807 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2811 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2815 int config_parse_personality(
2817 const char *filename,
2819 const char *section,
2820 unsigned section_line,
2827 unsigned long *personality = data, p;
2832 assert(personality);
2834 p = personality_from_string(rvalue);
2835 if (p == 0xffffffffUL) {
2836 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2837 "Failed to parse personality, ignoring: %s", rvalue);
2845 int config_parse_runtime_directory(
2847 const char *filename,
2849 const char *section,
2850 unsigned section_line,
2857 char***rt = data, *w, *state;
2866 if (isempty(rvalue)) {
2867 /* Empty assignment resets the list */
2873 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2874 _cleanup_free_ char *n;
2880 if (!filename_is_safe(n)) {
2881 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2885 r = strv_push(rt, n);
2895 int config_parse_set_status(
2897 const char *filename,
2899 const char *section,
2900 unsigned section_line,
2911 ExitStatusSet *status_set = data;
2918 if (isempty(rvalue)) {
2919 /* Empty assignment resets the list */
2921 set_free(status_set->signal);
2922 set_free(status_set->code);
2924 status_set->signal = status_set->code = NULL;
2928 FOREACH_WORD(w, l, rvalue, state) {
2929 _cleanup_free_ char *temp;
2932 temp = strndup(w, l);
2936 r = safe_atoi(temp, &val);
2938 val = signal_from_string_try_harder(temp);
2941 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
2945 r = set_put(status_set->signal, INT_TO_PTR(val));
2947 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2951 log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", w);
2955 if (val < 0 || val > 255)
2956 log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
2958 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
2962 r = set_put(status_set->code, INT_TO_PTR(val));
2964 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2974 int config_parse_namespace_path_strv(
2976 const char *filename,
2978 const char *section,
2979 unsigned section_line,
2986 char*** sv = data, *w, *state;
2995 if (isempty(rvalue)) {
2996 /* Empty assignment resets the list */
3002 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
3003 _cleanup_free_ char *n;
3010 if (!utf8_is_valid(n)) {
3011 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3015 offset = n[0] == '-';
3016 if (!path_is_absolute(n + offset)) {
3017 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
3021 path_kill_slashes(n);
3023 r = strv_push(sv, n);
3033 int config_parse_no_new_priviliges(
3035 const char *filename,
3037 const char *section,
3038 unsigned section_line,
3045 ExecContext *c = data;
3053 k = parse_boolean(rvalue);
3055 log_syntax(unit, LOG_ERR, filename, line, -k, "Failed to parse boolean value, ignoring: %s", rvalue);
3059 c->no_new_privileges = !!k;
3060 c->no_new_privileges_set = true;
3065 #define FOLLOW_MAX 8
3067 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3078 /* This will update the filename pointer if the loaded file is
3079 * reached by a symlink. The old string will be freed. */
3082 char *target, *name;
3084 if (c++ >= FOLLOW_MAX)
3087 path_kill_slashes(*filename);
3089 /* Add the file name we are currently looking at to
3090 * the names of this unit, but only if it is a valid
3092 name = basename(*filename);
3094 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3096 id = set_get(names, name);
3102 r = set_consume(names, id);
3108 /* Try to open the file name, but don't if its a symlink */
3109 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3116 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3117 r = readlink_and_make_absolute(*filename, &target);
3125 f = fdopen(fd, "re");
3137 static int merge_by_names(Unit **u, Set *names, const char *id) {
3145 /* Let's try to add in all symlink names we found */
3146 while ((k = set_steal_first(names))) {
3148 /* First try to merge in the other name into our
3150 r = unit_merge_by_name(*u, k);
3154 /* Hmm, we couldn't merge the other unit into
3155 * ours? Then let's try it the other way
3158 other = manager_get_unit((*u)->manager, k);
3162 r = unit_merge(other, *u);
3165 return merge_by_names(u, names, NULL);
3173 unit_choose_id(*u, id);
3181 static int load_from_path(Unit *u, const char *path) {
3183 _cleanup_set_free_free_ Set *symlink_names = NULL;
3184 _cleanup_fclose_ FILE *f = NULL;
3185 _cleanup_free_ char *filename = NULL;
3193 symlink_names = set_new(string_hash_func, string_compare_func);
3197 if (path_is_absolute(path)) {
3199 filename = strdup(path);
3203 r = open_follow(&filename, &f, symlink_names, &id);
3215 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3217 /* Instead of opening the path right away, we manually
3218 * follow all symlinks and add their name to our unit
3219 * name set while doing so */
3220 filename = path_make_absolute(path, *p);
3224 if (u->manager->unit_path_cache &&
3225 !set_get(u->manager->unit_path_cache, filename))
3228 r = open_follow(&filename, &f, symlink_names, &id);
3237 /* Empty the symlink names for the next run */
3238 set_clear_free(symlink_names);
3247 /* Hmm, no suitable file found? */
3251 r = merge_by_names(&merged, symlink_names, id);
3256 u->load_state = UNIT_MERGED;
3260 if (fstat(fileno(f), &st) < 0)
3263 if (null_or_empty(&st))
3264 u->load_state = UNIT_MASKED;
3266 u->load_state = UNIT_LOADED;
3268 /* Now, parse the file contents */
3269 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
3270 config_item_perf_lookup,
3271 (void*) load_fragment_gperf_lookup, false, true, u);
3276 free(u->fragment_path);
3277 u->fragment_path = filename;
3280 u->fragment_mtime = timespec_load(&st.st_mtim);
3282 if (u->source_path) {
3283 if (stat(u->source_path, &st) >= 0)
3284 u->source_mtime = timespec_load(&st.st_mtim);
3286 u->source_mtime = 0;
3292 int unit_load_fragment(Unit *u) {
3298 assert(u->load_state == UNIT_STUB);
3301 /* First, try to find the unit under its id. We always look
3302 * for unit files in the default directories, to make it easy
3303 * to override things by placing things in /etc/systemd/system */
3304 r = load_from_path(u, u->id);
3308 /* Try to find an alias we can load this with */
3309 if (u->load_state == UNIT_STUB)
3310 SET_FOREACH(t, u->names, i) {
3315 r = load_from_path(u, t);
3319 if (u->load_state != UNIT_STUB)
3323 /* And now, try looking for it under the suggested (originally linked) path */
3324 if (u->load_state == UNIT_STUB && u->fragment_path) {
3326 r = load_from_path(u, u->fragment_path);
3330 if (u->load_state == UNIT_STUB) {
3331 /* Hmm, this didn't work? Then let's get rid
3332 * of the fragment path stored for us, so that
3333 * we don't point to an invalid location. */
3334 free(u->fragment_path);
3335 u->fragment_path = NULL;
3339 /* Look for a template */
3340 if (u->load_state == UNIT_STUB && u->instance) {
3341 _cleanup_free_ char *k;
3343 k = unit_name_template(u->id);
3347 r = load_from_path(u, k);
3351 if (u->load_state == UNIT_STUB)
3352 SET_FOREACH(t, u->names, i) {
3353 _cleanup_free_ char *z = NULL;
3358 z = unit_name_template(t);
3362 r = load_from_path(u, z);
3366 if (u->load_state != UNIT_STUB)
3374 void unit_dump_config_items(FILE *f) {
3375 static const struct {
3376 const ConfigParserCallback callback;
3379 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3380 { config_parse_warn_compat, "NOTSUPPORTED" },
3382 { config_parse_int, "INTEGER" },
3383 { config_parse_unsigned, "UNSIGNED" },
3384 { config_parse_iec_size, "SIZE" },
3385 { config_parse_iec_off, "SIZE" },
3386 { config_parse_si_size, "SIZE" },
3387 { config_parse_bool, "BOOLEAN" },
3388 { config_parse_string, "STRING" },
3389 { config_parse_path, "PATH" },
3390 { config_parse_unit_path_printf, "PATH" },
3391 { config_parse_strv, "STRING [...]" },
3392 { config_parse_exec_nice, "NICE" },
3393 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3394 { config_parse_exec_io_class, "IOCLASS" },
3395 { config_parse_exec_io_priority, "IOPRIORITY" },
3396 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3397 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3398 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3399 { config_parse_mode, "MODE" },
3400 { config_parse_unit_env_file, "FILE" },
3401 { config_parse_output, "OUTPUT" },
3402 { config_parse_input, "INPUT" },
3403 { config_parse_log_facility, "FACILITY" },
3404 { config_parse_log_level, "LEVEL" },
3405 { config_parse_exec_capabilities, "CAPABILITIES" },
3406 { config_parse_exec_secure_bits, "SECUREBITS" },
3407 { config_parse_bounding_set, "BOUNDINGSET" },
3408 { config_parse_limit, "LIMIT" },
3409 { config_parse_unit_deps, "UNIT [...]" },
3410 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3411 { config_parse_service_type, "SERVICETYPE" },
3412 { config_parse_service_restart, "SERVICERESTART" },
3413 #ifdef HAVE_SYSV_COMPAT
3414 { config_parse_sysv_priority, "SYSVPRIORITY" },
3416 { config_parse_kill_mode, "KILLMODE" },
3417 { config_parse_kill_signal, "SIGNAL" },
3418 { config_parse_socket_listen, "SOCKET [...]" },
3419 { config_parse_socket_bind, "SOCKETBIND" },
3420 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3421 { config_parse_sec, "SECONDS" },
3422 { config_parse_nsec, "NANOSECONDS" },
3423 { config_parse_namespace_path_strv, "PATH [...]" },
3424 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3425 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3426 { config_parse_unit_string_printf, "STRING" },
3427 { config_parse_trigger_unit, "UNIT" },
3428 { config_parse_timer, "TIMER" },
3429 { config_parse_path_spec, "PATH" },
3430 { config_parse_notify_access, "ACCESS" },
3431 { config_parse_ip_tos, "TOS" },
3432 { config_parse_unit_condition_path, "CONDITION" },
3433 { config_parse_unit_condition_string, "CONDITION" },
3434 { config_parse_unit_condition_null, "CONDITION" },
3435 { config_parse_unit_slice, "SLICE" },
3436 { config_parse_documentation, "URL" },
3437 { config_parse_service_timeout, "SECONDS" },
3438 { config_parse_failure_action, "ACTION" },
3439 { config_parse_set_status, "STATUS" },
3440 { config_parse_service_sockets, "SOCKETS" },
3441 { config_parse_environ, "ENVIRON" },
3443 { config_parse_syscall_filter, "SYSCALLS" },
3444 { config_parse_syscall_archs, "ARCHS" },
3445 { config_parse_syscall_errno, "ERRNO" },
3446 { config_parse_address_families, "FAMILIES" },
3448 { config_parse_cpu_shares, "SHARES" },
3449 { config_parse_memory_limit, "LIMIT" },
3450 { config_parse_device_allow, "DEVICE" },
3451 { config_parse_device_policy, "POLICY" },
3452 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3453 { config_parse_blockio_weight, "WEIGHT" },
3454 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3455 { config_parse_long, "LONG" },
3456 { config_parse_socket_service, "SERVICE" },
3458 { config_parse_exec_selinux_context, "LABEL" },
3460 { config_parse_job_mode, "MODE" },
3461 { config_parse_job_mode_isolate, "BOOLEAN" },
3462 { config_parse_personality, "PERSONALITY" },
3465 const char *prev = NULL;
3470 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3471 const char *rvalue = "OTHER", *lvalue;
3475 const ConfigPerfItem *p;
3477 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3479 dot = strchr(i, '.');
3480 lvalue = dot ? dot + 1 : i;
3484 if (!prev || !strneq(prev, i, prefix_len+1)) {
3488 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3491 for (j = 0; j < ELEMENTSOF(table); j++)
3492 if (p->parse == table[j].callback) {
3493 rvalue = table[j].rvalue;
3497 fprintf(f, "%s=%s\n", lvalue, rvalue);