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 int config_parse_warn_compat(
72 unsigned section_line,
78 Disabled reason = ltype;
81 case DISABLED_CONFIGURATION:
82 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
83 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
86 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
87 "Support for option %s= has been removed and it is ignored", lvalue);
89 case DISABLED_EXPERIMENTAL:
90 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
91 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
98 int config_parse_unit_deps(const char *unit,
102 unsigned section_line,
109 UnitDependency d = ltype;
111 const char *word, *state;
118 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
119 _cleanup_free_ char *t = NULL, *k = NULL;
122 t = strndup(word, l);
126 r = unit_name_printf(u, t, &k);
128 log_syntax(unit, LOG_ERR, filename, line, -r,
129 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
133 r = unit_add_dependency_by_name(u, d, k, NULL, true);
135 log_syntax(unit, LOG_ERR, filename, line, -r,
136 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
139 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
144 int config_parse_unit_string_printf(const char *unit,
145 const char *filename,
148 unsigned section_line,
156 _cleanup_free_ char *k = NULL;
164 r = unit_full_printf(u, rvalue, &k);
166 log_syntax(unit, LOG_ERR, filename, line, -r,
167 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
169 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
170 k ? k : rvalue, data, userdata);
173 int config_parse_unit_strv_printf(const char *unit,
174 const char *filename,
177 unsigned section_line,
185 _cleanup_free_ char *k = NULL;
193 r = unit_full_printf(u, rvalue, &k);
195 log_syntax(unit, LOG_ERR, filename, line, -r,
196 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
198 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
199 k ? k : rvalue, data, userdata);
202 int config_parse_unit_path_printf(const char *unit,
203 const char *filename,
206 unsigned section_line,
213 _cleanup_free_ char *k = NULL;
222 r = unit_full_printf(u, rvalue, &k);
224 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
228 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
231 int config_parse_unit_path_strv_printf(
233 const char *filename,
236 unsigned section_line,
244 const char *word, *state;
254 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
255 _cleanup_free_ char *k = NULL;
261 r = unit_full_printf(u, t, &k);
263 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
267 if (!utf8_is_valid(k)) {
268 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
272 if (!path_is_absolute(k)) {
273 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
277 path_kill_slashes(k);
286 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
291 int config_parse_socket_listen(const char *unit,
292 const char *filename,
295 unsigned section_line,
302 _cleanup_free_ SocketPort *p = NULL;
314 if (isempty(rvalue)) {
315 /* An empty assignment removes all ports */
316 socket_free_ports(s);
320 p = new0(SocketPort, 1);
324 if (ltype != SOCKET_SOCKET) {
327 r = unit_full_printf(UNIT(s), rvalue, &p->path);
329 p->path = strdup(rvalue);
333 log_syntax(unit, LOG_ERR, filename, line, -r,
334 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
337 path_kill_slashes(p->path);
339 } else if (streq(lvalue, "ListenNetlink")) {
340 _cleanup_free_ char *k = NULL;
342 p->type = SOCKET_SOCKET;
343 r = unit_full_printf(UNIT(s), rvalue, &k);
345 log_syntax(unit, LOG_ERR, filename, line, -r,
346 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
348 r = socket_address_parse_netlink(&p->address, k ?: rvalue);
350 log_syntax(unit, LOG_ERR, filename, line, -r,
351 "Failed to parse address value, ignoring: %s", rvalue);
356 _cleanup_free_ char *k = NULL;
358 p->type = SOCKET_SOCKET;
359 r = unit_full_printf(UNIT(s), rvalue, &k);
361 log_syntax(unit, LOG_ERR, filename, line, -r,
362 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
364 r = socket_address_parse(&p->address, k ? k : rvalue);
366 log_syntax(unit, LOG_ERR, filename, line, -r,
367 "Failed to parse address value, ignoring: %s", rvalue);
371 if (streq(lvalue, "ListenStream"))
372 p->address.type = SOCK_STREAM;
373 else if (streq(lvalue, "ListenDatagram"))
374 p->address.type = SOCK_DGRAM;
376 assert(streq(lvalue, "ListenSequentialPacket"));
377 p->address.type = SOCK_SEQPACKET;
380 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
381 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
382 "Address family not supported, ignoring: %s", rvalue);
391 LIST_FIND_TAIL(port, s->ports, tail);
392 LIST_INSERT_AFTER(port, s->ports, tail, p);
394 LIST_PREPEND(port, s->ports, p);
400 int config_parse_socket_bind(const char *unit,
401 const char *filename,
404 unsigned section_line,
412 SocketAddressBindIPv6Only b;
421 b = socket_address_bind_ipv6_only_from_string(rvalue);
425 r = parse_boolean(rvalue);
427 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
428 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
432 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
434 s->bind_ipv6_only = b;
439 int config_parse_exec_nice(const char *unit,
440 const char *filename,
443 unsigned section_line,
450 ExecContext *c = data;
458 r = safe_atoi(rvalue, &priority);
460 log_syntax(unit, LOG_ERR, filename, line, -r,
461 "Failed to parse nice priority, ignoring: %s. ", rvalue);
465 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
466 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
467 "Nice priority out of range, ignoring: %s", rvalue);
477 int config_parse_exec_oom_score_adjust(const char* unit,
478 const char *filename,
481 unsigned section_line,
488 ExecContext *c = data;
496 r = safe_atoi(rvalue, &oa);
498 log_syntax(unit, LOG_ERR, filename, line, -r,
499 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
503 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
504 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
505 "OOM score adjust value out of range, ignoring: %s", rvalue);
509 c->oom_score_adjust = oa;
510 c->oom_score_adjust_set = true;
515 int config_parse_exec(const char *unit,
516 const char *filename,
519 unsigned section_line,
526 ExecCommand **e = data, *nce;
538 if (isempty(rvalue)) {
539 /* An empty assignment resets the list */
540 exec_command_free_list(*e);
545 /* We accept an absolute path as first argument, or
546 * alternatively an absolute prefixed with @ to allow
547 * overriding of argv[0]. */
550 const char *word, *state;
552 bool honour_argv0 = false, ignore = false;
558 rvalue += strspn(rvalue, WHITESPACE);
563 for (i = 0; i < 2; i++) {
564 if (rvalue[0] == '-' && !ignore) {
569 if (rvalue[0] == '@' && !honour_argv0) {
575 if (*rvalue != '/') {
576 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
577 "Executable path is not absolute, ignoring: %s", rvalue);
582 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
583 if (strneq(word, ";", MAX(l, 1U)))
588 if (!isempty(state)) {
589 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
590 "Trailing garbage, ignoring.");
595 n = new(char*, k + !honour_argv0);
600 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
601 if (strneq(word, ";", MAX(l, 1U)))
603 else if (strneq(word, "\\;", MAX(l, 1U)))
606 if (honour_argv0 && word == rvalue) {
609 path = strndup(word, l);
615 if (!utf8_is_valid(path)) {
616 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
624 c = n[k++] = cunescape_length(word, l);
630 if (!utf8_is_valid(c)) {
631 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
641 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
642 "Invalid command line, ignoring: %s", rvalue);
655 assert(path_is_absolute(path));
657 nce = new0(ExecCommand, 1);
665 nce->ignore = ignore;
667 path_kill_slashes(nce->path);
669 exec_command_append_list(e, nce);
685 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
686 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
688 int config_parse_socket_bindtodevice(const char* unit,
689 const char *filename,
692 unsigned section_line,
707 if (rvalue[0] && !streq(rvalue, "*")) {
714 free(s->bind_to_device);
715 s->bind_to_device = n;
720 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
721 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
723 int config_parse_exec_io_class(const char *unit,
724 const char *filename,
727 unsigned section_line,
734 ExecContext *c = data;
742 x = ioprio_class_from_string(rvalue);
744 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
745 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
749 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
750 c->ioprio_set = true;
755 int config_parse_exec_io_priority(const char *unit,
756 const char *filename,
759 unsigned section_line,
766 ExecContext *c = data;
774 r = safe_atoi(rvalue, &i);
775 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
776 log_syntax(unit, LOG_ERR, filename, line, -r,
777 "Failed to parse IO priority, ignoring: %s", rvalue);
781 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
782 c->ioprio_set = true;
787 int config_parse_exec_cpu_sched_policy(const char *unit,
788 const char *filename,
791 unsigned section_line,
799 ExecContext *c = data;
807 x = sched_policy_from_string(rvalue);
809 log_syntax(unit, LOG_ERR, filename, line, -x,
810 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
814 c->cpu_sched_policy = x;
815 /* Moving to or from real-time policy? We need to adjust the priority */
816 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
817 c->cpu_sched_set = true;
822 int config_parse_exec_cpu_sched_prio(const char *unit,
823 const char *filename,
826 unsigned section_line,
833 ExecContext *c = data;
841 r = safe_atoi(rvalue, &i);
843 log_syntax(unit, LOG_ERR, filename, line, -r,
844 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
848 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
849 min = sched_get_priority_min(c->cpu_sched_policy);
850 max = sched_get_priority_max(c->cpu_sched_policy);
852 if (i < min || i > max) {
853 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
854 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
858 c->cpu_sched_priority = i;
859 c->cpu_sched_set = true;
864 int config_parse_exec_cpu_affinity(const char *unit,
865 const char *filename,
868 unsigned section_line,
875 ExecContext *c = data;
876 const char *word, *state;
884 if (isempty(rvalue)) {
885 /* An empty assignment resets the CPU list */
892 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
893 _cleanup_free_ char *t = NULL;
897 t = strndup(word, l);
901 r = safe_atou(t, &cpu);
904 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
909 if (r < 0 || cpu >= c->cpuset_ncpus) {
910 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
911 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
915 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
918 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
919 "Trailing garbage, ignoring.");
924 int config_parse_exec_capabilities(const char *unit,
925 const char *filename,
928 unsigned section_line,
935 ExecContext *c = data;
943 cap = cap_from_text(rvalue);
945 log_syntax(unit, LOG_ERR, filename, line, errno,
946 "Failed to parse capabilities, ignoring: %s", rvalue);
951 cap_free(c->capabilities);
952 c->capabilities = cap;
957 int config_parse_exec_secure_bits(const char *unit,
958 const char *filename,
961 unsigned section_line,
968 ExecContext *c = data;
970 const char *word, *state;
977 if (isempty(rvalue)) {
978 /* An empty assignment resets the field */
983 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
984 if (first_word(word, "keep-caps"))
985 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
986 else if (first_word(word, "keep-caps-locked"))
987 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
988 else if (first_word(word, "no-setuid-fixup"))
989 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
990 else if (first_word(word, "no-setuid-fixup-locked"))
991 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
992 else if (first_word(word, "noroot"))
993 c->secure_bits |= 1<<SECURE_NOROOT;
994 else if (first_word(word, "noroot-locked"))
995 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
997 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
998 "Failed to parse secure bits, ignoring: %s", rvalue);
1002 if (!isempty(state))
1003 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1004 "Invalid syntax, garbage at the end, ignoring.");
1009 int config_parse_bounding_set(const char *unit,
1010 const char *filename,
1012 const char *section,
1013 unsigned section_line,
1020 uint64_t *capability_bounding_set_drop = data;
1021 const char *word, *state;
1023 bool invert = false;
1031 if (rvalue[0] == '~') {
1036 /* Note that we store this inverted internally, since the
1037 * kernel wants it like this. But we actually expose it
1038 * non-inverted everywhere to have a fully normalized
1041 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1042 _cleanup_free_ char *t = NULL;
1046 t = strndup(word, l);
1050 r = cap_from_name(t, &cap);
1052 log_syntax(unit, LOG_ERR, filename, line, errno,
1053 "Failed to parse capability in bounding set, ignoring: %s", t);
1057 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1059 if (!isempty(state))
1060 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1061 "Trailing garbage, ignoring.");
1064 *capability_bounding_set_drop |= sum;
1066 *capability_bounding_set_drop |= ~sum;
1071 int config_parse_limit(const char *unit,
1072 const char *filename,
1074 const char *section,
1075 unsigned section_line,
1082 struct rlimit **rl = data;
1083 unsigned long long u;
1092 if (streq(rvalue, "infinity"))
1093 u = (unsigned long long) RLIM_INFINITY;
1097 r = safe_atollu(rvalue, &u);
1099 log_syntax(unit, LOG_ERR, filename, line, -r,
1100 "Failed to parse resource value, ignoring: %s", rvalue);
1106 *rl = new(struct rlimit, 1);
1111 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1115 #ifdef HAVE_SYSV_COMPAT
1116 int config_parse_sysv_priority(const char *unit,
1117 const char *filename,
1119 const char *section,
1120 unsigned section_line,
1127 int *priority = data;
1135 r = safe_atoi(rvalue, &i);
1136 if (r < 0 || i < 0) {
1137 log_syntax(unit, LOG_ERR, filename, line, -r,
1138 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1142 *priority = (int) i;
1147 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1149 int config_parse_kill_signal(const char *unit,
1150 const char *filename,
1152 const char *section,
1153 unsigned section_line,
1168 r = signal_from_string_try_harder(rvalue);
1170 log_syntax(unit, LOG_ERR, filename, line, -r,
1171 "Failed to parse kill signal, ignoring: %s", rvalue);
1179 int config_parse_exec_mount_flags(const char *unit,
1180 const char *filename,
1182 const char *section,
1183 unsigned section_line,
1190 ExecContext *c = data;
1191 const char *word, *state;
1193 unsigned long flags = 0;
1200 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1201 _cleanup_free_ char *t;
1203 t = strndup(word, l);
1207 if (streq(t, "shared"))
1209 else if (streq(t, "slave"))
1211 else if (streq(word, "private"))
1214 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1215 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1219 if (!isempty(state))
1220 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1221 "Trailing garbage, ignoring.");
1223 c->mount_flags = flags;
1227 int config_parse_exec_selinux_context(
1229 const char *filename,
1231 const char *section,
1232 unsigned section_line,
1239 ExecContext *c = data;
1250 if (isempty(rvalue)) {
1251 free(c->selinux_context);
1252 c->selinux_context = NULL;
1253 c->selinux_context_ignore = false;
1257 if (rvalue[0] == '-') {
1263 r = unit_name_printf(u, rvalue, &k);
1265 log_syntax(unit, LOG_ERR, filename, line, -r,
1266 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1270 free(c->selinux_context);
1271 c->selinux_context = k;
1272 c->selinux_context_ignore = ignore;
1277 int config_parse_exec_apparmor_profile(
1279 const char *filename,
1281 const char *section,
1282 unsigned section_line,
1289 ExecContext *c = data;
1300 if (isempty(rvalue)) {
1301 free(c->apparmor_profile);
1302 c->apparmor_profile = NULL;
1303 c->apparmor_profile_ignore = false;
1307 if (rvalue[0] == '-') {
1313 r = unit_name_printf(u, rvalue, &k);
1315 log_syntax(unit, LOG_ERR, filename, line, -r,
1316 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1320 free(c->apparmor_profile);
1321 c->apparmor_profile = k;
1322 c->apparmor_profile_ignore = ignore;
1327 int config_parse_exec_smack_process_label(
1329 const char *filename,
1331 const char *section,
1332 unsigned section_line,
1339 ExecContext *c = data;
1350 if (isempty(rvalue)) {
1351 free(c->smack_process_label);
1352 c->smack_process_label = NULL;
1353 c->smack_process_label_ignore = false;
1357 if (rvalue[0] == '-') {
1363 r = unit_name_printf(u, rvalue, &k);
1365 log_syntax(unit, LOG_ERR, filename, line, -r,
1366 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1370 free(c->smack_process_label);
1371 c->smack_process_label = k;
1372 c->smack_process_label_ignore = ignore;
1377 int config_parse_timer(const char *unit,
1378 const char *filename,
1380 const char *section,
1381 unsigned section_line,
1392 CalendarSpec *c = NULL;
1399 if (isempty(rvalue)) {
1400 /* Empty assignment resets list */
1401 timer_free_values(t);
1405 b = timer_base_from_string(lvalue);
1407 log_syntax(unit, LOG_ERR, filename, line, -b,
1408 "Failed to parse timer base, ignoring: %s", lvalue);
1412 if (b == TIMER_CALENDAR) {
1413 if (calendar_spec_from_string(rvalue, &c) < 0) {
1414 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1415 "Failed to parse calendar specification, ignoring: %s",
1420 if (parse_sec(rvalue, &u) < 0) {
1421 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1422 "Failed to parse timer value, ignoring: %s",
1428 v = new0(TimerValue, 1);
1430 calendar_spec_free(c);
1436 v->calendar_spec = c;
1438 LIST_PREPEND(value, t->values, v);
1443 int config_parse_trigger_unit(
1445 const char *filename,
1447 const char *section,
1448 unsigned section_line,
1455 _cleanup_free_ char *p = NULL;
1465 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1466 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1467 "Multiple units to trigger specified, ignoring: %s", rvalue);
1471 r = unit_name_printf(u, rvalue, &p);
1473 log_syntax(unit, LOG_ERR, filename, line, -r,
1474 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1476 type = unit_name_to_type(p ?: rvalue);
1478 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1479 "Unit type not valid, ignoring: %s", rvalue);
1483 if (type == u->type) {
1484 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1485 "Trigger cannot be of same type, ignoring: %s", rvalue);
1489 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1491 log_syntax(unit, LOG_ERR, filename, line, -r,
1492 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1499 int config_parse_path_spec(const char *unit,
1500 const char *filename,
1502 const char *section,
1503 unsigned section_line,
1513 _cleanup_free_ char *k = NULL;
1521 if (isempty(rvalue)) {
1522 /* Empty assignment clears list */
1527 b = path_type_from_string(lvalue);
1529 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1530 "Failed to parse path type, ignoring: %s", lvalue);
1534 r = unit_full_printf(UNIT(p), rvalue, &k);
1540 log_syntax(unit, LOG_ERR, filename, line, -r,
1541 "Failed to resolve unit specifiers on %s. Ignoring.",
1545 if (!path_is_absolute(k)) {
1546 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1547 "Path is not absolute, ignoring: %s", k);
1551 s = new0(PathSpec, 1);
1556 s->path = path_kill_slashes(k);
1561 LIST_PREPEND(spec, p->specs, s);
1566 int config_parse_socket_service(const char *unit,
1567 const char *filename,
1569 const char *section,
1570 unsigned section_line,
1577 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1581 _cleanup_free_ char *p = NULL;
1588 r = unit_name_printf(UNIT(s), rvalue, &p);
1590 log_syntax(unit, LOG_ERR, filename, line, -r,
1591 "Failed to resolve specifiers, ignoring: %s", rvalue);
1595 if (!endswith(p, ".service")) {
1596 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1597 "Unit must be of type service, ignoring: %s", rvalue);
1601 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1603 log_syntax(unit, LOG_ERR, filename, line, -r,
1604 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1608 unit_ref_set(&s->service, x);
1613 int config_parse_service_sockets(const char *unit,
1614 const char *filename,
1616 const char *section,
1617 unsigned section_line,
1626 const char *word, *state;
1634 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1635 _cleanup_free_ char *t = NULL, *k = NULL;
1637 t = strndup(word, l);
1641 r = unit_name_printf(UNIT(s), t, &k);
1643 log_syntax(unit, LOG_ERR, filename, line, -r,
1644 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1646 if (!endswith(k ?: t, ".socket")) {
1647 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1648 "Unit must be of type socket, ignoring: %s", k ?: t);
1652 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1654 log_syntax(unit, LOG_ERR, filename, line, -r,
1655 "Failed to add dependency on %s, ignoring: %s",
1656 k ?: t, strerror(-r));
1658 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1662 if (!isempty(state))
1663 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1664 "Trailing garbage, ignoring.");
1669 int config_parse_service_timeout(const char *unit,
1670 const char *filename,
1672 const char *section,
1673 unsigned section_line,
1680 Service *s = userdata;
1688 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1689 rvalue, data, userdata);
1693 if (streq(lvalue, "TimeoutSec")) {
1694 s->start_timeout_defined = true;
1695 s->timeout_stop_usec = s->timeout_start_usec;
1696 } else if (streq(lvalue, "TimeoutStartSec"))
1697 s->start_timeout_defined = true;
1702 int config_parse_busname_service(
1704 const char *filename,
1706 const char *section,
1707 unsigned section_line,
1714 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1718 _cleanup_free_ char *p = NULL;
1725 r = unit_name_printf(UNIT(n), rvalue, &p);
1727 log_syntax(unit, LOG_ERR, filename, line, -r,
1728 "Failed to resolve specifiers, ignoring: %s", rvalue);
1732 if (!endswith(p, ".service")) {
1733 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1734 "Unit must be of type service, ignoring: %s", rvalue);
1738 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1740 log_syntax(unit, LOG_ERR, filename, line, -r,
1741 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1745 unit_ref_set(&n->service, x);
1750 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1752 int config_parse_bus_policy(
1754 const char *filename,
1756 const char *section,
1757 unsigned section_line,
1764 _cleanup_free_ BusNamePolicy *p = NULL;
1765 _cleanup_free_ char *id_str = NULL;
1766 BusName *busname = data;
1774 p = new0(BusNamePolicy, 1);
1778 if (streq(lvalue, "AllowUser"))
1779 p->type = BUSNAME_POLICY_TYPE_USER;
1780 else if (streq(lvalue, "AllowGroup"))
1781 p->type = BUSNAME_POLICY_TYPE_GROUP;
1783 assert_not_reached("Unknown lvalue");
1785 id_str = strdup(rvalue);
1789 access_str = strpbrk(id_str, WHITESPACE);
1791 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1792 "Invalid busname policy value '%s'", rvalue);
1798 access_str += strspn(access_str, WHITESPACE);
1800 p->access = bus_policy_access_from_string(access_str);
1801 if (p->access < 0) {
1802 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1803 "Invalid busname policy access type '%s'", access_str);
1810 LIST_PREPEND(policy, busname->policy, p);
1816 int config_parse_bus_endpoint_policy(
1818 const char *filename,
1820 const char *section,
1821 unsigned section_line,
1828 _cleanup_free_ char *name = NULL;
1829 BusPolicyAccess access;
1830 ExecContext *c = data;
1839 name = strdup(rvalue);
1843 access_str = strpbrk(name, WHITESPACE);
1845 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1846 "Invalid endpoint policy value '%s'", rvalue);
1852 access_str += strspn(access_str, WHITESPACE);
1854 access = bus_policy_access_from_string(access_str);
1855 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1856 access >= _BUS_POLICY_ACCESS_MAX) {
1857 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1858 "Invalid endpoint policy access type '%s'", access_str);
1862 if (!c->bus_endpoint) {
1863 r = bus_endpoint_new(&c->bus_endpoint);
1869 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1872 int config_parse_unit_env_file(const char *unit,
1873 const char *filename,
1875 const char *section,
1876 unsigned section_line,
1885 _cleanup_free_ char *n = NULL;
1894 if (isempty(rvalue)) {
1895 /* Empty assignment frees the list */
1901 r = unit_full_printf(u, rvalue, &n);
1903 log_syntax(unit, LOG_ERR, filename, line, -r,
1904 "Failed to resolve specifiers, ignoring: %s", rvalue);
1907 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1908 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1909 "Path '%s' is not absolute, ignoring.", s);
1913 r = strv_extend(env, s);
1920 int config_parse_environ(const char *unit,
1921 const char *filename,
1923 const char *section,
1924 unsigned section_line,
1933 const char *word, *state;
1935 _cleanup_free_ char *k = NULL;
1943 if (isempty(rvalue)) {
1944 /* Empty assignment resets the list */
1951 r = unit_full_printf(u, rvalue, &k);
1953 log_syntax(unit, LOG_ERR, filename, line, -r,
1954 "Failed to resolve specifiers, ignoring: %s", rvalue);
1962 FOREACH_WORD_QUOTED(word, l, k, state) {
1963 _cleanup_free_ char *n;
1966 n = cunescape_length(word, l);
1970 if (!env_assignment_is_valid(n)) {
1971 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1972 "Invalid environment assignment, ignoring: %s", rvalue);
1976 x = strv_env_set(*env, n);
1983 if (!isempty(state))
1984 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1985 "Trailing garbage, ignoring.");
1990 int config_parse_ip_tos(const char *unit,
1991 const char *filename,
1993 const char *section,
1994 unsigned section_line,
2001 int *ip_tos = data, x;
2008 x = ip_tos_from_string(rvalue);
2010 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2011 "Failed to parse IP TOS value, ignoring: %s", rvalue);
2019 int config_parse_unit_condition_path(
2021 const char *filename,
2023 const char *section,
2024 unsigned section_line,
2031 _cleanup_free_ char *p = NULL;
2032 Condition **list = data, *c;
2033 ConditionType t = ltype;
2034 bool trigger, negate;
2043 if (isempty(rvalue)) {
2044 /* Empty assignment resets the list */
2045 condition_free_list(*list);
2050 trigger = rvalue[0] == '|';
2054 negate = rvalue[0] == '!';
2058 r = unit_full_printf(u, rvalue, &p);
2060 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2064 if (!path_is_absolute(p)) {
2065 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2069 c = condition_new(t, p, trigger, negate);
2073 LIST_PREPEND(conditions, *list, c);
2077 int config_parse_unit_condition_string(
2079 const char *filename,
2081 const char *section,
2082 unsigned section_line,
2089 _cleanup_free_ char *s = NULL;
2090 Condition **list = data, *c;
2091 ConditionType t = ltype;
2092 bool trigger, negate;
2101 if (isempty(rvalue)) {
2102 /* Empty assignment resets the list */
2103 condition_free_list(*list);
2108 trigger = rvalue[0] == '|';
2112 negate = rvalue[0] == '!';
2116 r = unit_full_printf(u, rvalue, &s);
2118 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2122 c = condition_new(t, s, trigger, negate);
2126 LIST_PREPEND(conditions, *list, c);
2130 int config_parse_unit_condition_null(
2132 const char *filename,
2134 const char *section,
2135 unsigned section_line,
2142 Condition **list = data, *c;
2143 bool trigger, negate;
2151 if (isempty(rvalue)) {
2152 /* Empty assignment resets the list */
2153 condition_free_list(*list);
2158 trigger = rvalue[0] == '|';
2162 negate = rvalue[0] == '!';
2166 b = parse_boolean(rvalue);
2168 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2175 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2179 LIST_PREPEND(conditions, *list, c);
2183 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2184 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2186 int config_parse_unit_requires_mounts_for(
2188 const char *filename,
2190 const char *section,
2191 unsigned section_line,
2199 const char *word, *state;
2207 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2209 _cleanup_free_ char *n;
2211 n = strndup(word, l);
2215 if (!utf8_is_valid(n)) {
2216 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2220 r = unit_require_mounts_for(u, n);
2222 log_syntax(unit, LOG_ERR, filename, line, -r,
2223 "Failed to add required mount for, ignoring: %s", rvalue);
2227 if (!isempty(state))
2228 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2229 "Trailing garbage, ignoring.");
2234 int config_parse_documentation(const char *unit,
2235 const char *filename,
2237 const char *section,
2238 unsigned section_line,
2254 if (isempty(rvalue)) {
2255 /* Empty assignment resets the list */
2256 strv_free(u->documentation);
2257 u->documentation = NULL;
2261 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2262 rvalue, data, userdata);
2266 for (a = b = u->documentation; a && *a; a++) {
2268 if (is_valid_documentation_url(*a))
2271 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2272 "Invalid URL, ignoring: %s", *a);
2283 int config_parse_syscall_filter(
2285 const char *filename,
2287 const char *section,
2288 unsigned section_line,
2295 static const char default_syscalls[] =
2302 ExecContext *c = data;
2304 bool invert = false;
2305 const char *word, *state;
2314 if (isempty(rvalue)) {
2315 /* Empty assignment resets the list */
2316 set_free(c->syscall_filter);
2317 c->syscall_filter = NULL;
2318 c->syscall_whitelist = false;
2322 if (rvalue[0] == '~') {
2327 if (!c->syscall_filter) {
2328 c->syscall_filter = set_new(NULL);
2329 if (!c->syscall_filter)
2333 /* Allow everything but the ones listed */
2334 c->syscall_whitelist = false;
2338 /* Allow nothing but the ones listed */
2339 c->syscall_whitelist = true;
2341 /* Accept default syscalls if we are on a whitelist */
2342 NULSTR_FOREACH(i, default_syscalls) {
2345 id = seccomp_syscall_resolve_name(i);
2349 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2358 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2359 _cleanup_free_ char *t = NULL;
2362 t = strndup(word, l);
2366 id = seccomp_syscall_resolve_name(t);
2368 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2369 "Failed to parse system call, ignoring: %s", t);
2373 /* If we previously wanted to forbid a syscall and now
2374 * we want to allow it, then remove it from the list
2376 if (!invert == c->syscall_whitelist) {
2377 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2383 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2385 if (!isempty(state))
2386 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2387 "Trailing garbage, ignoring.");
2389 /* Turn on NNP, but only if it wasn't configured explicitly
2390 * before, and only if we are in user mode. */
2391 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2392 c->no_new_privileges = true;
2397 int config_parse_syscall_archs(
2399 const char *filename,
2401 const char *section,
2402 unsigned section_line,
2410 const char *word, *state;
2414 if (isempty(rvalue)) {
2420 r = set_ensure_allocated(archs, NULL);
2424 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2425 _cleanup_free_ char *t = NULL;
2428 t = strndup(word, l);
2432 r = seccomp_arch_from_string(t, &a);
2434 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2435 "Failed to parse system call architecture, ignoring: %s", t);
2439 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2445 if (!isempty(state))
2446 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2447 "Trailing garbage, ignoring.");
2452 int config_parse_syscall_errno(
2454 const char *filename,
2456 const char *section,
2457 unsigned section_line,
2464 ExecContext *c = data;
2471 if (isempty(rvalue)) {
2472 /* Empty assignment resets to KILL */
2473 c->syscall_errno = 0;
2477 e = errno_from_name(rvalue);
2479 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2480 "Failed to parse error number, ignoring: %s", rvalue);
2484 c->syscall_errno = e;
2488 int config_parse_address_families(
2490 const char *filename,
2492 const char *section,
2493 unsigned section_line,
2500 ExecContext *c = data;
2501 bool invert = false;
2502 const char *word, *state;
2510 if (isempty(rvalue)) {
2511 /* Empty assignment resets the list */
2512 set_free(c->address_families);
2513 c->address_families = NULL;
2514 c->address_families_whitelist = false;
2518 if (rvalue[0] == '~') {
2523 if (!c->address_families) {
2524 c->address_families = set_new(NULL);
2525 if (!c->address_families)
2528 c->address_families_whitelist = !invert;
2531 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2532 _cleanup_free_ char *t = NULL;
2535 t = strndup(word, l);
2539 af = af_from_name(t);
2541 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2542 "Failed to parse address family, ignoring: %s", t);
2546 /* If we previously wanted to forbid an address family and now
2547 * we want to allow it, then remove it from the list
2549 if (!invert == c->address_families_whitelist) {
2550 r = set_put(c->address_families, INT_TO_PTR(af));
2556 set_remove(c->address_families, INT_TO_PTR(af));
2558 if (!isempty(state))
2559 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2560 "Trailing garbage, ignoring.");
2566 int config_parse_unit_slice(
2568 const char *filename,
2570 const char *section,
2571 unsigned section_line,
2578 _cleanup_free_ char *k = NULL;
2579 Unit *u = userdata, *slice;
2587 r = unit_name_printf(u, rvalue, &k);
2589 log_syntax(unit, LOG_ERR, filename, line, -r,
2590 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2597 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2599 log_syntax(unit, LOG_ERR, filename, line, -r,
2600 "Failed to load slice unit %s. Ignoring.", k);
2604 if (slice->type != UNIT_SLICE) {
2605 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2606 "Slice unit %s is not a slice. Ignoring.", k);
2610 unit_ref_set(&u->slice, slice);
2614 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2616 int config_parse_cpu_shares(
2618 const char *filename,
2620 const char *section,
2621 unsigned section_line,
2628 unsigned long *shares = data, lu;
2635 if (isempty(rvalue)) {
2636 *shares = (unsigned long) -1;
2640 r = safe_atolu(rvalue, &lu);
2641 if (r < 0 || lu <= 0) {
2642 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2643 "CPU shares '%s' invalid. Ignoring.", rvalue);
2651 int config_parse_cpu_quota(
2653 const char *filename,
2655 const char *section,
2656 unsigned section_line,
2663 CGroupContext *c = data;
2670 if (isempty(rvalue)) {
2671 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2675 if (!endswith(rvalue, "%")) {
2677 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2678 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2682 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2683 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2684 "CPU quota '%s' invalid. Ignoring.", rvalue);
2688 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2693 int config_parse_memory_limit(
2695 const char *filename,
2697 const char *section,
2698 unsigned section_line,
2705 CGroupContext *c = data;
2709 if (isempty(rvalue)) {
2710 c->memory_limit = (uint64_t) -1;
2714 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2716 r = parse_size(rvalue, 1024, &bytes);
2718 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2719 "Memory limit '%s' invalid. Ignoring.", rvalue);
2723 c->memory_limit = (uint64_t) bytes;
2727 int config_parse_device_allow(
2729 const char *filename,
2731 const char *section,
2732 unsigned section_line,
2739 _cleanup_free_ char *path = NULL;
2740 CGroupContext *c = data;
2741 CGroupDeviceAllow *a;
2745 if (isempty(rvalue)) {
2746 while (c->device_allow)
2747 cgroup_context_free_device_allow(c, c->device_allow);
2752 n = strcspn(rvalue, WHITESPACE);
2753 path = strndup(rvalue, n);
2757 if (!startswith(path, "/dev/") &&
2758 !startswith(path, "block-") &&
2759 !startswith(path, "char-")) {
2760 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2761 "Invalid device node path '%s'. Ignoring.", path);
2765 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2769 if (!in_charset(m, "rwm")) {
2770 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2771 "Invalid device rights '%s'. Ignoring.", m);
2775 a = new0(CGroupDeviceAllow, 1);
2781 a->r = !!strchr(m, 'r');
2782 a->w = !!strchr(m, 'w');
2783 a->m = !!strchr(m, 'm');
2785 LIST_PREPEND(device_allow, c->device_allow, a);
2789 int config_parse_blockio_weight(
2791 const char *filename,
2793 const char *section,
2794 unsigned section_line,
2801 unsigned long *weight = data, lu;
2808 if (isempty(rvalue)) {
2809 *weight = (unsigned long) -1;
2813 r = safe_atolu(rvalue, &lu);
2814 if (r < 0 || lu < 10 || lu > 1000) {
2815 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2816 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2824 int config_parse_blockio_device_weight(
2826 const char *filename,
2828 const char *section,
2829 unsigned section_line,
2836 _cleanup_free_ char *path = NULL;
2837 CGroupBlockIODeviceWeight *w;
2838 CGroupContext *c = data;
2848 if (isempty(rvalue)) {
2849 while (c->blockio_device_weights)
2850 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2855 n = strcspn(rvalue, WHITESPACE);
2856 weight = rvalue + n;
2858 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2859 "Expected block device and device weight. Ignoring.");
2863 path = strndup(rvalue, n);
2867 if (!path_startswith(path, "/dev")) {
2868 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2869 "Invalid device node path '%s'. Ignoring.", path);
2873 weight += strspn(weight, WHITESPACE);
2874 r = safe_atolu(weight, &lu);
2875 if (r < 0 || lu < 10 || lu > 1000) {
2876 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2877 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2881 w = new0(CGroupBlockIODeviceWeight, 1);
2890 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2894 int config_parse_blockio_bandwidth(
2896 const char *filename,
2898 const char *section,
2899 unsigned section_line,
2906 _cleanup_free_ char *path = NULL;
2907 CGroupBlockIODeviceBandwidth *b;
2908 CGroupContext *c = data;
2909 const char *bandwidth;
2919 read = streq("BlockIOReadBandwidth", lvalue);
2921 if (isempty(rvalue)) {
2922 CGroupBlockIODeviceBandwidth *next;
2924 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2925 if (b->read == read)
2926 cgroup_context_free_blockio_device_bandwidth(c, b);
2931 n = strcspn(rvalue, WHITESPACE);
2932 bandwidth = rvalue + n;
2933 bandwidth += strspn(bandwidth, WHITESPACE);
2936 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2937 "Expected space separated pair of device node and bandwidth. Ignoring.");
2941 path = strndup(rvalue, n);
2945 if (!path_startswith(path, "/dev")) {
2946 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2947 "Invalid device node path '%s'. Ignoring.", path);
2951 r = parse_size(bandwidth, 1000, &bytes);
2952 if (r < 0 || bytes <= 0) {
2953 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2954 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2958 b = new0(CGroupBlockIODeviceBandwidth, 1);
2964 b->bandwidth = (uint64_t) bytes;
2967 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2972 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2974 int config_parse_job_mode_isolate(
2976 const char *filename,
2978 const char *section,
2979 unsigned section_line,
2993 r = parse_boolean(rvalue);
2995 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2996 "Failed to parse boolean, ignoring: %s", rvalue);
3000 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3004 int config_parse_personality(
3006 const char *filename,
3008 const char *section,
3009 unsigned section_line,
3016 unsigned long *personality = data, p;
3021 assert(personality);
3023 p = personality_from_string(rvalue);
3024 if (p == 0xffffffffUL) {
3025 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3026 "Failed to parse personality, ignoring: %s", rvalue);
3034 int config_parse_runtime_directory(
3036 const char *filename,
3038 const char *section,
3039 unsigned section_line,
3047 const char *word, *state;
3056 if (isempty(rvalue)) {
3057 /* Empty assignment resets the list */
3063 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3064 _cleanup_free_ char *n;
3066 n = strndup(word, l);
3070 if (!filename_is_safe(n)) {
3071 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3072 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3076 r = strv_push(rt, n);
3082 if (!isempty(state))
3083 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3084 "Trailing garbage, ignoring.");
3089 int config_parse_set_status(
3091 const char *filename,
3093 const char *section,
3094 unsigned section_line,
3102 const char *word, *state;
3104 ExitStatusSet *status_set = data;
3111 /* Empty assignment resets the list */
3112 if (isempty(rvalue)) {
3113 exit_status_set_free(status_set);
3117 FOREACH_WORD(word, l, rvalue, state) {
3118 _cleanup_free_ char *temp;
3121 temp = strndup(word, l);
3125 r = safe_atoi(temp, &val);
3127 val = signal_from_string_try_harder(temp);
3130 log_syntax(unit, LOG_ERR, filename, line, -val,
3131 "Failed to parse value, ignoring: %s", word);
3135 if (val < 0 || val > 255) {
3136 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3137 "Value %d is outside range 0-255, ignoring", val);
3142 r = set_ensure_allocated(&status_set->status, NULL);
3146 r = set_put(status_set->status, INT_TO_PTR(val));
3148 log_syntax(unit, LOG_ERR, filename, line, -r,
3149 "Unable to store: %s", word);
3153 if (!isempty(state))
3154 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3155 "Trailing garbage, ignoring.");
3160 int config_parse_namespace_path_strv(
3162 const char *filename,
3164 const char *section,
3165 unsigned section_line,
3173 const char *word, *state;
3182 if (isempty(rvalue)) {
3183 /* Empty assignment resets the list */
3189 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3190 _cleanup_free_ char *n;
3193 n = strndup(word, l);
3197 if (!utf8_is_valid(n)) {
3198 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3202 offset = n[0] == '-';
3203 if (!path_is_absolute(n + offset)) {
3204 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3205 "Not an absolute path, ignoring: %s", rvalue);
3209 path_kill_slashes(n);
3211 r = strv_push(sv, n);
3217 if (!isempty(state))
3218 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3219 "Trailing garbage, ignoring.");
3224 int config_parse_no_new_privileges(
3226 const char *filename,
3228 const char *section,
3229 unsigned section_line,
3236 ExecContext *c = data;
3244 k = parse_boolean(rvalue);
3246 log_syntax(unit, LOG_ERR, filename, line, -k,
3247 "Failed to parse boolean value, ignoring: %s", rvalue);
3251 c->no_new_privileges = !!k;
3252 c->no_new_privileges_set = true;
3257 int config_parse_protect_home(
3259 const char *filename,
3261 const char *section,
3262 unsigned section_line,
3269 ExecContext *c = data;
3277 /* Our enum shall be a superset of booleans, hence first try
3278 * to parse as as boolean, and then as enum */
3280 k = parse_boolean(rvalue);
3282 c->protect_home = PROTECT_HOME_YES;
3284 c->protect_home = PROTECT_HOME_NO;
3288 h = protect_home_from_string(rvalue);
3290 log_syntax(unit, LOG_ERR, filename, line, -h,
3291 "Failed to parse protect home value, ignoring: %s", rvalue);
3295 c->protect_home = h;
3301 int config_parse_protect_system(
3303 const char *filename,
3305 const char *section,
3306 unsigned section_line,
3313 ExecContext *c = data;
3321 /* Our enum shall be a superset of booleans, hence first try
3322 * to parse as as boolean, and then as enum */
3324 k = parse_boolean(rvalue);
3326 c->protect_system = PROTECT_SYSTEM_YES;
3328 c->protect_system = PROTECT_SYSTEM_NO;
3332 s = protect_system_from_string(rvalue);
3334 log_syntax(unit, LOG_ERR, filename, line, -s,
3335 "Failed to parse protect system value, ignoring: %s", rvalue);
3339 c->protect_system = s;
3345 #define FOLLOW_MAX 8
3347 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3358 /* This will update the filename pointer if the loaded file is
3359 * reached by a symlink. The old string will be freed. */
3362 char *target, *name;
3364 if (c++ >= FOLLOW_MAX)
3367 path_kill_slashes(*filename);
3369 /* Add the file name we are currently looking at to
3370 * the names of this unit, but only if it is a valid
3372 name = basename(*filename);
3374 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3376 id = set_get(names, name);
3382 r = set_consume(names, id);
3388 /* Try to open the file name, but don't if its a symlink */
3389 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3396 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3397 r = readlink_and_make_absolute(*filename, &target);
3405 f = fdopen(fd, "re");
3417 static int merge_by_names(Unit **u, Set *names, const char *id) {
3425 /* Let's try to add in all symlink names we found */
3426 while ((k = set_steal_first(names))) {
3428 /* First try to merge in the other name into our
3430 r = unit_merge_by_name(*u, k);
3434 /* Hmm, we couldn't merge the other unit into
3435 * ours? Then let's try it the other way
3438 other = manager_get_unit((*u)->manager, k);
3442 r = unit_merge(other, *u);
3445 return merge_by_names(u, names, NULL);
3453 unit_choose_id(*u, id);
3461 static int load_from_path(Unit *u, const char *path) {
3463 _cleanup_set_free_free_ Set *symlink_names = NULL;
3464 _cleanup_fclose_ FILE *f = NULL;
3465 _cleanup_free_ char *filename = NULL;
3473 symlink_names = set_new(&string_hash_ops);
3477 if (path_is_absolute(path)) {
3479 filename = strdup(path);
3483 r = open_follow(&filename, &f, symlink_names, &id);
3495 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3497 /* Instead of opening the path right away, we manually
3498 * follow all symlinks and add their name to our unit
3499 * name set while doing so */
3500 filename = path_make_absolute(path, *p);
3504 if (u->manager->unit_path_cache &&
3505 !set_get(u->manager->unit_path_cache, filename))
3508 r = open_follow(&filename, &f, symlink_names, &id);
3517 /* Empty the symlink names for the next run */
3518 set_clear_free(symlink_names);
3527 /* Hmm, no suitable file found? */
3531 r = merge_by_names(&merged, symlink_names, id);
3536 u->load_state = UNIT_MERGED;
3540 if (fstat(fileno(f), &st) < 0)
3543 if (null_or_empty(&st))
3544 u->load_state = UNIT_MASKED;
3546 u->load_state = UNIT_LOADED;
3548 /* Now, parse the file contents */
3549 r = config_parse(u->id, filename, f,
3550 UNIT_VTABLE(u)->sections,
3551 config_item_perf_lookup, load_fragment_gperf_lookup,
3552 false, true, false, u);
3557 free(u->fragment_path);
3558 u->fragment_path = filename;
3561 u->fragment_mtime = timespec_load(&st.st_mtim);
3563 if (u->source_path) {
3564 if (stat(u->source_path, &st) >= 0)
3565 u->source_mtime = timespec_load(&st.st_mtim);
3567 u->source_mtime = 0;
3573 int unit_load_fragment(Unit *u) {
3579 assert(u->load_state == UNIT_STUB);
3582 /* First, try to find the unit under its id. We always look
3583 * for unit files in the default directories, to make it easy
3584 * to override things by placing things in /etc/systemd/system */
3585 r = load_from_path(u, u->id);
3589 /* Try to find an alias we can load this with */
3590 if (u->load_state == UNIT_STUB)
3591 SET_FOREACH(t, u->names, i) {
3596 r = load_from_path(u, t);
3600 if (u->load_state != UNIT_STUB)
3604 /* And now, try looking for it under the suggested (originally linked) path */
3605 if (u->load_state == UNIT_STUB && u->fragment_path) {
3607 r = load_from_path(u, u->fragment_path);
3611 if (u->load_state == UNIT_STUB) {
3612 /* Hmm, this didn't work? Then let's get rid
3613 * of the fragment path stored for us, so that
3614 * we don't point to an invalid location. */
3615 free(u->fragment_path);
3616 u->fragment_path = NULL;
3620 /* Look for a template */
3621 if (u->load_state == UNIT_STUB && u->instance) {
3622 _cleanup_free_ char *k;
3624 k = unit_name_template(u->id);
3628 r = load_from_path(u, k);
3632 if (u->load_state == UNIT_STUB)
3633 SET_FOREACH(t, u->names, i) {
3634 _cleanup_free_ char *z = NULL;
3639 z = unit_name_template(t);
3643 r = load_from_path(u, z);
3647 if (u->load_state != UNIT_STUB)
3655 void unit_dump_config_items(FILE *f) {
3656 static const struct {
3657 const ConfigParserCallback callback;
3660 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3661 { config_parse_warn_compat, "NOTSUPPORTED" },
3663 { config_parse_int, "INTEGER" },
3664 { config_parse_unsigned, "UNSIGNED" },
3665 { config_parse_iec_size, "SIZE" },
3666 { config_parse_iec_off, "SIZE" },
3667 { config_parse_si_size, "SIZE" },
3668 { config_parse_bool, "BOOLEAN" },
3669 { config_parse_string, "STRING" },
3670 { config_parse_path, "PATH" },
3671 { config_parse_unit_path_printf, "PATH" },
3672 { config_parse_strv, "STRING [...]" },
3673 { config_parse_exec_nice, "NICE" },
3674 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3675 { config_parse_exec_io_class, "IOCLASS" },
3676 { config_parse_exec_io_priority, "IOPRIORITY" },
3677 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3678 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3679 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3680 { config_parse_mode, "MODE" },
3681 { config_parse_unit_env_file, "FILE" },
3682 { config_parse_output, "OUTPUT" },
3683 { config_parse_input, "INPUT" },
3684 { config_parse_log_facility, "FACILITY" },
3685 { config_parse_log_level, "LEVEL" },
3686 { config_parse_exec_capabilities, "CAPABILITIES" },
3687 { config_parse_exec_secure_bits, "SECUREBITS" },
3688 { config_parse_bounding_set, "BOUNDINGSET" },
3689 { config_parse_limit, "LIMIT" },
3690 { config_parse_unit_deps, "UNIT [...]" },
3691 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3692 { config_parse_service_type, "SERVICETYPE" },
3693 { config_parse_service_restart, "SERVICERESTART" },
3694 #ifdef HAVE_SYSV_COMPAT
3695 { config_parse_sysv_priority, "SYSVPRIORITY" },
3697 { config_parse_kill_mode, "KILLMODE" },
3698 { config_parse_kill_signal, "SIGNAL" },
3699 { config_parse_socket_listen, "SOCKET [...]" },
3700 { config_parse_socket_bind, "SOCKETBIND" },
3701 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3702 { config_parse_sec, "SECONDS" },
3703 { config_parse_nsec, "NANOSECONDS" },
3704 { config_parse_namespace_path_strv, "PATH [...]" },
3705 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3706 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3707 { config_parse_unit_string_printf, "STRING" },
3708 { config_parse_trigger_unit, "UNIT" },
3709 { config_parse_timer, "TIMER" },
3710 { config_parse_path_spec, "PATH" },
3711 { config_parse_notify_access, "ACCESS" },
3712 { config_parse_ip_tos, "TOS" },
3713 { config_parse_unit_condition_path, "CONDITION" },
3714 { config_parse_unit_condition_string, "CONDITION" },
3715 { config_parse_unit_condition_null, "CONDITION" },
3716 { config_parse_unit_slice, "SLICE" },
3717 { config_parse_documentation, "URL" },
3718 { config_parse_service_timeout, "SECONDS" },
3719 { config_parse_failure_action, "ACTION" },
3720 { config_parse_set_status, "STATUS" },
3721 { config_parse_service_sockets, "SOCKETS" },
3722 { config_parse_environ, "ENVIRON" },
3724 { config_parse_syscall_filter, "SYSCALLS" },
3725 { config_parse_syscall_archs, "ARCHS" },
3726 { config_parse_syscall_errno, "ERRNO" },
3727 { config_parse_address_families, "FAMILIES" },
3729 { config_parse_cpu_shares, "SHARES" },
3730 { config_parse_memory_limit, "LIMIT" },
3731 { config_parse_device_allow, "DEVICE" },
3732 { config_parse_device_policy, "POLICY" },
3733 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3734 { config_parse_blockio_weight, "WEIGHT" },
3735 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3736 { config_parse_long, "LONG" },
3737 { config_parse_socket_service, "SERVICE" },
3739 { config_parse_exec_selinux_context, "LABEL" },
3741 { config_parse_job_mode, "MODE" },
3742 { config_parse_job_mode_isolate, "BOOLEAN" },
3743 { config_parse_personality, "PERSONALITY" },
3746 const char *prev = NULL;
3751 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3752 const char *rvalue = "OTHER", *lvalue;
3756 const ConfigPerfItem *p;
3758 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3760 dot = strchr(i, '.');
3761 lvalue = dot ? dot + 1 : i;
3765 if (!prev || !strneq(prev, i, prefix_len+1)) {
3769 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3772 for (j = 0; j < ELEMENTSOF(table); j++)
3773 if (p->parse == table[j].callback) {
3774 rvalue = table[j].rvalue;
3778 fprintf(f, "%s=%s\n", lvalue, rvalue);