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;
107 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
108 _cleanup_free_ char *t = NULL, *k = NULL;
115 r = unit_name_printf(u, t, &k);
117 log_syntax(unit, LOG_ERR, filename, line, -r,
118 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
122 r = unit_add_dependency_by_name(u, d, k, NULL, true);
124 log_syntax(unit, LOG_ERR, filename, line, -r,
125 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
131 int config_parse_unit_string_printf(const char *unit,
132 const char *filename,
135 unsigned section_line,
143 _cleanup_free_ char *k = NULL;
151 r = unit_full_printf(u, rvalue, &k);
153 log_syntax(unit, LOG_ERR, filename, line, -r,
154 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
156 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
157 k ? k : rvalue, data, userdata);
160 int config_parse_unit_strv_printf(const char *unit,
161 const char *filename,
164 unsigned section_line,
172 _cleanup_free_ char *k = NULL;
180 r = unit_full_printf(u, rvalue, &k);
182 log_syntax(unit, LOG_ERR, filename, line, -r,
183 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
185 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
186 k ? k : rvalue, data, userdata);
189 int config_parse_unit_path_printf(const char *unit,
190 const char *filename,
193 unsigned section_line,
200 _cleanup_free_ char *k = NULL;
209 r = unit_full_printf(u, rvalue, &k);
211 log_syntax(unit, LOG_ERR, filename, line, -r, "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, k, data, userdata);
218 int config_parse_unit_path_strv_printf(
220 const char *filename,
223 unsigned section_line,
230 char *w, *state, ***x = data;
240 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
241 _cleanup_free_ char *k = NULL;
247 r = unit_full_printf(u, t, &k);
249 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
253 if (!utf8_is_valid(k)) {
254 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
258 if (!path_is_absolute(k)) {
259 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
263 path_kill_slashes(k);
275 int config_parse_socket_listen(const char *unit,
276 const char *filename,
279 unsigned section_line,
286 SocketPort *p, *tail;
297 if (isempty(rvalue)) {
298 /* An empty assignment removes all ports */
299 socket_free_ports(s);
303 p = new0(SocketPort, 1);
307 if (ltype != SOCKET_SOCKET) {
310 r = unit_full_printf(UNIT(s), rvalue, &p->path);
312 p->path = strdup(rvalue);
317 log_syntax(unit, LOG_ERR, filename, line, -r,
318 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
321 path_kill_slashes(p->path);
323 } else if (streq(lvalue, "ListenNetlink")) {
324 _cleanup_free_ char *k = NULL;
326 p->type = SOCKET_SOCKET;
327 r = unit_full_printf(UNIT(s), rvalue, &k);
329 log_syntax(unit, LOG_ERR, filename, line, -r,
330 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
332 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
334 log_syntax(unit, LOG_ERR, filename, line, -r,
335 "Failed to parse address value, ignoring: %s", rvalue);
341 _cleanup_free_ char *k = NULL;
343 p->type = SOCKET_SOCKET;
344 r = unit_full_printf(UNIT(s), rvalue, &k);
346 log_syntax(unit, LOG_ERR, filename, line, -r,
347 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
349 r = socket_address_parse(&p->address, k ? k : rvalue);
351 log_syntax(unit, LOG_ERR, filename, line, -r,
352 "Failed to parse address value, ignoring: %s", rvalue);
357 if (streq(lvalue, "ListenStream"))
358 p->address.type = SOCK_STREAM;
359 else if (streq(lvalue, "ListenDatagram"))
360 p->address.type = SOCK_DGRAM;
362 assert(streq(lvalue, "ListenSequentialPacket"));
363 p->address.type = SOCK_SEQPACKET;
366 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
367 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
368 "Address family not supported, ignoring: %s", rvalue);
378 LIST_FIND_TAIL(port, s->ports, tail);
379 LIST_INSERT_AFTER(port, s->ports, tail, p);
381 LIST_PREPEND(port, s->ports, p);
386 int config_parse_socket_bind(const char *unit,
387 const char *filename,
390 unsigned section_line,
398 SocketAddressBindIPv6Only b;
407 b = socket_address_bind_ipv6_only_from_string(rvalue);
411 r = parse_boolean(rvalue);
413 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
414 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
418 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
420 s->bind_ipv6_only = b;
425 int config_parse_exec_nice(const char *unit,
426 const char *filename,
429 unsigned section_line,
436 ExecContext *c = data;
444 r = safe_atoi(rvalue, &priority);
446 log_syntax(unit, LOG_ERR, filename, line, -r,
447 "Failed to parse nice priority, ignoring: %s. ", rvalue);
451 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
452 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
453 "Nice priority out of range, ignoring: %s", rvalue);
463 int config_parse_exec_oom_score_adjust(const char* unit,
464 const char *filename,
467 unsigned section_line,
474 ExecContext *c = data;
482 r = safe_atoi(rvalue, &oa);
484 log_syntax(unit, LOG_ERR, filename, line, -r,
485 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
489 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
490 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
491 "OOM score adjust value out of range, ignoring: %s", rvalue);
495 c->oom_score_adjust = oa;
496 c->oom_score_adjust_set = true;
501 int config_parse_exec(const char *unit,
502 const char *filename,
505 unsigned section_line,
512 ExecCommand **e = data, *nce;
524 if (isempty(rvalue)) {
525 /* An empty assignment resets the list */
526 exec_command_free_list(*e);
531 /* We accept an absolute path as first argument, or
532 * alternatively an absolute prefixed with @ to allow
533 * overriding of argv[0]. */
539 bool honour_argv0 = false, ignore = false;
545 rvalue += strspn(rvalue, WHITESPACE);
550 for (i = 0; i < 2; i++) {
551 if (rvalue[0] == '-' && !ignore) {
556 if (rvalue[0] == '@' && !honour_argv0) {
562 if (*rvalue != '/') {
563 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
564 "Executable path is not absolute, ignoring: %s", rvalue);
569 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
570 if (strneq(w, ";", MAX(l, 1U)))
576 n = new(char*, k + !honour_argv0);
581 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
582 if (strneq(w, ";", MAX(l, 1U)))
584 else if (strneq(w, "\\;", MAX(l, 1U)))
587 if (honour_argv0 && w == rvalue) {
590 path = strndup(w, l);
596 if (!utf8_is_valid(path)) {
597 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
605 c = n[k++] = cunescape_length(w, l);
611 if (!utf8_is_valid(c)) {
612 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
622 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
623 "Invalid command line, ignoring: %s", rvalue);
636 assert(path_is_absolute(path));
638 nce = new0(ExecCommand, 1);
646 nce->ignore = ignore;
648 path_kill_slashes(nce->path);
650 exec_command_append_list(e, nce);
666 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
667 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
669 int config_parse_socket_bindtodevice(const char* unit,
670 const char *filename,
673 unsigned section_line,
688 if (rvalue[0] && !streq(rvalue, "*")) {
695 free(s->bind_to_device);
696 s->bind_to_device = n;
701 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
702 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
704 int config_parse_exec_io_class(const char *unit,
705 const char *filename,
708 unsigned section_line,
715 ExecContext *c = data;
723 x = ioprio_class_from_string(rvalue);
725 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
726 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
730 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
731 c->ioprio_set = true;
736 int config_parse_exec_io_priority(const char *unit,
737 const char *filename,
740 unsigned section_line,
747 ExecContext *c = data;
755 r = safe_atoi(rvalue, &i);
756 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
757 log_syntax(unit, LOG_ERR, filename, line, -r,
758 "Failed to parse IO priority, ignoring: %s", rvalue);
762 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
763 c->ioprio_set = true;
768 int config_parse_exec_cpu_sched_policy(const char *unit,
769 const char *filename,
772 unsigned section_line,
780 ExecContext *c = data;
788 x = sched_policy_from_string(rvalue);
790 log_syntax(unit, LOG_ERR, filename, line, -x,
791 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
795 c->cpu_sched_policy = x;
796 /* Moving to or from real-time policy? We need to adjust the priority */
797 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
798 c->cpu_sched_set = true;
803 int config_parse_exec_cpu_sched_prio(const char *unit,
804 const char *filename,
807 unsigned section_line,
814 ExecContext *c = data;
822 r = safe_atoi(rvalue, &i);
824 log_syntax(unit, LOG_ERR, filename, line, -r,
825 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
829 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
830 min = sched_get_priority_min(c->cpu_sched_policy);
831 max = sched_get_priority_max(c->cpu_sched_policy);
833 if (i < min || i > max) {
834 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
835 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
839 c->cpu_sched_priority = i;
840 c->cpu_sched_set = true;
845 int config_parse_exec_cpu_affinity(const char *unit,
846 const char *filename,
849 unsigned section_line,
856 ExecContext *c = data;
866 if (isempty(rvalue)) {
867 /* An empty assignment resets the CPU list */
874 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
875 _cleanup_free_ char *t = NULL;
883 r = safe_atou(t, &cpu);
886 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
891 if (r < 0 || cpu >= c->cpuset_ncpus) {
892 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
893 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
897 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
903 int config_parse_exec_capabilities(const char *unit,
904 const char *filename,
907 unsigned section_line,
914 ExecContext *c = data;
922 cap = cap_from_text(rvalue);
924 log_syntax(unit, LOG_ERR, filename, line, errno,
925 "Failed to parse capabilities, ignoring: %s", rvalue);
930 cap_free(c->capabilities);
931 c->capabilities = cap;
936 int config_parse_exec_secure_bits(const char *unit,
937 const char *filename,
940 unsigned section_line,
947 ExecContext *c = data;
957 if (isempty(rvalue)) {
958 /* An empty assignment resets the field */
963 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
964 if (first_word(w, "keep-caps"))
965 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
966 else if (first_word(w, "keep-caps-locked"))
967 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
968 else if (first_word(w, "no-setuid-fixup"))
969 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
970 else if (first_word(w, "no-setuid-fixup-locked"))
971 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
972 else if (first_word(w, "noroot"))
973 c->secure_bits |= 1<<SECURE_NOROOT;
974 else if (first_word(w, "noroot-locked"))
975 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
977 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
978 "Failed to parse secure bits, ignoring: %s", rvalue);
986 int config_parse_bounding_set(const char *unit,
987 const char *filename,
990 unsigned section_line,
997 uint64_t *capability_bounding_set_drop = data;
1001 bool invert = false;
1009 if (rvalue[0] == '~') {
1014 /* Note that we store this inverted internally, since the
1015 * kernel wants it like this. But we actually expose it
1016 * non-inverted everywhere to have a fully normalized
1019 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1020 _cleanup_free_ char *t = NULL;
1028 r = cap_from_name(t, &cap);
1030 log_syntax(unit, LOG_ERR, filename, line, errno,
1031 "Failed to parse capability in bounding set, ignoring: %s", t);
1035 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1039 *capability_bounding_set_drop |= sum;
1041 *capability_bounding_set_drop |= ~sum;
1046 int config_parse_limit(const char *unit,
1047 const char *filename,
1049 const char *section,
1050 unsigned section_line,
1057 struct rlimit **rl = data;
1058 unsigned long long u;
1067 if (streq(rvalue, "infinity"))
1068 u = (unsigned long long) RLIM_INFINITY;
1072 r = safe_atollu(rvalue, &u);
1074 log_syntax(unit, LOG_ERR, filename, line, -r,
1075 "Failed to parse resource value, ignoring: %s", rvalue);
1081 *rl = new(struct rlimit, 1);
1086 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1090 #ifdef HAVE_SYSV_COMPAT
1091 int config_parse_sysv_priority(const char *unit,
1092 const char *filename,
1094 const char *section,
1095 unsigned section_line,
1102 int *priority = data;
1110 r = safe_atoi(rvalue, &i);
1111 if (r < 0 || i < 0) {
1112 log_syntax(unit, LOG_ERR, filename, line, -r,
1113 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1117 *priority = (int) i;
1122 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1124 int config_parse_kill_signal(const char *unit,
1125 const char *filename,
1127 const char *section,
1128 unsigned section_line,
1143 r = signal_from_string_try_harder(rvalue);
1145 log_syntax(unit, LOG_ERR, filename, line, -r,
1146 "Failed to parse kill signal, ignoring: %s", rvalue);
1154 int config_parse_exec_mount_flags(const char *unit,
1155 const char *filename,
1157 const char *section,
1158 unsigned section_line,
1165 ExecContext *c = data;
1169 unsigned long flags = 0;
1176 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1177 _cleanup_free_ char *t;
1183 if (streq(t, "shared"))
1185 else if (streq(t, "slave"))
1187 else if (streq(w, "private"))
1190 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1195 c->mount_flags = flags;
1199 int config_parse_exec_selinux_context(
1201 const char *filename,
1203 const char *section,
1204 unsigned section_line,
1211 ExecContext *c = data;
1222 if (isempty(rvalue)) {
1223 free(c->selinux_context);
1224 c->selinux_context = NULL;
1225 c->selinux_context_ignore = false;
1229 if (rvalue[0] == '-') {
1235 r = unit_name_printf(u, rvalue, &k);
1237 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1241 free(c->selinux_context);
1242 c->selinux_context = k;
1243 c->selinux_context_ignore = ignore;
1248 int config_parse_exec_apparmor_profile(
1250 const char *filename,
1252 const char *section,
1253 unsigned section_line,
1260 ExecContext *c = data;
1271 if (isempty(rvalue)) {
1272 free(c->apparmor_profile);
1273 c->apparmor_profile = NULL;
1274 c->apparmor_profile_ignore = false;
1278 if (rvalue[0] == '-') {
1284 r = unit_name_printf(u, rvalue, &k);
1286 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1290 free(c->apparmor_profile);
1291 c->apparmor_profile = k;
1292 c->apparmor_profile_ignore = ignore;
1297 int config_parse_timer(const char *unit,
1298 const char *filename,
1300 const char *section,
1301 unsigned section_line,
1312 CalendarSpec *c = NULL;
1319 if (isempty(rvalue)) {
1320 /* Empty assignment resets list */
1321 timer_free_values(t);
1325 b = timer_base_from_string(lvalue);
1327 log_syntax(unit, LOG_ERR, filename, line, -b,
1328 "Failed to parse timer base, ignoring: %s", lvalue);
1332 if (b == TIMER_CALENDAR) {
1333 if (calendar_spec_from_string(rvalue, &c) < 0) {
1334 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1335 "Failed to parse calendar specification, ignoring: %s",
1340 if (parse_sec(rvalue, &u) < 0) {
1341 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1342 "Failed to parse timer value, ignoring: %s",
1348 v = new0(TimerValue, 1);
1354 v->calendar_spec = c;
1356 LIST_PREPEND(value, t->values, v);
1361 int config_parse_trigger_unit(
1363 const char *filename,
1365 const char *section,
1366 unsigned section_line,
1373 _cleanup_free_ char *p = NULL;
1383 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1384 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1385 "Multiple units to trigger specified, ignoring: %s", rvalue);
1389 r = unit_name_printf(u, rvalue, &p);
1391 log_syntax(unit, LOG_ERR, filename, line, -r,
1392 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1394 type = unit_name_to_type(p ?: rvalue);
1396 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1397 "Unit type not valid, ignoring: %s", rvalue);
1401 if (type == u->type) {
1402 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1403 "Trigger cannot be of same type, ignoring: %s", rvalue);
1407 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1409 log_syntax(unit, LOG_ERR, filename, line, -r,
1410 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1417 int config_parse_path_spec(const char *unit,
1418 const char *filename,
1420 const char *section,
1421 unsigned section_line,
1431 _cleanup_free_ char *k = NULL;
1439 if (isempty(rvalue)) {
1440 /* Empty assignment clears list */
1445 b = path_type_from_string(lvalue);
1447 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1448 "Failed to parse path type, ignoring: %s", lvalue);
1452 r = unit_full_printf(UNIT(p), rvalue, &k);
1458 log_syntax(unit, LOG_ERR, filename, line, -r,
1459 "Failed to resolve unit specifiers on %s. Ignoring.",
1463 if (!path_is_absolute(k)) {
1464 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1465 "Path is not absolute, ignoring: %s", k);
1469 s = new0(PathSpec, 1);
1474 s->path = path_kill_slashes(k);
1479 LIST_PREPEND(spec, p->specs, s);
1484 int config_parse_socket_service(const char *unit,
1485 const char *filename,
1487 const char *section,
1488 unsigned section_line,
1495 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1499 _cleanup_free_ char *p = NULL;
1506 r = unit_name_printf(UNIT(s), rvalue, &p);
1508 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1512 if (!endswith(p, ".service")) {
1513 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1517 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1519 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1523 unit_ref_set(&s->service, x);
1528 int config_parse_service_sockets(const char *unit,
1529 const char *filename,
1531 const char *section,
1532 unsigned section_line,
1549 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1550 _cleanup_free_ char *t = NULL, *k = NULL;
1556 r = unit_name_printf(UNIT(s), t, &k);
1558 log_syntax(unit, LOG_ERR, filename, line, -r,
1559 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1561 if (!endswith(k ?: t, ".socket")) {
1562 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1563 "Unit must be of type socket, ignoring: %s", k ?: t);
1567 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1569 log_syntax(unit, LOG_ERR, filename, line, -r,
1570 "Failed to add dependency on %s, ignoring: %s",
1571 k ?: t, strerror(-r));
1573 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1581 int config_parse_service_timeout(const char *unit,
1582 const char *filename,
1584 const char *section,
1585 unsigned section_line,
1592 Service *s = userdata;
1600 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1601 rvalue, data, userdata);
1605 if (streq(lvalue, "TimeoutSec")) {
1606 s->start_timeout_defined = true;
1607 s->timeout_stop_usec = s->timeout_start_usec;
1608 } else if (streq(lvalue, "TimeoutStartSec"))
1609 s->start_timeout_defined = true;
1614 int config_parse_busname_service(
1616 const char *filename,
1618 const char *section,
1619 unsigned section_line,
1626 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1630 _cleanup_free_ char *p = NULL;
1637 r = unit_name_printf(UNIT(n), rvalue, &p);
1639 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1643 if (!endswith(p, ".service")) {
1644 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1648 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1650 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1654 unit_ref_set(&n->service, x);
1659 int config_parse_bus_policy(
1661 const char *filename,
1663 const char *section,
1664 unsigned section_line,
1671 _cleanup_free_ BusNamePolicy *p = NULL;
1672 _cleanup_free_ char *id_str = NULL;
1673 BusName *busname = data;
1682 p = new0(BusNamePolicy, 1);
1686 if (streq(lvalue, "AllowUser"))
1687 p->type = BUSNAME_POLICY_TYPE_USER;
1688 else if (streq(lvalue, "AllowGroup"))
1689 p->type = BUSNAME_POLICY_TYPE_GROUP;
1690 else if (streq(lvalue, "AllowWorld"))
1691 p->type = BUSNAME_POLICY_TYPE_WORLD;
1693 assert_not_reached("Unknown lvalue");
1695 id_str = strdup(rvalue);
1699 if (p->type != BUSNAME_POLICY_TYPE_WORLD) {
1700 access_str = strchr(id_str, ' ');
1702 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy value '%s'", rvalue);
1709 if (p->type == BUSNAME_POLICY_TYPE_USER) {
1710 const char *user = id_str;
1712 r = get_user_creds(&user, &p->uid, NULL, NULL, NULL);
1714 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to parse uid from '%s'", id_str);
1718 const char *group = id_str;
1720 r = get_group_creds(&group, &p->gid);
1722 log_syntax(unit, LOG_ERR, filename, line, -errno, "Unable to parse gid from '%s'", id_str);
1727 access_str = id_str;
1730 p->access = busname_policy_access_from_string(access_str);
1731 if (p->access < 0) {
1732 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy access type '%s'", access_str);
1736 LIST_PREPEND(policy, busname->policy, p);
1742 int config_parse_unit_env_file(const char *unit,
1743 const char *filename,
1745 const char *section,
1746 unsigned section_line,
1755 _cleanup_free_ char *n = NULL;
1764 if (isempty(rvalue)) {
1765 /* Empty assignment frees the list */
1771 r = unit_full_printf(u, rvalue, &n);
1773 log_syntax(unit, LOG_ERR, filename, line, r,
1774 "Failed to resolve specifiers, ignoring: %s", rvalue);
1777 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1778 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1779 "Path '%s' is not absolute, ignoring.", s);
1783 r = strv_extend(env, s);
1790 int config_parse_environ(const char *unit,
1791 const char *filename,
1793 const char *section,
1794 unsigned section_line,
1802 char*** env = data, *w, *state;
1804 _cleanup_free_ char *k = NULL;
1812 if (isempty(rvalue)) {
1813 /* Empty assignment resets the list */
1820 r = unit_full_printf(u, rvalue, &k);
1822 log_syntax(unit, LOG_ERR, filename, line, -r,
1823 "Failed to resolve specifiers, ignoring: %s", rvalue);
1831 FOREACH_WORD_QUOTED(w, l, k, state) {
1832 _cleanup_free_ char *n;
1835 n = cunescape_length(w, l);
1839 if (!env_assignment_is_valid(n)) {
1840 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1841 "Invalid environment assignment, ignoring: %s", rvalue);
1845 x = strv_env_set(*env, n);
1856 int config_parse_ip_tos(const char *unit,
1857 const char *filename,
1859 const char *section,
1860 unsigned section_line,
1867 int *ip_tos = data, x;
1874 x = ip_tos_from_string(rvalue);
1876 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1877 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1885 int config_parse_unit_condition_path(const char *unit,
1886 const char *filename,
1888 const char *section,
1889 unsigned section_line,
1896 ConditionType cond = ltype;
1898 bool trigger, negate;
1900 _cleanup_free_ char *p = NULL;
1908 if (isempty(rvalue)) {
1909 /* Empty assignment resets the list */
1910 condition_free_list(u->conditions);
1911 u->conditions = NULL;
1915 trigger = rvalue[0] == '|';
1919 negate = rvalue[0] == '!';
1923 r = unit_full_printf(u, rvalue, &p);
1925 log_syntax(unit, LOG_ERR, filename, line, -r,
1926 "Failed to resolve specifiers, ignoring: %s", rvalue);
1933 if (!path_is_absolute(p)) {
1934 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1935 "Path in condition not absolute, ignoring: %s", p);
1939 c = condition_new(cond, p, trigger, negate);
1943 LIST_PREPEND(conditions, u->conditions, c);
1947 int config_parse_unit_condition_string(const char *unit,
1948 const char *filename,
1950 const char *section,
1951 unsigned section_line,
1958 ConditionType cond = ltype;
1960 bool trigger, negate;
1962 _cleanup_free_ char *s = NULL;
1970 if (isempty(rvalue)) {
1971 /* Empty assignment resets the list */
1972 condition_free_list(u->conditions);
1973 u->conditions = NULL;
1977 trigger = rvalue[0] == '|';
1981 negate = rvalue[0] == '!';
1985 r = unit_full_printf(u, rvalue, &s);
1987 log_syntax(unit, LOG_ERR, filename, line, -r,
1988 "Failed to resolve specifiers, ignoring: %s", rvalue);
1995 c = condition_new(cond, s, trigger, negate);
1999 LIST_PREPEND(conditions, u->conditions, c);
2003 int config_parse_unit_condition_null(const char *unit,
2004 const char *filename,
2006 const char *section,
2007 unsigned section_line,
2016 bool trigger, negate;
2024 if (isempty(rvalue)) {
2025 /* Empty assignment resets the list */
2026 condition_free_list(u->conditions);
2027 u->conditions = NULL;
2031 trigger = rvalue[0] == '|';
2035 negate = rvalue[0] == '!';
2039 b = parse_boolean(rvalue);
2041 log_syntax(unit, LOG_ERR, filename, line, -b,
2042 "Failed to parse boolean value in condition, ignoring: %s",
2050 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2054 LIST_PREPEND(conditions, u->conditions, c);
2058 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2059 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2061 int config_parse_unit_requires_mounts_for(
2063 const char *filename,
2065 const char *section,
2066 unsigned section_line,
2083 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2085 _cleanup_free_ char *n;
2091 if (!utf8_is_valid(n)) {
2092 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2096 r = unit_require_mounts_for(u, n);
2098 log_syntax(unit, LOG_ERR, filename, line, r,
2099 "Failed to add required mount for, ignoring: %s", rvalue);
2107 int config_parse_documentation(const char *unit,
2108 const char *filename,
2110 const char *section,
2111 unsigned section_line,
2127 if (isempty(rvalue)) {
2128 /* Empty assignment resets the list */
2129 strv_free(u->documentation);
2130 u->documentation = NULL;
2134 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2135 rvalue, data, userdata);
2139 for (a = b = u->documentation; a && *a; a++) {
2141 if (is_valid_documentation_url(*a))
2144 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2145 "Invalid URL, ignoring: %s", *a);
2156 int config_parse_syscall_filter(
2158 const char *filename,
2160 const char *section,
2161 unsigned section_line,
2168 static const char default_syscalls[] =
2175 ExecContext *c = data;
2177 bool invert = false;
2187 if (isempty(rvalue)) {
2188 /* Empty assignment resets the list */
2189 set_free(c->syscall_filter);
2190 c->syscall_filter = NULL;
2191 c->syscall_whitelist = false;
2195 if (rvalue[0] == '~') {
2200 if (!c->syscall_filter) {
2201 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2202 if (!c->syscall_filter)
2206 /* Allow everything but the ones listed */
2207 c->syscall_whitelist = false;
2211 /* Allow nothing but the ones listed */
2212 c->syscall_whitelist = true;
2214 /* Accept default syscalls if we are on a whitelist */
2215 NULSTR_FOREACH(i, default_syscalls) {
2218 id = seccomp_syscall_resolve_name(i);
2222 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2231 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2232 _cleanup_free_ char *t = NULL;
2239 id = seccomp_syscall_resolve_name(t);
2241 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2245 /* If we previously wanted to forbid a syscall and now
2246 * we want to allow it, then remove it from the list
2248 if (!invert == c->syscall_whitelist) {
2249 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2255 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2258 /* Turn on NNP, but only if it wasn't configured explicitly
2259 * before, and only if we are in user mode. */
2260 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2261 c->no_new_privileges = true;
2266 int config_parse_syscall_archs(
2268 const char *filename,
2270 const char *section,
2271 unsigned section_line,
2283 if (isempty(rvalue)) {
2289 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2293 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2294 _cleanup_free_ char *t = NULL;
2301 r = seccomp_arch_from_string(t, &a);
2303 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2307 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2317 int config_parse_syscall_errno(
2319 const char *filename,
2321 const char *section,
2322 unsigned section_line,
2329 ExecContext *c = data;
2336 if (isempty(rvalue)) {
2337 /* Empty assignment resets to KILL */
2338 c->syscall_errno = 0;
2342 e = errno_from_name(rvalue);
2344 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2348 c->syscall_errno = e;
2352 int config_parse_address_families(
2354 const char *filename,
2356 const char *section,
2357 unsigned section_line,
2364 ExecContext *c = data;
2366 bool invert = false;
2376 if (isempty(rvalue)) {
2377 /* Empty assignment resets the list */
2378 set_free(c->address_families);
2379 c->address_families = NULL;
2380 c->address_families_whitelist = false;
2384 if (rvalue[0] == '~') {
2389 if (!c->address_families) {
2390 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2391 if (!c->address_families)
2394 c->address_families_whitelist = !invert;
2397 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2398 _cleanup_free_ char *t = NULL;
2405 af = af_from_name(t);
2407 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
2411 /* If we previously wanted to forbid an address family and now
2412 * we want to allow it, then remove it from the list
2414 if (!invert == c->address_families_whitelist) {
2415 r = set_put(c->address_families, INT_TO_PTR(af));
2421 set_remove(c->address_families, INT_TO_PTR(af));
2428 int config_parse_unit_slice(
2430 const char *filename,
2432 const char *section,
2433 unsigned section_line,
2440 _cleanup_free_ char *k = NULL;
2441 Unit *u = userdata, *slice;
2449 r = unit_name_printf(u, rvalue, &k);
2451 log_syntax(unit, LOG_ERR, filename, line, -r,
2452 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2459 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2461 log_syntax(unit, LOG_ERR, filename, line, -r,
2462 "Failed to load slice unit %s. Ignoring.", k);
2466 if (slice->type != UNIT_SLICE) {
2467 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2468 "Slice unit %s is not a slice. Ignoring.", k);
2472 unit_ref_set(&u->slice, slice);
2476 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2478 int config_parse_cpu_shares(
2480 const char *filename,
2482 const char *section,
2483 unsigned section_line,
2490 unsigned long *shares = data, lu;
2497 if (isempty(rvalue)) {
2498 *shares = (unsigned long) -1;
2502 r = safe_atolu(rvalue, &lu);
2503 if (r < 0 || lu <= 0) {
2504 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU shares '%s' invalid. Ignoring.", rvalue);
2512 int config_parse_cpu_quota(
2514 const char *filename,
2516 const char *section,
2517 unsigned section_line,
2524 CGroupContext *c = data;
2531 if (isempty(rvalue)) {
2532 c->cpu_quota_per_sec_usec = (usec_t) -1;
2536 if (!endswith(rvalue, "%")) {
2538 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2542 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2543 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' invalid. Ignoring.", rvalue);
2547 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2552 int config_parse_memory_limit(
2554 const char *filename,
2556 const char *section,
2557 unsigned section_line,
2564 CGroupContext *c = data;
2568 if (isempty(rvalue)) {
2569 c->memory_limit = (uint64_t) -1;
2573 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2575 r = parse_size(rvalue, 1024, &bytes);
2577 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
2581 c->memory_limit = (uint64_t) bytes;
2585 int config_parse_device_allow(
2587 const char *filename,
2589 const char *section,
2590 unsigned section_line,
2597 _cleanup_free_ char *path = NULL;
2598 CGroupContext *c = data;
2599 CGroupDeviceAllow *a;
2603 if (isempty(rvalue)) {
2604 while (c->device_allow)
2605 cgroup_context_free_device_allow(c, c->device_allow);
2610 n = strcspn(rvalue, WHITESPACE);
2611 path = strndup(rvalue, n);
2615 if (!startswith(path, "/dev/") &&
2616 !startswith(path, "block-") &&
2617 !startswith(path, "char-")) {
2618 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2622 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2626 if (!in_charset(m, "rwm")) {
2627 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
2631 a = new0(CGroupDeviceAllow, 1);
2637 a->r = !!strchr(m, 'r');
2638 a->w = !!strchr(m, 'w');
2639 a->m = !!strchr(m, 'm');
2641 LIST_PREPEND(device_allow, c->device_allow, a);
2645 int config_parse_blockio_weight(
2647 const char *filename,
2649 const char *section,
2650 unsigned section_line,
2657 unsigned long *weight = data, lu;
2664 if (isempty(rvalue)) {
2665 *weight = (unsigned long) -1;
2669 r = safe_atolu(rvalue, &lu);
2670 if (r < 0 || lu < 10 || lu > 1000) {
2671 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
2679 int config_parse_blockio_device_weight(
2681 const char *filename,
2683 const char *section,
2684 unsigned section_line,
2691 _cleanup_free_ char *path = NULL;
2692 CGroupBlockIODeviceWeight *w;
2693 CGroupContext *c = data;
2703 if (isempty(rvalue)) {
2704 while (c->blockio_device_weights)
2705 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2710 n = strcspn(rvalue, WHITESPACE);
2711 weight = rvalue + n;
2713 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Expected block device and device weight. Ignoring.");
2717 path = strndup(rvalue, n);
2721 if (!path_startswith(path, "/dev")) {
2722 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2726 weight += strspn(weight, WHITESPACE);
2727 r = safe_atolu(weight, &lu);
2728 if (r < 0 || lu < 10 || lu > 1000) {
2729 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
2733 w = new0(CGroupBlockIODeviceWeight, 1);
2742 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2746 int config_parse_blockio_bandwidth(
2748 const char *filename,
2750 const char *section,
2751 unsigned section_line,
2758 _cleanup_free_ char *path = NULL;
2759 CGroupBlockIODeviceBandwidth *b;
2760 CGroupContext *c = data;
2761 const char *bandwidth;
2771 read = streq("BlockIOReadBandwidth", lvalue);
2773 if (isempty(rvalue)) {
2774 CGroupBlockIODeviceBandwidth *next;
2776 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2777 if (b->read == read)
2778 cgroup_context_free_blockio_device_bandwidth(c, b);
2783 n = strcspn(rvalue, WHITESPACE);
2784 bandwidth = rvalue + n;
2785 bandwidth += strspn(bandwidth, WHITESPACE);
2788 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2789 "Expected space separated pair of device node and bandwidth. Ignoring.");
2793 path = strndup(rvalue, n);
2797 if (!path_startswith(path, "/dev")) {
2798 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2799 "Invalid device node path '%s'. Ignoring.", path);
2803 r = parse_size(bandwidth, 1000, &bytes);
2804 if (r < 0 || bytes <= 0) {
2805 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2809 b = new0(CGroupBlockIODeviceBandwidth, 1);
2815 b->bandwidth = (uint64_t) bytes;
2818 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2823 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2825 int config_parse_job_mode_isolate(
2827 const char *filename,
2829 const char *section,
2830 unsigned section_line,
2844 r = parse_boolean(rvalue);
2846 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2850 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2854 int config_parse_personality(
2856 const char *filename,
2858 const char *section,
2859 unsigned section_line,
2866 unsigned long *personality = data, p;
2871 assert(personality);
2873 p = personality_from_string(rvalue);
2874 if (p == 0xffffffffUL) {
2875 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2876 "Failed to parse personality, ignoring: %s", rvalue);
2884 int config_parse_runtime_directory(
2886 const char *filename,
2888 const char *section,
2889 unsigned section_line,
2896 char***rt = data, *w, *state;
2905 if (isempty(rvalue)) {
2906 /* Empty assignment resets the list */
2912 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2913 _cleanup_free_ char *n;
2919 if (!filename_is_safe(n)) {
2920 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2924 r = strv_push(rt, n);
2934 int config_parse_set_status(
2936 const char *filename,
2938 const char *section,
2939 unsigned section_line,
2950 ExitStatusSet *status_set = data;
2957 if (isempty(rvalue)) {
2958 /* Empty assignment resets the list */
2960 set_free(status_set->signal);
2961 set_free(status_set->code);
2963 status_set->signal = status_set->code = NULL;
2967 FOREACH_WORD(w, l, rvalue, state) {
2968 _cleanup_free_ char *temp;
2971 temp = strndup(w, l);
2975 r = safe_atoi(temp, &val);
2977 val = signal_from_string_try_harder(temp);
2980 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
2984 r = set_put(status_set->signal, INT_TO_PTR(val));
2986 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2990 log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", w);
2994 if (val < 0 || val > 255)
2995 log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
2997 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
3001 r = set_put(status_set->code, INT_TO_PTR(val));
3003 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
3013 int config_parse_namespace_path_strv(
3015 const char *filename,
3017 const char *section,
3018 unsigned section_line,
3025 char*** sv = data, *w, *state;
3034 if (isempty(rvalue)) {
3035 /* Empty assignment resets the list */
3041 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
3042 _cleanup_free_ char *n;
3049 if (!utf8_is_valid(n)) {
3050 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3054 offset = n[0] == '-';
3055 if (!path_is_absolute(n + offset)) {
3056 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
3060 path_kill_slashes(n);
3062 r = strv_push(sv, n);
3072 int config_parse_no_new_privileges(
3074 const char *filename,
3076 const char *section,
3077 unsigned section_line,
3084 ExecContext *c = data;
3092 k = parse_boolean(rvalue);
3094 log_syntax(unit, LOG_ERR, filename, line, -k, "Failed to parse boolean value, ignoring: %s", rvalue);
3098 c->no_new_privileges = !!k;
3099 c->no_new_privileges_set = true;
3104 int config_parse_protected_home(
3106 const char *filename,
3108 const char *section,
3109 unsigned section_line,
3116 ExecContext *c = data;
3124 /* Our enum shall be a superset of booleans, hence first try
3125 * to parse as as boolean, and then as enum */
3127 k = parse_boolean(rvalue);
3129 c->protected_home = PROTECTED_HOME_YES;
3131 c->protected_home = PROTECTED_HOME_NO;
3135 h = protected_home_from_string(rvalue);
3137 log_syntax(unit, LOG_ERR, filename, line, -h, "Failed to parse protected home value, ignoring: %s", rvalue);
3141 c->protected_home = h;
3147 #define FOLLOW_MAX 8
3149 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3160 /* This will update the filename pointer if the loaded file is
3161 * reached by a symlink. The old string will be freed. */
3164 char *target, *name;
3166 if (c++ >= FOLLOW_MAX)
3169 path_kill_slashes(*filename);
3171 /* Add the file name we are currently looking at to
3172 * the names of this unit, but only if it is a valid
3174 name = basename(*filename);
3176 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3178 id = set_get(names, name);
3184 r = set_consume(names, id);
3190 /* Try to open the file name, but don't if its a symlink */
3191 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3198 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3199 r = readlink_and_make_absolute(*filename, &target);
3207 f = fdopen(fd, "re");
3219 static int merge_by_names(Unit **u, Set *names, const char *id) {
3227 /* Let's try to add in all symlink names we found */
3228 while ((k = set_steal_first(names))) {
3230 /* First try to merge in the other name into our
3232 r = unit_merge_by_name(*u, k);
3236 /* Hmm, we couldn't merge the other unit into
3237 * ours? Then let's try it the other way
3240 other = manager_get_unit((*u)->manager, k);
3244 r = unit_merge(other, *u);
3247 return merge_by_names(u, names, NULL);
3255 unit_choose_id(*u, id);
3263 static int load_from_path(Unit *u, const char *path) {
3265 _cleanup_set_free_free_ Set *symlink_names = NULL;
3266 _cleanup_fclose_ FILE *f = NULL;
3267 _cleanup_free_ char *filename = NULL;
3275 symlink_names = set_new(string_hash_func, string_compare_func);
3279 if (path_is_absolute(path)) {
3281 filename = strdup(path);
3285 r = open_follow(&filename, &f, symlink_names, &id);
3297 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3299 /* Instead of opening the path right away, we manually
3300 * follow all symlinks and add their name to our unit
3301 * name set while doing so */
3302 filename = path_make_absolute(path, *p);
3306 if (u->manager->unit_path_cache &&
3307 !set_get(u->manager->unit_path_cache, filename))
3310 r = open_follow(&filename, &f, symlink_names, &id);
3319 /* Empty the symlink names for the next run */
3320 set_clear_free(symlink_names);
3329 /* Hmm, no suitable file found? */
3333 r = merge_by_names(&merged, symlink_names, id);
3338 u->load_state = UNIT_MERGED;
3342 if (fstat(fileno(f), &st) < 0)
3345 if (null_or_empty(&st))
3346 u->load_state = UNIT_MASKED;
3348 u->load_state = UNIT_LOADED;
3350 /* Now, parse the file contents */
3351 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
3352 config_item_perf_lookup,
3353 (void*) load_fragment_gperf_lookup, false, true, u);
3358 free(u->fragment_path);
3359 u->fragment_path = filename;
3362 u->fragment_mtime = timespec_load(&st.st_mtim);
3364 if (u->source_path) {
3365 if (stat(u->source_path, &st) >= 0)
3366 u->source_mtime = timespec_load(&st.st_mtim);
3368 u->source_mtime = 0;
3374 int unit_load_fragment(Unit *u) {
3380 assert(u->load_state == UNIT_STUB);
3383 /* First, try to find the unit under its id. We always look
3384 * for unit files in the default directories, to make it easy
3385 * to override things by placing things in /etc/systemd/system */
3386 r = load_from_path(u, u->id);
3390 /* Try to find an alias we can load this with */
3391 if (u->load_state == UNIT_STUB)
3392 SET_FOREACH(t, u->names, i) {
3397 r = load_from_path(u, t);
3401 if (u->load_state != UNIT_STUB)
3405 /* And now, try looking for it under the suggested (originally linked) path */
3406 if (u->load_state == UNIT_STUB && u->fragment_path) {
3408 r = load_from_path(u, u->fragment_path);
3412 if (u->load_state == UNIT_STUB) {
3413 /* Hmm, this didn't work? Then let's get rid
3414 * of the fragment path stored for us, so that
3415 * we don't point to an invalid location. */
3416 free(u->fragment_path);
3417 u->fragment_path = NULL;
3421 /* Look for a template */
3422 if (u->load_state == UNIT_STUB && u->instance) {
3423 _cleanup_free_ char *k;
3425 k = unit_name_template(u->id);
3429 r = load_from_path(u, k);
3433 if (u->load_state == UNIT_STUB)
3434 SET_FOREACH(t, u->names, i) {
3435 _cleanup_free_ char *z = NULL;
3440 z = unit_name_template(t);
3444 r = load_from_path(u, z);
3448 if (u->load_state != UNIT_STUB)
3456 void unit_dump_config_items(FILE *f) {
3457 static const struct {
3458 const ConfigParserCallback callback;
3461 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3462 { config_parse_warn_compat, "NOTSUPPORTED" },
3464 { config_parse_int, "INTEGER" },
3465 { config_parse_unsigned, "UNSIGNED" },
3466 { config_parse_iec_size, "SIZE" },
3467 { config_parse_iec_off, "SIZE" },
3468 { config_parse_si_size, "SIZE" },
3469 { config_parse_bool, "BOOLEAN" },
3470 { config_parse_string, "STRING" },
3471 { config_parse_path, "PATH" },
3472 { config_parse_unit_path_printf, "PATH" },
3473 { config_parse_strv, "STRING [...]" },
3474 { config_parse_exec_nice, "NICE" },
3475 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3476 { config_parse_exec_io_class, "IOCLASS" },
3477 { config_parse_exec_io_priority, "IOPRIORITY" },
3478 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3479 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3480 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3481 { config_parse_mode, "MODE" },
3482 { config_parse_unit_env_file, "FILE" },
3483 { config_parse_output, "OUTPUT" },
3484 { config_parse_input, "INPUT" },
3485 { config_parse_log_facility, "FACILITY" },
3486 { config_parse_log_level, "LEVEL" },
3487 { config_parse_exec_capabilities, "CAPABILITIES" },
3488 { config_parse_exec_secure_bits, "SECUREBITS" },
3489 { config_parse_bounding_set, "BOUNDINGSET" },
3490 { config_parse_limit, "LIMIT" },
3491 { config_parse_unit_deps, "UNIT [...]" },
3492 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3493 { config_parse_service_type, "SERVICETYPE" },
3494 { config_parse_service_restart, "SERVICERESTART" },
3495 #ifdef HAVE_SYSV_COMPAT
3496 { config_parse_sysv_priority, "SYSVPRIORITY" },
3498 { config_parse_kill_mode, "KILLMODE" },
3499 { config_parse_kill_signal, "SIGNAL" },
3500 { config_parse_socket_listen, "SOCKET [...]" },
3501 { config_parse_socket_bind, "SOCKETBIND" },
3502 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3503 { config_parse_sec, "SECONDS" },
3504 { config_parse_nsec, "NANOSECONDS" },
3505 { config_parse_namespace_path_strv, "PATH [...]" },
3506 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3507 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3508 { config_parse_unit_string_printf, "STRING" },
3509 { config_parse_trigger_unit, "UNIT" },
3510 { config_parse_timer, "TIMER" },
3511 { config_parse_path_spec, "PATH" },
3512 { config_parse_notify_access, "ACCESS" },
3513 { config_parse_ip_tos, "TOS" },
3514 { config_parse_unit_condition_path, "CONDITION" },
3515 { config_parse_unit_condition_string, "CONDITION" },
3516 { config_parse_unit_condition_null, "CONDITION" },
3517 { config_parse_unit_slice, "SLICE" },
3518 { config_parse_documentation, "URL" },
3519 { config_parse_service_timeout, "SECONDS" },
3520 { config_parse_failure_action, "ACTION" },
3521 { config_parse_set_status, "STATUS" },
3522 { config_parse_service_sockets, "SOCKETS" },
3523 { config_parse_environ, "ENVIRON" },
3525 { config_parse_syscall_filter, "SYSCALLS" },
3526 { config_parse_syscall_archs, "ARCHS" },
3527 { config_parse_syscall_errno, "ERRNO" },
3528 { config_parse_address_families, "FAMILIES" },
3530 { config_parse_cpu_shares, "SHARES" },
3531 { config_parse_memory_limit, "LIMIT" },
3532 { config_parse_device_allow, "DEVICE" },
3533 { config_parse_device_policy, "POLICY" },
3534 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3535 { config_parse_blockio_weight, "WEIGHT" },
3536 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3537 { config_parse_long, "LONG" },
3538 { config_parse_socket_service, "SERVICE" },
3540 { config_parse_exec_selinux_context, "LABEL" },
3542 { config_parse_job_mode, "MODE" },
3543 { config_parse_job_mode_isolate, "BOOLEAN" },
3544 { config_parse_personality, "PERSONALITY" },
3547 const char *prev = NULL;
3552 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3553 const char *rvalue = "OTHER", *lvalue;
3557 const ConfigPerfItem *p;
3559 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3561 dot = strchr(i, '.');
3562 lvalue = dot ? dot + 1 : i;
3566 if (!prev || !strneq(prev, i, prefix_len+1)) {
3570 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3573 for (j = 0; j < ELEMENTSOF(table); j++)
3574 if (p->parse == table[j].callback) {
3575 rvalue = table[j].rvalue;
3579 fprintf(f, "%s=%s\n", lvalue, rvalue);