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 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, busname_policy_access, BusNamePolicyAccess, "Failed to parse bus name policy access");
1661 int config_parse_bus_policy(
1663 const char *filename,
1665 const char *section,
1666 unsigned section_line,
1673 _cleanup_free_ BusNamePolicy *p = NULL;
1674 _cleanup_free_ char *id_str = NULL;
1675 BusName *busname = data;
1683 p = new0(BusNamePolicy, 1);
1687 if (streq(lvalue, "AllowUser"))
1688 p->type = BUSNAME_POLICY_TYPE_USER;
1689 else if (streq(lvalue, "AllowGroup"))
1690 p->type = BUSNAME_POLICY_TYPE_GROUP;
1692 assert_not_reached("Unknown lvalue");
1694 id_str = strdup(rvalue);
1698 access_str = strpbrk(id_str, WHITESPACE);
1700 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy value '%s'", rvalue);
1706 access_str += strspn(access_str, WHITESPACE);
1708 p->access = busname_policy_access_from_string(access_str);
1709 if (p->access < 0) {
1710 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy access type '%s'", access_str);
1717 LIST_PREPEND(policy, busname->policy, p);
1723 int config_parse_unit_env_file(const char *unit,
1724 const char *filename,
1726 const char *section,
1727 unsigned section_line,
1736 _cleanup_free_ char *n = NULL;
1745 if (isempty(rvalue)) {
1746 /* Empty assignment frees the list */
1752 r = unit_full_printf(u, rvalue, &n);
1754 log_syntax(unit, LOG_ERR, filename, line, r,
1755 "Failed to resolve specifiers, ignoring: %s", rvalue);
1758 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1759 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1760 "Path '%s' is not absolute, ignoring.", s);
1764 r = strv_extend(env, s);
1771 int config_parse_environ(const char *unit,
1772 const char *filename,
1774 const char *section,
1775 unsigned section_line,
1783 char*** env = data, *w, *state;
1785 _cleanup_free_ char *k = NULL;
1793 if (isempty(rvalue)) {
1794 /* Empty assignment resets the list */
1801 r = unit_full_printf(u, rvalue, &k);
1803 log_syntax(unit, LOG_ERR, filename, line, -r,
1804 "Failed to resolve specifiers, ignoring: %s", rvalue);
1812 FOREACH_WORD_QUOTED(w, l, k, state) {
1813 _cleanup_free_ char *n;
1816 n = cunescape_length(w, l);
1820 if (!env_assignment_is_valid(n)) {
1821 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1822 "Invalid environment assignment, ignoring: %s", rvalue);
1826 x = strv_env_set(*env, n);
1837 int config_parse_ip_tos(const char *unit,
1838 const char *filename,
1840 const char *section,
1841 unsigned section_line,
1848 int *ip_tos = data, x;
1855 x = ip_tos_from_string(rvalue);
1857 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1858 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1866 int config_parse_unit_condition_path(const char *unit,
1867 const char *filename,
1869 const char *section,
1870 unsigned section_line,
1877 ConditionType cond = ltype;
1879 bool trigger, negate;
1881 _cleanup_free_ char *p = NULL;
1889 if (isempty(rvalue)) {
1890 /* Empty assignment resets the list */
1891 condition_free_list(u->conditions);
1892 u->conditions = NULL;
1896 trigger = rvalue[0] == '|';
1900 negate = rvalue[0] == '!';
1904 r = unit_full_printf(u, rvalue, &p);
1906 log_syntax(unit, LOG_ERR, filename, line, -r,
1907 "Failed to resolve specifiers, ignoring: %s", rvalue);
1914 if (!path_is_absolute(p)) {
1915 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1916 "Path in condition not absolute, ignoring: %s", p);
1920 c = condition_new(cond, p, trigger, negate);
1924 LIST_PREPEND(conditions, u->conditions, c);
1928 int config_parse_unit_condition_string(const char *unit,
1929 const char *filename,
1931 const char *section,
1932 unsigned section_line,
1939 ConditionType cond = ltype;
1941 bool trigger, negate;
1943 _cleanup_free_ char *s = NULL;
1951 if (isempty(rvalue)) {
1952 /* Empty assignment resets the list */
1953 condition_free_list(u->conditions);
1954 u->conditions = NULL;
1958 trigger = rvalue[0] == '|';
1962 negate = rvalue[0] == '!';
1966 r = unit_full_printf(u, rvalue, &s);
1968 log_syntax(unit, LOG_ERR, filename, line, -r,
1969 "Failed to resolve specifiers, ignoring: %s", rvalue);
1976 c = condition_new(cond, s, trigger, negate);
1980 LIST_PREPEND(conditions, u->conditions, c);
1984 int config_parse_unit_condition_null(const char *unit,
1985 const char *filename,
1987 const char *section,
1988 unsigned section_line,
1997 bool trigger, negate;
2005 if (isempty(rvalue)) {
2006 /* Empty assignment resets the list */
2007 condition_free_list(u->conditions);
2008 u->conditions = NULL;
2012 trigger = rvalue[0] == '|';
2016 negate = rvalue[0] == '!';
2020 b = parse_boolean(rvalue);
2022 log_syntax(unit, LOG_ERR, filename, line, -b,
2023 "Failed to parse boolean value in condition, ignoring: %s",
2031 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2035 LIST_PREPEND(conditions, u->conditions, c);
2039 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2040 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2042 int config_parse_unit_requires_mounts_for(
2044 const char *filename,
2046 const char *section,
2047 unsigned section_line,
2064 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2066 _cleanup_free_ char *n;
2072 if (!utf8_is_valid(n)) {
2073 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2077 r = unit_require_mounts_for(u, n);
2079 log_syntax(unit, LOG_ERR, filename, line, r,
2080 "Failed to add required mount for, ignoring: %s", rvalue);
2088 int config_parse_documentation(const char *unit,
2089 const char *filename,
2091 const char *section,
2092 unsigned section_line,
2108 if (isempty(rvalue)) {
2109 /* Empty assignment resets the list */
2110 strv_free(u->documentation);
2111 u->documentation = NULL;
2115 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2116 rvalue, data, userdata);
2120 for (a = b = u->documentation; a && *a; a++) {
2122 if (is_valid_documentation_url(*a))
2125 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2126 "Invalid URL, ignoring: %s", *a);
2137 int config_parse_syscall_filter(
2139 const char *filename,
2141 const char *section,
2142 unsigned section_line,
2149 static const char default_syscalls[] =
2156 ExecContext *c = data;
2158 bool invert = false;
2168 if (isempty(rvalue)) {
2169 /* Empty assignment resets the list */
2170 set_free(c->syscall_filter);
2171 c->syscall_filter = NULL;
2172 c->syscall_whitelist = false;
2176 if (rvalue[0] == '~') {
2181 if (!c->syscall_filter) {
2182 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2183 if (!c->syscall_filter)
2187 /* Allow everything but the ones listed */
2188 c->syscall_whitelist = false;
2192 /* Allow nothing but the ones listed */
2193 c->syscall_whitelist = true;
2195 /* Accept default syscalls if we are on a whitelist */
2196 NULSTR_FOREACH(i, default_syscalls) {
2199 id = seccomp_syscall_resolve_name(i);
2203 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2212 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2213 _cleanup_free_ char *t = NULL;
2220 id = seccomp_syscall_resolve_name(t);
2222 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2226 /* If we previously wanted to forbid a syscall and now
2227 * we want to allow it, then remove it from the list
2229 if (!invert == c->syscall_whitelist) {
2230 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2236 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2239 /* Turn on NNP, but only if it wasn't configured explicitly
2240 * before, and only if we are in user mode. */
2241 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2242 c->no_new_privileges = true;
2247 int config_parse_syscall_archs(
2249 const char *filename,
2251 const char *section,
2252 unsigned section_line,
2264 if (isempty(rvalue)) {
2270 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2274 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2275 _cleanup_free_ char *t = NULL;
2282 r = seccomp_arch_from_string(t, &a);
2284 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2288 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2298 int config_parse_syscall_errno(
2300 const char *filename,
2302 const char *section,
2303 unsigned section_line,
2310 ExecContext *c = data;
2317 if (isempty(rvalue)) {
2318 /* Empty assignment resets to KILL */
2319 c->syscall_errno = 0;
2323 e = errno_from_name(rvalue);
2325 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2329 c->syscall_errno = e;
2333 int config_parse_address_families(
2335 const char *filename,
2337 const char *section,
2338 unsigned section_line,
2345 ExecContext *c = data;
2347 bool invert = false;
2357 if (isempty(rvalue)) {
2358 /* Empty assignment resets the list */
2359 set_free(c->address_families);
2360 c->address_families = NULL;
2361 c->address_families_whitelist = false;
2365 if (rvalue[0] == '~') {
2370 if (!c->address_families) {
2371 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2372 if (!c->address_families)
2375 c->address_families_whitelist = !invert;
2378 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2379 _cleanup_free_ char *t = NULL;
2386 af = af_from_name(t);
2388 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
2392 /* If we previously wanted to forbid an address family and now
2393 * we want to allow it, then remove it from the list
2395 if (!invert == c->address_families_whitelist) {
2396 r = set_put(c->address_families, INT_TO_PTR(af));
2402 set_remove(c->address_families, INT_TO_PTR(af));
2409 int config_parse_unit_slice(
2411 const char *filename,
2413 const char *section,
2414 unsigned section_line,
2421 _cleanup_free_ char *k = NULL;
2422 Unit *u = userdata, *slice;
2430 r = unit_name_printf(u, rvalue, &k);
2432 log_syntax(unit, LOG_ERR, filename, line, -r,
2433 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2440 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2442 log_syntax(unit, LOG_ERR, filename, line, -r,
2443 "Failed to load slice unit %s. Ignoring.", k);
2447 if (slice->type != UNIT_SLICE) {
2448 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2449 "Slice unit %s is not a slice. Ignoring.", k);
2453 unit_ref_set(&u->slice, slice);
2457 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2459 int config_parse_cpu_shares(
2461 const char *filename,
2463 const char *section,
2464 unsigned section_line,
2471 unsigned long *shares = data, lu;
2478 if (isempty(rvalue)) {
2479 *shares = (unsigned long) -1;
2483 r = safe_atolu(rvalue, &lu);
2484 if (r < 0 || lu <= 0) {
2485 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU shares '%s' invalid. Ignoring.", rvalue);
2493 int config_parse_cpu_quota(
2495 const char *filename,
2497 const char *section,
2498 unsigned section_line,
2505 CGroupContext *c = data;
2512 if (isempty(rvalue)) {
2513 c->cpu_quota_per_sec_usec = (usec_t) -1;
2517 if (!endswith(rvalue, "%")) {
2519 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2523 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2524 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' invalid. Ignoring.", rvalue);
2528 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2533 int config_parse_memory_limit(
2535 const char *filename,
2537 const char *section,
2538 unsigned section_line,
2545 CGroupContext *c = data;
2549 if (isempty(rvalue)) {
2550 c->memory_limit = (uint64_t) -1;
2554 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2556 r = parse_size(rvalue, 1024, &bytes);
2558 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
2562 c->memory_limit = (uint64_t) bytes;
2566 int config_parse_device_allow(
2568 const char *filename,
2570 const char *section,
2571 unsigned section_line,
2578 _cleanup_free_ char *path = NULL;
2579 CGroupContext *c = data;
2580 CGroupDeviceAllow *a;
2584 if (isempty(rvalue)) {
2585 while (c->device_allow)
2586 cgroup_context_free_device_allow(c, c->device_allow);
2591 n = strcspn(rvalue, WHITESPACE);
2592 path = strndup(rvalue, n);
2596 if (!startswith(path, "/dev/") &&
2597 !startswith(path, "block-") &&
2598 !startswith(path, "char-")) {
2599 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2603 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2607 if (!in_charset(m, "rwm")) {
2608 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
2612 a = new0(CGroupDeviceAllow, 1);
2618 a->r = !!strchr(m, 'r');
2619 a->w = !!strchr(m, 'w');
2620 a->m = !!strchr(m, 'm');
2622 LIST_PREPEND(device_allow, c->device_allow, a);
2626 int config_parse_blockio_weight(
2628 const char *filename,
2630 const char *section,
2631 unsigned section_line,
2638 unsigned long *weight = data, lu;
2645 if (isempty(rvalue)) {
2646 *weight = (unsigned long) -1;
2650 r = safe_atolu(rvalue, &lu);
2651 if (r < 0 || lu < 10 || lu > 1000) {
2652 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
2660 int config_parse_blockio_device_weight(
2662 const char *filename,
2664 const char *section,
2665 unsigned section_line,
2672 _cleanup_free_ char *path = NULL;
2673 CGroupBlockIODeviceWeight *w;
2674 CGroupContext *c = data;
2684 if (isempty(rvalue)) {
2685 while (c->blockio_device_weights)
2686 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2691 n = strcspn(rvalue, WHITESPACE);
2692 weight = rvalue + n;
2694 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Expected block device and device weight. Ignoring.");
2698 path = strndup(rvalue, n);
2702 if (!path_startswith(path, "/dev")) {
2703 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2707 weight += strspn(weight, WHITESPACE);
2708 r = safe_atolu(weight, &lu);
2709 if (r < 0 || lu < 10 || lu > 1000) {
2710 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
2714 w = new0(CGroupBlockIODeviceWeight, 1);
2723 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2727 int config_parse_blockio_bandwidth(
2729 const char *filename,
2731 const char *section,
2732 unsigned section_line,
2739 _cleanup_free_ char *path = NULL;
2740 CGroupBlockIODeviceBandwidth *b;
2741 CGroupContext *c = data;
2742 const char *bandwidth;
2752 read = streq("BlockIOReadBandwidth", lvalue);
2754 if (isempty(rvalue)) {
2755 CGroupBlockIODeviceBandwidth *next;
2757 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2758 if (b->read == read)
2759 cgroup_context_free_blockio_device_bandwidth(c, b);
2764 n = strcspn(rvalue, WHITESPACE);
2765 bandwidth = rvalue + n;
2766 bandwidth += strspn(bandwidth, WHITESPACE);
2769 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2770 "Expected space separated pair of device node and bandwidth. Ignoring.");
2774 path = strndup(rvalue, n);
2778 if (!path_startswith(path, "/dev")) {
2779 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2780 "Invalid device node path '%s'. Ignoring.", path);
2784 r = parse_size(bandwidth, 1000, &bytes);
2785 if (r < 0 || bytes <= 0) {
2786 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2790 b = new0(CGroupBlockIODeviceBandwidth, 1);
2796 b->bandwidth = (uint64_t) bytes;
2799 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2804 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2806 int config_parse_job_mode_isolate(
2808 const char *filename,
2810 const char *section,
2811 unsigned section_line,
2825 r = parse_boolean(rvalue);
2827 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2831 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2835 int config_parse_personality(
2837 const char *filename,
2839 const char *section,
2840 unsigned section_line,
2847 unsigned long *personality = data, p;
2852 assert(personality);
2854 p = personality_from_string(rvalue);
2855 if (p == 0xffffffffUL) {
2856 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2857 "Failed to parse personality, ignoring: %s", rvalue);
2865 int config_parse_runtime_directory(
2867 const char *filename,
2869 const char *section,
2870 unsigned section_line,
2877 char***rt = data, *w, *state;
2886 if (isempty(rvalue)) {
2887 /* Empty assignment resets the list */
2893 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2894 _cleanup_free_ char *n;
2900 if (!filename_is_safe(n)) {
2901 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2905 r = strv_push(rt, n);
2915 int config_parse_set_status(
2917 const char *filename,
2919 const char *section,
2920 unsigned section_line,
2931 ExitStatusSet *status_set = data;
2938 if (isempty(rvalue)) {
2939 /* Empty assignment resets the list */
2941 set_free(status_set->signal);
2942 set_free(status_set->code);
2944 status_set->signal = status_set->code = NULL;
2948 FOREACH_WORD(w, l, rvalue, state) {
2949 _cleanup_free_ char *temp;
2952 temp = strndup(w, l);
2956 r = safe_atoi(temp, &val);
2958 val = signal_from_string_try_harder(temp);
2961 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
2965 r = set_put(status_set->signal, INT_TO_PTR(val));
2967 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2971 log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", w);
2975 if (val < 0 || val > 255)
2976 log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
2978 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
2982 r = set_put(status_set->code, INT_TO_PTR(val));
2984 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2994 int config_parse_namespace_path_strv(
2996 const char *filename,
2998 const char *section,
2999 unsigned section_line,
3006 char*** sv = data, *w, *state;
3015 if (isempty(rvalue)) {
3016 /* Empty assignment resets the list */
3022 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
3023 _cleanup_free_ char *n;
3030 if (!utf8_is_valid(n)) {
3031 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3035 offset = n[0] == '-';
3036 if (!path_is_absolute(n + offset)) {
3037 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
3041 path_kill_slashes(n);
3043 r = strv_push(sv, n);
3053 int config_parse_no_new_privileges(
3055 const char *filename,
3057 const char *section,
3058 unsigned section_line,
3065 ExecContext *c = data;
3073 k = parse_boolean(rvalue);
3075 log_syntax(unit, LOG_ERR, filename, line, -k, "Failed to parse boolean value, ignoring: %s", rvalue);
3079 c->no_new_privileges = !!k;
3080 c->no_new_privileges_set = true;
3085 int config_parse_protect_home(
3087 const char *filename,
3089 const char *section,
3090 unsigned section_line,
3097 ExecContext *c = data;
3105 /* Our enum shall be a superset of booleans, hence first try
3106 * to parse as as boolean, and then as enum */
3108 k = parse_boolean(rvalue);
3110 c->protect_home = PROTECT_HOME_YES;
3112 c->protect_home = PROTECT_HOME_NO;
3116 h = protect_home_from_string(rvalue);
3118 log_syntax(unit, LOG_ERR, filename, line, -h, "Failed to parse protect home value, ignoring: %s", rvalue);
3122 c->protect_home = h;
3128 int config_parse_protect_system(
3130 const char *filename,
3132 const char *section,
3133 unsigned section_line,
3140 ExecContext *c = data;
3148 /* Our enum shall be a superset of booleans, hence first try
3149 * to parse as as boolean, and then as enum */
3151 k = parse_boolean(rvalue);
3153 c->protect_system = PROTECT_SYSTEM_YES;
3155 c->protect_system = PROTECT_SYSTEM_NO;
3159 s = protect_system_from_string(rvalue);
3161 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse protect system value, ignoring: %s", rvalue);
3165 c->protect_system = s;
3171 #define FOLLOW_MAX 8
3173 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3184 /* This will update the filename pointer if the loaded file is
3185 * reached by a symlink. The old string will be freed. */
3188 char *target, *name;
3190 if (c++ >= FOLLOW_MAX)
3193 path_kill_slashes(*filename);
3195 /* Add the file name we are currently looking at to
3196 * the names of this unit, but only if it is a valid
3198 name = basename(*filename);
3200 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3202 id = set_get(names, name);
3208 r = set_consume(names, id);
3214 /* Try to open the file name, but don't if its a symlink */
3215 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3222 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3223 r = readlink_and_make_absolute(*filename, &target);
3231 f = fdopen(fd, "re");
3243 static int merge_by_names(Unit **u, Set *names, const char *id) {
3251 /* Let's try to add in all symlink names we found */
3252 while ((k = set_steal_first(names))) {
3254 /* First try to merge in the other name into our
3256 r = unit_merge_by_name(*u, k);
3260 /* Hmm, we couldn't merge the other unit into
3261 * ours? Then let's try it the other way
3264 other = manager_get_unit((*u)->manager, k);
3268 r = unit_merge(other, *u);
3271 return merge_by_names(u, names, NULL);
3279 unit_choose_id(*u, id);
3287 static int load_from_path(Unit *u, const char *path) {
3289 _cleanup_set_free_free_ Set *symlink_names = NULL;
3290 _cleanup_fclose_ FILE *f = NULL;
3291 _cleanup_free_ char *filename = NULL;
3299 symlink_names = set_new(string_hash_func, string_compare_func);
3303 if (path_is_absolute(path)) {
3305 filename = strdup(path);
3309 r = open_follow(&filename, &f, symlink_names, &id);
3321 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3323 /* Instead of opening the path right away, we manually
3324 * follow all symlinks and add their name to our unit
3325 * name set while doing so */
3326 filename = path_make_absolute(path, *p);
3330 if (u->manager->unit_path_cache &&
3331 !set_get(u->manager->unit_path_cache, filename))
3334 r = open_follow(&filename, &f, symlink_names, &id);
3343 /* Empty the symlink names for the next run */
3344 set_clear_free(symlink_names);
3353 /* Hmm, no suitable file found? */
3357 r = merge_by_names(&merged, symlink_names, id);
3362 u->load_state = UNIT_MERGED;
3366 if (fstat(fileno(f), &st) < 0)
3369 if (null_or_empty(&st))
3370 u->load_state = UNIT_MASKED;
3372 u->load_state = UNIT_LOADED;
3374 /* Now, parse the file contents */
3375 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
3376 config_item_perf_lookup,
3377 (void*) load_fragment_gperf_lookup, false, true, u);
3382 free(u->fragment_path);
3383 u->fragment_path = filename;
3386 u->fragment_mtime = timespec_load(&st.st_mtim);
3388 if (u->source_path) {
3389 if (stat(u->source_path, &st) >= 0)
3390 u->source_mtime = timespec_load(&st.st_mtim);
3392 u->source_mtime = 0;
3398 int unit_load_fragment(Unit *u) {
3404 assert(u->load_state == UNIT_STUB);
3407 /* First, try to find the unit under its id. We always look
3408 * for unit files in the default directories, to make it easy
3409 * to override things by placing things in /etc/systemd/system */
3410 r = load_from_path(u, u->id);
3414 /* Try to find an alias we can load this with */
3415 if (u->load_state == UNIT_STUB)
3416 SET_FOREACH(t, u->names, i) {
3421 r = load_from_path(u, t);
3425 if (u->load_state != UNIT_STUB)
3429 /* And now, try looking for it under the suggested (originally linked) path */
3430 if (u->load_state == UNIT_STUB && u->fragment_path) {
3432 r = load_from_path(u, u->fragment_path);
3436 if (u->load_state == UNIT_STUB) {
3437 /* Hmm, this didn't work? Then let's get rid
3438 * of the fragment path stored for us, so that
3439 * we don't point to an invalid location. */
3440 free(u->fragment_path);
3441 u->fragment_path = NULL;
3445 /* Look for a template */
3446 if (u->load_state == UNIT_STUB && u->instance) {
3447 _cleanup_free_ char *k;
3449 k = unit_name_template(u->id);
3453 r = load_from_path(u, k);
3457 if (u->load_state == UNIT_STUB)
3458 SET_FOREACH(t, u->names, i) {
3459 _cleanup_free_ char *z = NULL;
3464 z = unit_name_template(t);
3468 r = load_from_path(u, z);
3472 if (u->load_state != UNIT_STUB)
3480 void unit_dump_config_items(FILE *f) {
3481 static const struct {
3482 const ConfigParserCallback callback;
3485 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3486 { config_parse_warn_compat, "NOTSUPPORTED" },
3488 { config_parse_int, "INTEGER" },
3489 { config_parse_unsigned, "UNSIGNED" },
3490 { config_parse_iec_size, "SIZE" },
3491 { config_parse_iec_off, "SIZE" },
3492 { config_parse_si_size, "SIZE" },
3493 { config_parse_bool, "BOOLEAN" },
3494 { config_parse_string, "STRING" },
3495 { config_parse_path, "PATH" },
3496 { config_parse_unit_path_printf, "PATH" },
3497 { config_parse_strv, "STRING [...]" },
3498 { config_parse_exec_nice, "NICE" },
3499 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3500 { config_parse_exec_io_class, "IOCLASS" },
3501 { config_parse_exec_io_priority, "IOPRIORITY" },
3502 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3503 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3504 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3505 { config_parse_mode, "MODE" },
3506 { config_parse_unit_env_file, "FILE" },
3507 { config_parse_output, "OUTPUT" },
3508 { config_parse_input, "INPUT" },
3509 { config_parse_log_facility, "FACILITY" },
3510 { config_parse_log_level, "LEVEL" },
3511 { config_parse_exec_capabilities, "CAPABILITIES" },
3512 { config_parse_exec_secure_bits, "SECUREBITS" },
3513 { config_parse_bounding_set, "BOUNDINGSET" },
3514 { config_parse_limit, "LIMIT" },
3515 { config_parse_unit_deps, "UNIT [...]" },
3516 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3517 { config_parse_service_type, "SERVICETYPE" },
3518 { config_parse_service_restart, "SERVICERESTART" },
3519 #ifdef HAVE_SYSV_COMPAT
3520 { config_parse_sysv_priority, "SYSVPRIORITY" },
3522 { config_parse_kill_mode, "KILLMODE" },
3523 { config_parse_kill_signal, "SIGNAL" },
3524 { config_parse_socket_listen, "SOCKET [...]" },
3525 { config_parse_socket_bind, "SOCKETBIND" },
3526 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3527 { config_parse_sec, "SECONDS" },
3528 { config_parse_nsec, "NANOSECONDS" },
3529 { config_parse_namespace_path_strv, "PATH [...]" },
3530 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3531 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3532 { config_parse_unit_string_printf, "STRING" },
3533 { config_parse_trigger_unit, "UNIT" },
3534 { config_parse_timer, "TIMER" },
3535 { config_parse_path_spec, "PATH" },
3536 { config_parse_notify_access, "ACCESS" },
3537 { config_parse_ip_tos, "TOS" },
3538 { config_parse_unit_condition_path, "CONDITION" },
3539 { config_parse_unit_condition_string, "CONDITION" },
3540 { config_parse_unit_condition_null, "CONDITION" },
3541 { config_parse_unit_slice, "SLICE" },
3542 { config_parse_documentation, "URL" },
3543 { config_parse_service_timeout, "SECONDS" },
3544 { config_parse_failure_action, "ACTION" },
3545 { config_parse_set_status, "STATUS" },
3546 { config_parse_service_sockets, "SOCKETS" },
3547 { config_parse_environ, "ENVIRON" },
3549 { config_parse_syscall_filter, "SYSCALLS" },
3550 { config_parse_syscall_archs, "ARCHS" },
3551 { config_parse_syscall_errno, "ERRNO" },
3552 { config_parse_address_families, "FAMILIES" },
3554 { config_parse_cpu_shares, "SHARES" },
3555 { config_parse_memory_limit, "LIMIT" },
3556 { config_parse_device_allow, "DEVICE" },
3557 { config_parse_device_policy, "POLICY" },
3558 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3559 { config_parse_blockio_weight, "WEIGHT" },
3560 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3561 { config_parse_long, "LONG" },
3562 { config_parse_socket_service, "SERVICE" },
3564 { config_parse_exec_selinux_context, "LABEL" },
3566 { config_parse_job_mode, "MODE" },
3567 { config_parse_job_mode_isolate, "BOOLEAN" },
3568 { config_parse_personality, "PERSONALITY" },
3571 const char *prev = NULL;
3576 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3577 const char *rvalue = "OTHER", *lvalue;
3581 const ConfigPerfItem *p;
3583 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3585 dot = strchr(i, '.');
3586 lvalue = dot ? dot + 1 : i;
3590 if (!prev || !strneq(prev, i, prefix_len+1)) {
3594 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3597 for (j = 0; j < ELEMENTSOF(table); j++)
3598 if (p->parse == table[j].callback) {
3599 rvalue = table[j].rvalue;
3603 fprintf(f, "%s=%s\n", lvalue, rvalue);