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;
100 const char *word, *state;
107 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
108 _cleanup_free_ char *t = NULL, *k = NULL;
111 t = strndup(word, l);
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));
128 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
133 int config_parse_unit_string_printf(const char *unit,
134 const char *filename,
137 unsigned section_line,
145 _cleanup_free_ char *k = NULL;
153 r = unit_full_printf(u, rvalue, &k);
155 log_syntax(unit, LOG_ERR, filename, line, -r,
156 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
158 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
159 k ? k : rvalue, data, userdata);
162 int config_parse_unit_strv_printf(const char *unit,
163 const char *filename,
166 unsigned section_line,
174 _cleanup_free_ char *k = NULL;
182 r = unit_full_printf(u, rvalue, &k);
184 log_syntax(unit, LOG_ERR, filename, line, -r,
185 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
187 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
188 k ? k : rvalue, data, userdata);
191 int config_parse_unit_path_printf(const char *unit,
192 const char *filename,
195 unsigned section_line,
202 _cleanup_free_ char *k = NULL;
211 r = unit_full_printf(u, rvalue, &k);
213 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
217 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
220 int config_parse_unit_path_strv_printf(
222 const char *filename,
225 unsigned section_line,
233 const char *word, *state;
243 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
244 _cleanup_free_ char *k = NULL;
250 r = unit_full_printf(u, t, &k);
252 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
256 if (!utf8_is_valid(k)) {
257 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
261 if (!path_is_absolute(k)) {
262 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
266 path_kill_slashes(k);
275 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
280 int config_parse_socket_listen(const char *unit,
281 const char *filename,
284 unsigned section_line,
291 SocketPort *p, *tail;
302 if (isempty(rvalue)) {
303 /* An empty assignment removes all ports */
304 socket_free_ports(s);
308 p = new0(SocketPort, 1);
312 if (ltype != SOCKET_SOCKET) {
315 r = unit_full_printf(UNIT(s), rvalue, &p->path);
317 p->path = strdup(rvalue);
322 log_syntax(unit, LOG_ERR, filename, line, -r,
323 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
326 path_kill_slashes(p->path);
328 } else if (streq(lvalue, "ListenNetlink")) {
329 _cleanup_free_ char *k = NULL;
331 p->type = SOCKET_SOCKET;
332 r = unit_full_printf(UNIT(s), rvalue, &k);
334 log_syntax(unit, LOG_ERR, filename, line, -r,
335 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
337 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
339 log_syntax(unit, LOG_ERR, filename, line, -r,
340 "Failed to parse address value, ignoring: %s", rvalue);
346 _cleanup_free_ char *k = NULL;
348 p->type = SOCKET_SOCKET;
349 r = unit_full_printf(UNIT(s), rvalue, &k);
351 log_syntax(unit, LOG_ERR, filename, line, -r,
352 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
354 r = socket_address_parse(&p->address, k ? k : rvalue);
356 log_syntax(unit, LOG_ERR, filename, line, -r,
357 "Failed to parse address value, ignoring: %s", rvalue);
362 if (streq(lvalue, "ListenStream"))
363 p->address.type = SOCK_STREAM;
364 else if (streq(lvalue, "ListenDatagram"))
365 p->address.type = SOCK_DGRAM;
367 assert(streq(lvalue, "ListenSequentialPacket"));
368 p->address.type = SOCK_SEQPACKET;
371 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
372 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
373 "Address family not supported, ignoring: %s", rvalue);
383 LIST_FIND_TAIL(port, s->ports, tail);
384 LIST_INSERT_AFTER(port, s->ports, tail, p);
386 LIST_PREPEND(port, s->ports, p);
391 int config_parse_socket_bind(const char *unit,
392 const char *filename,
395 unsigned section_line,
403 SocketAddressBindIPv6Only b;
412 b = socket_address_bind_ipv6_only_from_string(rvalue);
416 r = parse_boolean(rvalue);
418 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
419 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
423 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
425 s->bind_ipv6_only = b;
430 int config_parse_exec_nice(const char *unit,
431 const char *filename,
434 unsigned section_line,
441 ExecContext *c = data;
449 r = safe_atoi(rvalue, &priority);
451 log_syntax(unit, LOG_ERR, filename, line, -r,
452 "Failed to parse nice priority, ignoring: %s. ", rvalue);
456 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
457 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
458 "Nice priority out of range, ignoring: %s", rvalue);
468 int config_parse_exec_oom_score_adjust(const char* unit,
469 const char *filename,
472 unsigned section_line,
479 ExecContext *c = data;
487 r = safe_atoi(rvalue, &oa);
489 log_syntax(unit, LOG_ERR, filename, line, -r,
490 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
494 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
495 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
496 "OOM score adjust value out of range, ignoring: %s", rvalue);
500 c->oom_score_adjust = oa;
501 c->oom_score_adjust_set = true;
506 int config_parse_exec(const char *unit,
507 const char *filename,
510 unsigned section_line,
517 ExecCommand **e = data, *nce;
529 if (isempty(rvalue)) {
530 /* An empty assignment resets the list */
531 exec_command_free_list(*e);
536 /* We accept an absolute path as first argument, or
537 * alternatively an absolute prefixed with @ to allow
538 * overriding of argv[0]. */
541 const char *word, *state;
543 bool honour_argv0 = false, ignore = false;
549 rvalue += strspn(rvalue, WHITESPACE);
554 for (i = 0; i < 2; i++) {
555 if (rvalue[0] == '-' && !ignore) {
560 if (rvalue[0] == '@' && !honour_argv0) {
566 if (*rvalue != '/') {
567 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
568 "Executable path is not absolute, ignoring: %s", rvalue);
573 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
574 if (strneq(word, ";", MAX(l, 1U)))
579 if (!isempty(state)) {
580 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
581 "Trailing garbage, ignoring.");
586 n = new(char*, k + !honour_argv0);
591 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
592 if (strneq(word, ";", MAX(l, 1U)))
594 else if (strneq(word, "\\;", MAX(l, 1U)))
597 if (honour_argv0 && word == rvalue) {
600 path = strndup(word, l);
606 if (!utf8_is_valid(path)) {
607 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
615 c = n[k++] = cunescape_length(word, l);
621 if (!utf8_is_valid(c)) {
622 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
632 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
633 "Invalid command line, ignoring: %s", rvalue);
646 assert(path_is_absolute(path));
648 nce = new0(ExecCommand, 1);
656 nce->ignore = ignore;
658 path_kill_slashes(nce->path);
660 exec_command_append_list(e, nce);
676 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
677 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
679 int config_parse_socket_bindtodevice(const char* unit,
680 const char *filename,
683 unsigned section_line,
698 if (rvalue[0] && !streq(rvalue, "*")) {
705 free(s->bind_to_device);
706 s->bind_to_device = n;
711 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
712 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
714 int config_parse_exec_io_class(const char *unit,
715 const char *filename,
718 unsigned section_line,
725 ExecContext *c = data;
733 x = ioprio_class_from_string(rvalue);
735 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
736 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
740 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
741 c->ioprio_set = true;
746 int config_parse_exec_io_priority(const char *unit,
747 const char *filename,
750 unsigned section_line,
757 ExecContext *c = data;
765 r = safe_atoi(rvalue, &i);
766 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
767 log_syntax(unit, LOG_ERR, filename, line, -r,
768 "Failed to parse IO priority, ignoring: %s", rvalue);
772 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
773 c->ioprio_set = true;
778 int config_parse_exec_cpu_sched_policy(const char *unit,
779 const char *filename,
782 unsigned section_line,
790 ExecContext *c = data;
798 x = sched_policy_from_string(rvalue);
800 log_syntax(unit, LOG_ERR, filename, line, -x,
801 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
805 c->cpu_sched_policy = x;
806 /* Moving to or from real-time policy? We need to adjust the priority */
807 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
808 c->cpu_sched_set = true;
813 int config_parse_exec_cpu_sched_prio(const char *unit,
814 const char *filename,
817 unsigned section_line,
824 ExecContext *c = data;
832 r = safe_atoi(rvalue, &i);
834 log_syntax(unit, LOG_ERR, filename, line, -r,
835 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
839 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
840 min = sched_get_priority_min(c->cpu_sched_policy);
841 max = sched_get_priority_max(c->cpu_sched_policy);
843 if (i < min || i > max) {
844 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
845 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
849 c->cpu_sched_priority = i;
850 c->cpu_sched_set = true;
855 int config_parse_exec_cpu_affinity(const char *unit,
856 const char *filename,
859 unsigned section_line,
866 ExecContext *c = data;
867 const char *word, *state;
875 if (isempty(rvalue)) {
876 /* An empty assignment resets the CPU list */
883 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
884 _cleanup_free_ char *t = NULL;
888 t = strndup(word, l);
892 r = safe_atou(t, &cpu);
895 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
900 if (r < 0 || cpu >= c->cpuset_ncpus) {
901 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
902 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
906 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
909 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
910 "Trailing garbage, ignoring.");
915 int config_parse_exec_capabilities(const char *unit,
916 const char *filename,
919 unsigned section_line,
926 ExecContext *c = data;
934 cap = cap_from_text(rvalue);
936 log_syntax(unit, LOG_ERR, filename, line, errno,
937 "Failed to parse capabilities, ignoring: %s", rvalue);
942 cap_free(c->capabilities);
943 c->capabilities = cap;
948 int config_parse_exec_secure_bits(const char *unit,
949 const char *filename,
952 unsigned section_line,
959 ExecContext *c = data;
961 const char *word, *state;
968 if (isempty(rvalue)) {
969 /* An empty assignment resets the field */
974 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
975 if (first_word(word, "keep-caps"))
976 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
977 else if (first_word(word, "keep-caps-locked"))
978 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
979 else if (first_word(word, "no-setuid-fixup"))
980 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
981 else if (first_word(word, "no-setuid-fixup-locked"))
982 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
983 else if (first_word(word, "noroot"))
984 c->secure_bits |= 1<<SECURE_NOROOT;
985 else if (first_word(word, "noroot-locked"))
986 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
988 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
989 "Failed to parse secure bits, ignoring: %s", rvalue);
994 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
995 "Invalid syntax, garbage at the end, ignoring.");
1000 int config_parse_bounding_set(const char *unit,
1001 const char *filename,
1003 const char *section,
1004 unsigned section_line,
1011 uint64_t *capability_bounding_set_drop = data;
1012 const char *word, *state;
1014 bool invert = false;
1022 if (rvalue[0] == '~') {
1027 /* Note that we store this inverted internally, since the
1028 * kernel wants it like this. But we actually expose it
1029 * non-inverted everywhere to have a fully normalized
1032 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1033 _cleanup_free_ char *t = NULL;
1037 t = strndup(word, l);
1041 r = cap_from_name(t, &cap);
1043 log_syntax(unit, LOG_ERR, filename, line, errno,
1044 "Failed to parse capability in bounding set, ignoring: %s", t);
1048 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1050 if (!isempty(state))
1051 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1052 "Trailing garbage, ignoring.");
1055 *capability_bounding_set_drop |= sum;
1057 *capability_bounding_set_drop |= ~sum;
1062 int config_parse_limit(const char *unit,
1063 const char *filename,
1065 const char *section,
1066 unsigned section_line,
1073 struct rlimit **rl = data;
1074 unsigned long long u;
1083 if (streq(rvalue, "infinity"))
1084 u = (unsigned long long) RLIM_INFINITY;
1088 r = safe_atollu(rvalue, &u);
1090 log_syntax(unit, LOG_ERR, filename, line, -r,
1091 "Failed to parse resource value, ignoring: %s", rvalue);
1097 *rl = new(struct rlimit, 1);
1102 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1106 #ifdef HAVE_SYSV_COMPAT
1107 int config_parse_sysv_priority(const char *unit,
1108 const char *filename,
1110 const char *section,
1111 unsigned section_line,
1118 int *priority = data;
1126 r = safe_atoi(rvalue, &i);
1127 if (r < 0 || i < 0) {
1128 log_syntax(unit, LOG_ERR, filename, line, -r,
1129 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1133 *priority = (int) i;
1138 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1140 int config_parse_kill_signal(const char *unit,
1141 const char *filename,
1143 const char *section,
1144 unsigned section_line,
1159 r = signal_from_string_try_harder(rvalue);
1161 log_syntax(unit, LOG_ERR, filename, line, -r,
1162 "Failed to parse kill signal, ignoring: %s", rvalue);
1170 int config_parse_exec_mount_flags(const char *unit,
1171 const char *filename,
1173 const char *section,
1174 unsigned section_line,
1181 ExecContext *c = data;
1182 const char *word, *state;
1184 unsigned long flags = 0;
1191 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1192 _cleanup_free_ char *t;
1194 t = strndup(word, l);
1198 if (streq(t, "shared"))
1200 else if (streq(t, "slave"))
1202 else if (streq(word, "private"))
1205 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1206 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1210 if (!isempty(state))
1211 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1212 "Trailing garbage, ignoring.");
1214 c->mount_flags = flags;
1218 int config_parse_exec_selinux_context(
1220 const char *filename,
1222 const char *section,
1223 unsigned section_line,
1230 ExecContext *c = data;
1241 if (isempty(rvalue)) {
1242 free(c->selinux_context);
1243 c->selinux_context = NULL;
1244 c->selinux_context_ignore = false;
1248 if (rvalue[0] == '-') {
1254 r = unit_name_printf(u, rvalue, &k);
1256 log_syntax(unit, LOG_ERR, filename, line, -r,
1257 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1261 free(c->selinux_context);
1262 c->selinux_context = k;
1263 c->selinux_context_ignore = ignore;
1268 int config_parse_exec_apparmor_profile(
1270 const char *filename,
1272 const char *section,
1273 unsigned section_line,
1280 ExecContext *c = data;
1291 if (isempty(rvalue)) {
1292 free(c->apparmor_profile);
1293 c->apparmor_profile = NULL;
1294 c->apparmor_profile_ignore = false;
1298 if (rvalue[0] == '-') {
1304 r = unit_name_printf(u, rvalue, &k);
1306 log_syntax(unit, LOG_ERR, filename, line, -r,
1307 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1311 free(c->apparmor_profile);
1312 c->apparmor_profile = k;
1313 c->apparmor_profile_ignore = ignore;
1318 int config_parse_timer(const char *unit,
1319 const char *filename,
1321 const char *section,
1322 unsigned section_line,
1333 CalendarSpec *c = NULL;
1340 if (isempty(rvalue)) {
1341 /* Empty assignment resets list */
1342 timer_free_values(t);
1346 b = timer_base_from_string(lvalue);
1348 log_syntax(unit, LOG_ERR, filename, line, -b,
1349 "Failed to parse timer base, ignoring: %s", lvalue);
1353 if (b == TIMER_CALENDAR) {
1354 if (calendar_spec_from_string(rvalue, &c) < 0) {
1355 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1356 "Failed to parse calendar specification, ignoring: %s",
1361 if (parse_sec(rvalue, &u) < 0) {
1362 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1363 "Failed to parse timer value, ignoring: %s",
1369 v = new0(TimerValue, 1);
1375 v->calendar_spec = c;
1377 LIST_PREPEND(value, t->values, v);
1382 int config_parse_trigger_unit(
1384 const char *filename,
1386 const char *section,
1387 unsigned section_line,
1394 _cleanup_free_ char *p = NULL;
1404 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1405 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1406 "Multiple units to trigger specified, ignoring: %s", rvalue);
1410 r = unit_name_printf(u, rvalue, &p);
1412 log_syntax(unit, LOG_ERR, filename, line, -r,
1413 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1415 type = unit_name_to_type(p ?: rvalue);
1417 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1418 "Unit type not valid, ignoring: %s", rvalue);
1422 if (type == u->type) {
1423 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1424 "Trigger cannot be of same type, ignoring: %s", rvalue);
1428 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1430 log_syntax(unit, LOG_ERR, filename, line, -r,
1431 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1438 int config_parse_path_spec(const char *unit,
1439 const char *filename,
1441 const char *section,
1442 unsigned section_line,
1452 _cleanup_free_ char *k = NULL;
1460 if (isempty(rvalue)) {
1461 /* Empty assignment clears list */
1466 b = path_type_from_string(lvalue);
1468 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1469 "Failed to parse path type, ignoring: %s", lvalue);
1473 r = unit_full_printf(UNIT(p), rvalue, &k);
1479 log_syntax(unit, LOG_ERR, filename, line, -r,
1480 "Failed to resolve unit specifiers on %s. Ignoring.",
1484 if (!path_is_absolute(k)) {
1485 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1486 "Path is not absolute, ignoring: %s", k);
1490 s = new0(PathSpec, 1);
1495 s->path = path_kill_slashes(k);
1500 LIST_PREPEND(spec, p->specs, s);
1505 int config_parse_socket_service(const char *unit,
1506 const char *filename,
1508 const char *section,
1509 unsigned section_line,
1516 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1520 _cleanup_free_ char *p = NULL;
1527 r = unit_name_printf(UNIT(s), rvalue, &p);
1529 log_syntax(unit, LOG_ERR, filename, line, -r,
1530 "Failed to resolve specifiers, ignoring: %s", rvalue);
1534 if (!endswith(p, ".service")) {
1535 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1536 "Unit must be of type service, ignoring: %s", rvalue);
1540 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1542 log_syntax(unit, LOG_ERR, filename, line, -r,
1543 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1547 unit_ref_set(&s->service, x);
1552 int config_parse_service_sockets(const char *unit,
1553 const char *filename,
1555 const char *section,
1556 unsigned section_line,
1565 const char *word, *state;
1573 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1574 _cleanup_free_ char *t = NULL, *k = NULL;
1576 t = strndup(word, l);
1580 r = unit_name_printf(UNIT(s), t, &k);
1582 log_syntax(unit, LOG_ERR, filename, line, -r,
1583 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1585 if (!endswith(k ?: t, ".socket")) {
1586 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1587 "Unit must be of type socket, ignoring: %s", k ?: t);
1591 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1593 log_syntax(unit, LOG_ERR, filename, line, -r,
1594 "Failed to add dependency on %s, ignoring: %s",
1595 k ?: t, strerror(-r));
1597 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1601 if (!isempty(state))
1602 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1603 "Trailing garbage, ignoring.");
1608 int config_parse_service_timeout(const char *unit,
1609 const char *filename,
1611 const char *section,
1612 unsigned section_line,
1619 Service *s = userdata;
1627 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1628 rvalue, data, userdata);
1632 if (streq(lvalue, "TimeoutSec")) {
1633 s->start_timeout_defined = true;
1634 s->timeout_stop_usec = s->timeout_start_usec;
1635 } else if (streq(lvalue, "TimeoutStartSec"))
1636 s->start_timeout_defined = true;
1641 int config_parse_busname_service(
1643 const char *filename,
1645 const char *section,
1646 unsigned section_line,
1653 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1657 _cleanup_free_ char *p = NULL;
1664 r = unit_name_printf(UNIT(n), rvalue, &p);
1666 log_syntax(unit, LOG_ERR, filename, line, -r,
1667 "Failed to resolve specifiers, ignoring: %s", rvalue);
1671 if (!endswith(p, ".service")) {
1672 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1673 "Unit must be of type service, ignoring: %s", rvalue);
1677 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1679 log_syntax(unit, LOG_ERR, filename, line, -r,
1680 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1684 unit_ref_set(&n->service, x);
1689 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1691 int config_parse_bus_policy(
1693 const char *filename,
1695 const char *section,
1696 unsigned section_line,
1703 _cleanup_free_ BusNamePolicy *p = NULL;
1704 _cleanup_free_ char *id_str = NULL;
1705 BusName *busname = data;
1713 p = new0(BusNamePolicy, 1);
1717 if (streq(lvalue, "AllowUser"))
1718 p->type = BUSNAME_POLICY_TYPE_USER;
1719 else if (streq(lvalue, "AllowGroup"))
1720 p->type = BUSNAME_POLICY_TYPE_GROUP;
1722 assert_not_reached("Unknown lvalue");
1724 id_str = strdup(rvalue);
1728 access_str = strpbrk(id_str, WHITESPACE);
1730 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1731 "Invalid busname policy value '%s'", rvalue);
1737 access_str += strspn(access_str, WHITESPACE);
1739 p->access = bus_policy_access_from_string(access_str);
1740 if (p->access < 0) {
1741 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1742 "Invalid busname policy access type '%s'", access_str);
1749 LIST_PREPEND(policy, busname->policy, p);
1755 int config_parse_bus_endpoint_policy(
1757 const char *filename,
1759 const char *section,
1760 unsigned section_line,
1767 _cleanup_free_ char *name = NULL;
1768 BusPolicyAccess access;
1769 ExecContext *c = data;
1778 name = strdup(rvalue);
1782 access_str = strpbrk(name, WHITESPACE);
1784 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1785 "Invalid endpoint policy value '%s'", rvalue);
1791 access_str += strspn(access_str, WHITESPACE);
1793 access = bus_policy_access_from_string(access_str);
1794 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1795 access >= _BUS_POLICY_ACCESS_MAX) {
1796 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1797 "Invalid endpoint policy access type '%s'", access_str);
1801 if (!c->bus_endpoint) {
1802 r = bus_endpoint_new(&c->bus_endpoint);
1808 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1811 int config_parse_unit_env_file(const char *unit,
1812 const char *filename,
1814 const char *section,
1815 unsigned section_line,
1824 _cleanup_free_ char *n = NULL;
1833 if (isempty(rvalue)) {
1834 /* Empty assignment frees the list */
1840 r = unit_full_printf(u, rvalue, &n);
1842 log_syntax(unit, LOG_ERR, filename, line, -r,
1843 "Failed to resolve specifiers, ignoring: %s", rvalue);
1846 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1847 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1848 "Path '%s' is not absolute, ignoring.", s);
1852 r = strv_extend(env, s);
1859 int config_parse_environ(const char *unit,
1860 const char *filename,
1862 const char *section,
1863 unsigned section_line,
1872 const char *word, *state;
1874 _cleanup_free_ char *k = NULL;
1882 if (isempty(rvalue)) {
1883 /* Empty assignment resets the list */
1890 r = unit_full_printf(u, rvalue, &k);
1892 log_syntax(unit, LOG_ERR, filename, line, -r,
1893 "Failed to resolve specifiers, ignoring: %s", rvalue);
1901 FOREACH_WORD_QUOTED(word, l, k, state) {
1902 _cleanup_free_ char *n;
1905 n = cunescape_length(word, l);
1909 if (!env_assignment_is_valid(n)) {
1910 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1911 "Invalid environment assignment, ignoring: %s", rvalue);
1915 x = strv_env_set(*env, n);
1922 if (!isempty(state))
1923 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1924 "Trailing garbage, ignoring.");
1929 int config_parse_ip_tos(const char *unit,
1930 const char *filename,
1932 const char *section,
1933 unsigned section_line,
1940 int *ip_tos = data, x;
1947 x = ip_tos_from_string(rvalue);
1949 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1950 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1958 int config_parse_unit_condition_path(const char *unit,
1959 const char *filename,
1961 const char *section,
1962 unsigned section_line,
1969 ConditionType cond = ltype;
1971 bool trigger, negate;
1973 _cleanup_free_ char *p = NULL;
1981 if (isempty(rvalue)) {
1982 /* Empty assignment resets the list */
1983 condition_free_list(u->conditions);
1984 u->conditions = NULL;
1988 trigger = rvalue[0] == '|';
1992 negate = rvalue[0] == '!';
1996 r = unit_full_printf(u, rvalue, &p);
1998 log_syntax(unit, LOG_ERR, filename, line, -r,
1999 "Failed to resolve specifiers, ignoring: %s", rvalue);
2006 if (!path_is_absolute(p)) {
2007 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2008 "Path in condition not absolute, ignoring: %s", p);
2012 c = condition_new(cond, p, trigger, negate);
2016 LIST_PREPEND(conditions, u->conditions, c);
2020 int config_parse_unit_condition_string(const char *unit,
2021 const char *filename,
2023 const char *section,
2024 unsigned section_line,
2031 ConditionType cond = ltype;
2033 bool trigger, negate;
2035 _cleanup_free_ char *s = NULL;
2043 if (isempty(rvalue)) {
2044 /* Empty assignment resets the list */
2045 condition_free_list(u->conditions);
2046 u->conditions = NULL;
2050 trigger = rvalue[0] == '|';
2054 negate = rvalue[0] == '!';
2058 r = unit_full_printf(u, rvalue, &s);
2060 log_syntax(unit, LOG_ERR, filename, line, -r,
2061 "Failed to resolve specifiers, ignoring: %s", rvalue);
2068 c = condition_new(cond, s, trigger, negate);
2072 LIST_PREPEND(conditions, u->conditions, c);
2076 int config_parse_unit_condition_null(const char *unit,
2077 const char *filename,
2079 const char *section,
2080 unsigned section_line,
2089 bool trigger, negate;
2097 if (isempty(rvalue)) {
2098 /* Empty assignment resets the list */
2099 condition_free_list(u->conditions);
2100 u->conditions = NULL;
2104 trigger = rvalue[0] == '|';
2108 negate = rvalue[0] == '!';
2112 b = parse_boolean(rvalue);
2114 log_syntax(unit, LOG_ERR, filename, line, -b,
2115 "Failed to parse boolean value in condition, ignoring: %s",
2123 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2127 LIST_PREPEND(conditions, u->conditions, c);
2131 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2132 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2134 int config_parse_unit_requires_mounts_for(
2136 const char *filename,
2138 const char *section,
2139 unsigned section_line,
2147 const char *word, *state;
2155 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2157 _cleanup_free_ char *n;
2159 n = strndup(word, l);
2163 if (!utf8_is_valid(n)) {
2164 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2168 r = unit_require_mounts_for(u, n);
2170 log_syntax(unit, LOG_ERR, filename, line, -r,
2171 "Failed to add required mount for, ignoring: %s", rvalue);
2175 if (!isempty(state))
2176 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2177 "Trailing garbage, ignoring.");
2182 int config_parse_documentation(const char *unit,
2183 const char *filename,
2185 const char *section,
2186 unsigned section_line,
2202 if (isempty(rvalue)) {
2203 /* Empty assignment resets the list */
2204 strv_free(u->documentation);
2205 u->documentation = NULL;
2209 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2210 rvalue, data, userdata);
2214 for (a = b = u->documentation; a && *a; a++) {
2216 if (is_valid_documentation_url(*a))
2219 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2220 "Invalid URL, ignoring: %s", *a);
2231 int config_parse_syscall_filter(
2233 const char *filename,
2235 const char *section,
2236 unsigned section_line,
2243 static const char default_syscalls[] =
2250 ExecContext *c = data;
2252 bool invert = false;
2253 const char *word, *state;
2262 if (isempty(rvalue)) {
2263 /* Empty assignment resets the list */
2264 set_free(c->syscall_filter);
2265 c->syscall_filter = NULL;
2266 c->syscall_whitelist = false;
2270 if (rvalue[0] == '~') {
2275 if (!c->syscall_filter) {
2276 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2277 if (!c->syscall_filter)
2281 /* Allow everything but the ones listed */
2282 c->syscall_whitelist = false;
2286 /* Allow nothing but the ones listed */
2287 c->syscall_whitelist = true;
2289 /* Accept default syscalls if we are on a whitelist */
2290 NULSTR_FOREACH(i, default_syscalls) {
2293 id = seccomp_syscall_resolve_name(i);
2297 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2306 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2307 _cleanup_free_ char *t = NULL;
2310 t = strndup(word, l);
2314 id = seccomp_syscall_resolve_name(t);
2316 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2317 "Failed to parse system call, ignoring: %s", t);
2321 /* If we previously wanted to forbid a syscall and now
2322 * we want to allow it, then remove it from the list
2324 if (!invert == c->syscall_whitelist) {
2325 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2331 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2333 if (!isempty(state))
2334 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2335 "Trailing garbage, ignoring.");
2337 /* Turn on NNP, but only if it wasn't configured explicitly
2338 * before, and only if we are in user mode. */
2339 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2340 c->no_new_privileges = true;
2345 int config_parse_syscall_archs(
2347 const char *filename,
2349 const char *section,
2350 unsigned section_line,
2358 const char *word, *state;
2362 if (isempty(rvalue)) {
2368 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2372 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2373 _cleanup_free_ char *t = NULL;
2376 t = strndup(word, l);
2380 r = seccomp_arch_from_string(t, &a);
2382 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2383 "Failed to parse system call architecture, ignoring: %s", t);
2387 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2393 if (!isempty(state))
2394 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2395 "Trailing garbage, ignoring.");
2400 int config_parse_syscall_errno(
2402 const char *filename,
2404 const char *section,
2405 unsigned section_line,
2412 ExecContext *c = data;
2419 if (isempty(rvalue)) {
2420 /* Empty assignment resets to KILL */
2421 c->syscall_errno = 0;
2425 e = errno_from_name(rvalue);
2427 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2428 "Failed to parse error number, ignoring: %s", rvalue);
2432 c->syscall_errno = e;
2436 int config_parse_address_families(
2438 const char *filename,
2440 const char *section,
2441 unsigned section_line,
2448 ExecContext *c = data;
2450 bool invert = false;
2451 const char *word, *state;
2460 if (isempty(rvalue)) {
2461 /* Empty assignment resets the list */
2462 set_free(c->address_families);
2463 c->address_families = NULL;
2464 c->address_families_whitelist = false;
2468 if (rvalue[0] == '~') {
2473 if (!c->address_families) {
2474 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2475 if (!c->address_families)
2478 c->address_families_whitelist = !invert;
2481 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2482 _cleanup_free_ char *t = NULL;
2485 t = strndup(word, l);
2489 af = af_from_name(t);
2491 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2492 "Failed to parse address family, ignoring: %s", t);
2496 /* If we previously wanted to forbid an address family and now
2497 * we want to allow it, then remove it from the list
2499 if (!invert == c->address_families_whitelist) {
2500 r = set_put(c->address_families, INT_TO_PTR(af));
2506 set_remove(c->address_families, INT_TO_PTR(af));
2508 if (!isempty(state))
2509 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2510 "Trailing garbage, ignoring.");
2516 int config_parse_unit_slice(
2518 const char *filename,
2520 const char *section,
2521 unsigned section_line,
2528 _cleanup_free_ char *k = NULL;
2529 Unit *u = userdata, *slice;
2537 r = unit_name_printf(u, rvalue, &k);
2539 log_syntax(unit, LOG_ERR, filename, line, -r,
2540 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2547 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2549 log_syntax(unit, LOG_ERR, filename, line, -r,
2550 "Failed to load slice unit %s. Ignoring.", k);
2554 if (slice->type != UNIT_SLICE) {
2555 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2556 "Slice unit %s is not a slice. Ignoring.", k);
2560 unit_ref_set(&u->slice, slice);
2564 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2566 int config_parse_cpu_shares(
2568 const char *filename,
2570 const char *section,
2571 unsigned section_line,
2578 unsigned long *shares = data, lu;
2585 if (isempty(rvalue)) {
2586 *shares = (unsigned long) -1;
2590 r = safe_atolu(rvalue, &lu);
2591 if (r < 0 || lu <= 0) {
2592 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2593 "CPU shares '%s' invalid. Ignoring.", rvalue);
2601 int config_parse_cpu_quota(
2603 const char *filename,
2605 const char *section,
2606 unsigned section_line,
2613 CGroupContext *c = data;
2620 if (isempty(rvalue)) {
2621 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2625 if (!endswith(rvalue, "%")) {
2627 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2628 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2632 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2633 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2634 "CPU quota '%s' invalid. Ignoring.", rvalue);
2638 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2643 int config_parse_memory_limit(
2645 const char *filename,
2647 const char *section,
2648 unsigned section_line,
2655 CGroupContext *c = data;
2659 if (isempty(rvalue)) {
2660 c->memory_limit = (uint64_t) -1;
2664 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2666 r = parse_size(rvalue, 1024, &bytes);
2668 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2669 "Memory limit '%s' invalid. Ignoring.", rvalue);
2673 c->memory_limit = (uint64_t) bytes;
2677 int config_parse_device_allow(
2679 const char *filename,
2681 const char *section,
2682 unsigned section_line,
2689 _cleanup_free_ char *path = NULL;
2690 CGroupContext *c = data;
2691 CGroupDeviceAllow *a;
2695 if (isempty(rvalue)) {
2696 while (c->device_allow)
2697 cgroup_context_free_device_allow(c, c->device_allow);
2702 n = strcspn(rvalue, WHITESPACE);
2703 path = strndup(rvalue, n);
2707 if (!startswith(path, "/dev/") &&
2708 !startswith(path, "block-") &&
2709 !startswith(path, "char-")) {
2710 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2711 "Invalid device node path '%s'. Ignoring.", path);
2715 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2719 if (!in_charset(m, "rwm")) {
2720 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2721 "Invalid device rights '%s'. Ignoring.", m);
2725 a = new0(CGroupDeviceAllow, 1);
2731 a->r = !!strchr(m, 'r');
2732 a->w = !!strchr(m, 'w');
2733 a->m = !!strchr(m, 'm');
2735 LIST_PREPEND(device_allow, c->device_allow, a);
2739 int config_parse_blockio_weight(
2741 const char *filename,
2743 const char *section,
2744 unsigned section_line,
2751 unsigned long *weight = data, lu;
2758 if (isempty(rvalue)) {
2759 *weight = (unsigned long) -1;
2763 r = safe_atolu(rvalue, &lu);
2764 if (r < 0 || lu < 10 || lu > 1000) {
2765 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2766 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2774 int config_parse_blockio_device_weight(
2776 const char *filename,
2778 const char *section,
2779 unsigned section_line,
2786 _cleanup_free_ char *path = NULL;
2787 CGroupBlockIODeviceWeight *w;
2788 CGroupContext *c = data;
2798 if (isempty(rvalue)) {
2799 while (c->blockio_device_weights)
2800 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2805 n = strcspn(rvalue, WHITESPACE);
2806 weight = rvalue + n;
2808 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2809 "Expected block device and device weight. Ignoring.");
2813 path = strndup(rvalue, n);
2817 if (!path_startswith(path, "/dev")) {
2818 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2819 "Invalid device node path '%s'. Ignoring.", path);
2823 weight += strspn(weight, WHITESPACE);
2824 r = safe_atolu(weight, &lu);
2825 if (r < 0 || lu < 10 || lu > 1000) {
2826 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2827 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2831 w = new0(CGroupBlockIODeviceWeight, 1);
2840 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2844 int config_parse_blockio_bandwidth(
2846 const char *filename,
2848 const char *section,
2849 unsigned section_line,
2856 _cleanup_free_ char *path = NULL;
2857 CGroupBlockIODeviceBandwidth *b;
2858 CGroupContext *c = data;
2859 const char *bandwidth;
2869 read = streq("BlockIOReadBandwidth", lvalue);
2871 if (isempty(rvalue)) {
2872 CGroupBlockIODeviceBandwidth *next;
2874 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2875 if (b->read == read)
2876 cgroup_context_free_blockio_device_bandwidth(c, b);
2881 n = strcspn(rvalue, WHITESPACE);
2882 bandwidth = rvalue + n;
2883 bandwidth += strspn(bandwidth, WHITESPACE);
2886 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2887 "Expected space separated pair of device node and bandwidth. Ignoring.");
2891 path = strndup(rvalue, n);
2895 if (!path_startswith(path, "/dev")) {
2896 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2897 "Invalid device node path '%s'. Ignoring.", path);
2901 r = parse_size(bandwidth, 1000, &bytes);
2902 if (r < 0 || bytes <= 0) {
2903 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2904 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2908 b = new0(CGroupBlockIODeviceBandwidth, 1);
2914 b->bandwidth = (uint64_t) bytes;
2917 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2922 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2924 int config_parse_job_mode_isolate(
2926 const char *filename,
2928 const char *section,
2929 unsigned section_line,
2943 r = parse_boolean(rvalue);
2945 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2946 "Failed to parse boolean, ignoring: %s", rvalue);
2950 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2954 int config_parse_personality(
2956 const char *filename,
2958 const char *section,
2959 unsigned section_line,
2966 unsigned long *personality = data, p;
2971 assert(personality);
2973 p = personality_from_string(rvalue);
2974 if (p == 0xffffffffUL) {
2975 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2976 "Failed to parse personality, ignoring: %s", rvalue);
2984 int config_parse_runtime_directory(
2986 const char *filename,
2988 const char *section,
2989 unsigned section_line,
2997 const char *word, *state;
3006 if (isempty(rvalue)) {
3007 /* Empty assignment resets the list */
3013 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3014 _cleanup_free_ char *n;
3016 n = strndup(word, l);
3020 if (!filename_is_safe(n)) {
3021 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3022 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3026 r = strv_push(rt, n);
3032 if (!isempty(state))
3033 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3034 "Trailing garbage, ignoring.");
3039 int config_parse_set_status(
3041 const char *filename,
3043 const char *section,
3044 unsigned section_line,
3052 const char *word, *state;
3054 ExitStatusSet *status_set = data;
3061 /* Empty assignment resets the list */
3062 if (isempty(rvalue)) {
3063 exit_status_set_free(status_set);
3067 FOREACH_WORD(word, l, rvalue, state) {
3068 _cleanup_free_ char *temp;
3071 temp = strndup(word, l);
3075 r = safe_atoi(temp, &val);
3077 val = signal_from_string_try_harder(temp);
3080 log_syntax(unit, LOG_ERR, filename, line, -val,
3081 "Failed to parse value, ignoring: %s", word);
3085 if (val < 0 || val > 255) {
3086 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3087 "Value %d is outside range 0-255, ignoring", val);
3092 r = set_ensure_allocated(&status_set->status, NULL, NULL);
3096 r = set_put(status_set->status, INT_TO_PTR(val));
3098 log_syntax(unit, LOG_ERR, filename, line, -r,
3099 "Unable to store: %s", word);
3103 if (!isempty(state))
3104 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3105 "Trailing garbage, ignoring.");
3110 int config_parse_namespace_path_strv(
3112 const char *filename,
3114 const char *section,
3115 unsigned section_line,
3123 const char *word, *state;
3132 if (isempty(rvalue)) {
3133 /* Empty assignment resets the list */
3139 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3140 _cleanup_free_ char *n;
3143 n = strndup(word, l);
3147 if (!utf8_is_valid(n)) {
3148 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3152 offset = n[0] == '-';
3153 if (!path_is_absolute(n + offset)) {
3154 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3155 "Not an absolute path, ignoring: %s", rvalue);
3159 path_kill_slashes(n);
3161 r = strv_push(sv, n);
3167 if (!isempty(state))
3168 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3169 "Trailing garbage, ignoring.");
3174 int config_parse_no_new_privileges(
3176 const char *filename,
3178 const char *section,
3179 unsigned section_line,
3186 ExecContext *c = data;
3194 k = parse_boolean(rvalue);
3196 log_syntax(unit, LOG_ERR, filename, line, -k,
3197 "Failed to parse boolean value, ignoring: %s", rvalue);
3201 c->no_new_privileges = !!k;
3202 c->no_new_privileges_set = true;
3207 int config_parse_protect_home(
3209 const char *filename,
3211 const char *section,
3212 unsigned section_line,
3219 ExecContext *c = data;
3227 /* Our enum shall be a superset of booleans, hence first try
3228 * to parse as as boolean, and then as enum */
3230 k = parse_boolean(rvalue);
3232 c->protect_home = PROTECT_HOME_YES;
3234 c->protect_home = PROTECT_HOME_NO;
3238 h = protect_home_from_string(rvalue);
3240 log_syntax(unit, LOG_ERR, filename, line, -h,
3241 "Failed to parse protect home value, ignoring: %s", rvalue);
3245 c->protect_home = h;
3251 int config_parse_protect_system(
3253 const char *filename,
3255 const char *section,
3256 unsigned section_line,
3263 ExecContext *c = data;
3271 /* Our enum shall be a superset of booleans, hence first try
3272 * to parse as as boolean, and then as enum */
3274 k = parse_boolean(rvalue);
3276 c->protect_system = PROTECT_SYSTEM_YES;
3278 c->protect_system = PROTECT_SYSTEM_NO;
3282 s = protect_system_from_string(rvalue);
3284 log_syntax(unit, LOG_ERR, filename, line, -s,
3285 "Failed to parse protect system value, ignoring: %s", rvalue);
3289 c->protect_system = s;
3295 #define FOLLOW_MAX 8
3297 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3308 /* This will update the filename pointer if the loaded file is
3309 * reached by a symlink. The old string will be freed. */
3312 char *target, *name;
3314 if (c++ >= FOLLOW_MAX)
3317 path_kill_slashes(*filename);
3319 /* Add the file name we are currently looking at to
3320 * the names of this unit, but only if it is a valid
3322 name = basename(*filename);
3324 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3326 id = set_get(names, name);
3332 r = set_consume(names, id);
3338 /* Try to open the file name, but don't if its a symlink */
3339 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3346 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3347 r = readlink_and_make_absolute(*filename, &target);
3355 f = fdopen(fd, "re");
3367 static int merge_by_names(Unit **u, Set *names, const char *id) {
3375 /* Let's try to add in all symlink names we found */
3376 while ((k = set_steal_first(names))) {
3378 /* First try to merge in the other name into our
3380 r = unit_merge_by_name(*u, k);
3384 /* Hmm, we couldn't merge the other unit into
3385 * ours? Then let's try it the other way
3388 other = manager_get_unit((*u)->manager, k);
3392 r = unit_merge(other, *u);
3395 return merge_by_names(u, names, NULL);
3403 unit_choose_id(*u, id);
3411 static int load_from_path(Unit *u, const char *path) {
3413 _cleanup_set_free_free_ Set *symlink_names = NULL;
3414 _cleanup_fclose_ FILE *f = NULL;
3415 _cleanup_free_ char *filename = NULL;
3423 symlink_names = set_new(string_hash_func, string_compare_func);
3427 if (path_is_absolute(path)) {
3429 filename = strdup(path);
3433 r = open_follow(&filename, &f, symlink_names, &id);
3445 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3447 /* Instead of opening the path right away, we manually
3448 * follow all symlinks and add their name to our unit
3449 * name set while doing so */
3450 filename = path_make_absolute(path, *p);
3454 if (u->manager->unit_path_cache &&
3455 !set_get(u->manager->unit_path_cache, filename))
3458 r = open_follow(&filename, &f, symlink_names, &id);
3467 /* Empty the symlink names for the next run */
3468 set_clear_free(symlink_names);
3477 /* Hmm, no suitable file found? */
3481 r = merge_by_names(&merged, symlink_names, id);
3486 u->load_state = UNIT_MERGED;
3490 if (fstat(fileno(f), &st) < 0)
3493 if (null_or_empty(&st))
3494 u->load_state = UNIT_MASKED;
3496 u->load_state = UNIT_LOADED;
3498 /* Now, parse the file contents */
3499 r = config_parse(u->id, filename, f,
3500 UNIT_VTABLE(u)->sections,
3501 config_item_perf_lookup, load_fragment_gperf_lookup,
3502 false, true, false, u);
3507 free(u->fragment_path);
3508 u->fragment_path = filename;
3511 u->fragment_mtime = timespec_load(&st.st_mtim);
3513 if (u->source_path) {
3514 if (stat(u->source_path, &st) >= 0)
3515 u->source_mtime = timespec_load(&st.st_mtim);
3517 u->source_mtime = 0;
3523 int unit_load_fragment(Unit *u) {
3529 assert(u->load_state == UNIT_STUB);
3532 /* First, try to find the unit under its id. We always look
3533 * for unit files in the default directories, to make it easy
3534 * to override things by placing things in /etc/systemd/system */
3535 r = load_from_path(u, u->id);
3539 /* Try to find an alias we can load this with */
3540 if (u->load_state == UNIT_STUB)
3541 SET_FOREACH(t, u->names, i) {
3546 r = load_from_path(u, t);
3550 if (u->load_state != UNIT_STUB)
3554 /* And now, try looking for it under the suggested (originally linked) path */
3555 if (u->load_state == UNIT_STUB && u->fragment_path) {
3557 r = load_from_path(u, u->fragment_path);
3561 if (u->load_state == UNIT_STUB) {
3562 /* Hmm, this didn't work? Then let's get rid
3563 * of the fragment path stored for us, so that
3564 * we don't point to an invalid location. */
3565 free(u->fragment_path);
3566 u->fragment_path = NULL;
3570 /* Look for a template */
3571 if (u->load_state == UNIT_STUB && u->instance) {
3572 _cleanup_free_ char *k;
3574 k = unit_name_template(u->id);
3578 r = load_from_path(u, k);
3582 if (u->load_state == UNIT_STUB)
3583 SET_FOREACH(t, u->names, i) {
3584 _cleanup_free_ char *z = NULL;
3589 z = unit_name_template(t);
3593 r = load_from_path(u, z);
3597 if (u->load_state != UNIT_STUB)
3605 void unit_dump_config_items(FILE *f) {
3606 static const struct {
3607 const ConfigParserCallback callback;
3610 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3611 { config_parse_warn_compat, "NOTSUPPORTED" },
3613 { config_parse_int, "INTEGER" },
3614 { config_parse_unsigned, "UNSIGNED" },
3615 { config_parse_iec_size, "SIZE" },
3616 { config_parse_iec_off, "SIZE" },
3617 { config_parse_si_size, "SIZE" },
3618 { config_parse_bool, "BOOLEAN" },
3619 { config_parse_string, "STRING" },
3620 { config_parse_path, "PATH" },
3621 { config_parse_unit_path_printf, "PATH" },
3622 { config_parse_strv, "STRING [...]" },
3623 { config_parse_exec_nice, "NICE" },
3624 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3625 { config_parse_exec_io_class, "IOCLASS" },
3626 { config_parse_exec_io_priority, "IOPRIORITY" },
3627 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3628 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3629 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3630 { config_parse_mode, "MODE" },
3631 { config_parse_unit_env_file, "FILE" },
3632 { config_parse_output, "OUTPUT" },
3633 { config_parse_input, "INPUT" },
3634 { config_parse_log_facility, "FACILITY" },
3635 { config_parse_log_level, "LEVEL" },
3636 { config_parse_exec_capabilities, "CAPABILITIES" },
3637 { config_parse_exec_secure_bits, "SECUREBITS" },
3638 { config_parse_bounding_set, "BOUNDINGSET" },
3639 { config_parse_limit, "LIMIT" },
3640 { config_parse_unit_deps, "UNIT [...]" },
3641 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3642 { config_parse_service_type, "SERVICETYPE" },
3643 { config_parse_service_restart, "SERVICERESTART" },
3644 #ifdef HAVE_SYSV_COMPAT
3645 { config_parse_sysv_priority, "SYSVPRIORITY" },
3647 { config_parse_kill_mode, "KILLMODE" },
3648 { config_parse_kill_signal, "SIGNAL" },
3649 { config_parse_socket_listen, "SOCKET [...]" },
3650 { config_parse_socket_bind, "SOCKETBIND" },
3651 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3652 { config_parse_sec, "SECONDS" },
3653 { config_parse_nsec, "NANOSECONDS" },
3654 { config_parse_namespace_path_strv, "PATH [...]" },
3655 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3656 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3657 { config_parse_unit_string_printf, "STRING" },
3658 { config_parse_trigger_unit, "UNIT" },
3659 { config_parse_timer, "TIMER" },
3660 { config_parse_path_spec, "PATH" },
3661 { config_parse_notify_access, "ACCESS" },
3662 { config_parse_ip_tos, "TOS" },
3663 { config_parse_unit_condition_path, "CONDITION" },
3664 { config_parse_unit_condition_string, "CONDITION" },
3665 { config_parse_unit_condition_null, "CONDITION" },
3666 { config_parse_unit_slice, "SLICE" },
3667 { config_parse_documentation, "URL" },
3668 { config_parse_service_timeout, "SECONDS" },
3669 { config_parse_failure_action, "ACTION" },
3670 { config_parse_set_status, "STATUS" },
3671 { config_parse_service_sockets, "SOCKETS" },
3672 { config_parse_environ, "ENVIRON" },
3674 { config_parse_syscall_filter, "SYSCALLS" },
3675 { config_parse_syscall_archs, "ARCHS" },
3676 { config_parse_syscall_errno, "ERRNO" },
3677 { config_parse_address_families, "FAMILIES" },
3679 { config_parse_cpu_shares, "SHARES" },
3680 { config_parse_memory_limit, "LIMIT" },
3681 { config_parse_device_allow, "DEVICE" },
3682 { config_parse_device_policy, "POLICY" },
3683 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3684 { config_parse_blockio_weight, "WEIGHT" },
3685 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3686 { config_parse_long, "LONG" },
3687 { config_parse_socket_service, "SERVICE" },
3689 { config_parse_exec_selinux_context, "LABEL" },
3691 { config_parse_job_mode, "MODE" },
3692 { config_parse_job_mode_isolate, "BOOLEAN" },
3693 { config_parse_personality, "PERSONALITY" },
3696 const char *prev = NULL;
3701 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3702 const char *rvalue = "OTHER", *lvalue;
3706 const ConfigPerfItem *p;
3708 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3710 dot = strchr(i, '.');
3711 lvalue = dot ? dot + 1 : i;
3715 if (!prev || !strneq(prev, i, prefix_len+1)) {
3719 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3722 for (j = 0; j < ELEMENTSOF(table); j++)
3723 if (p->parse == table[j].callback) {
3724 rvalue = table[j].rvalue;
3728 fprintf(f, "%s=%s\n", lvalue, rvalue);