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);
1372 calendar_spec_free(c);
1378 v->calendar_spec = c;
1380 LIST_PREPEND(value, t->values, v);
1385 int config_parse_trigger_unit(
1387 const char *filename,
1389 const char *section,
1390 unsigned section_line,
1397 _cleanup_free_ char *p = NULL;
1407 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1408 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1409 "Multiple units to trigger specified, ignoring: %s", rvalue);
1413 r = unit_name_printf(u, rvalue, &p);
1415 log_syntax(unit, LOG_ERR, filename, line, -r,
1416 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1418 type = unit_name_to_type(p ?: rvalue);
1420 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1421 "Unit type not valid, ignoring: %s", rvalue);
1425 if (type == u->type) {
1426 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1427 "Trigger cannot be of same type, ignoring: %s", rvalue);
1431 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1433 log_syntax(unit, LOG_ERR, filename, line, -r,
1434 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1441 int config_parse_path_spec(const char *unit,
1442 const char *filename,
1444 const char *section,
1445 unsigned section_line,
1455 _cleanup_free_ char *k = NULL;
1463 if (isempty(rvalue)) {
1464 /* Empty assignment clears list */
1469 b = path_type_from_string(lvalue);
1471 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1472 "Failed to parse path type, ignoring: %s", lvalue);
1476 r = unit_full_printf(UNIT(p), rvalue, &k);
1482 log_syntax(unit, LOG_ERR, filename, line, -r,
1483 "Failed to resolve unit specifiers on %s. Ignoring.",
1487 if (!path_is_absolute(k)) {
1488 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1489 "Path is not absolute, ignoring: %s", k);
1493 s = new0(PathSpec, 1);
1498 s->path = path_kill_slashes(k);
1503 LIST_PREPEND(spec, p->specs, s);
1508 int config_parse_socket_service(const char *unit,
1509 const char *filename,
1511 const char *section,
1512 unsigned section_line,
1519 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1523 _cleanup_free_ char *p = NULL;
1530 r = unit_name_printf(UNIT(s), rvalue, &p);
1532 log_syntax(unit, LOG_ERR, filename, line, -r,
1533 "Failed to resolve specifiers, ignoring: %s", rvalue);
1537 if (!endswith(p, ".service")) {
1538 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1539 "Unit must be of type service, ignoring: %s", rvalue);
1543 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1545 log_syntax(unit, LOG_ERR, filename, line, -r,
1546 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1550 unit_ref_set(&s->service, x);
1555 int config_parse_service_sockets(const char *unit,
1556 const char *filename,
1558 const char *section,
1559 unsigned section_line,
1568 const char *word, *state;
1576 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1577 _cleanup_free_ char *t = NULL, *k = NULL;
1579 t = strndup(word, l);
1583 r = unit_name_printf(UNIT(s), t, &k);
1585 log_syntax(unit, LOG_ERR, filename, line, -r,
1586 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1588 if (!endswith(k ?: t, ".socket")) {
1589 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1590 "Unit must be of type socket, ignoring: %s", k ?: t);
1594 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1596 log_syntax(unit, LOG_ERR, filename, line, -r,
1597 "Failed to add dependency on %s, ignoring: %s",
1598 k ?: t, strerror(-r));
1600 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1604 if (!isempty(state))
1605 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1606 "Trailing garbage, ignoring.");
1611 int config_parse_service_timeout(const char *unit,
1612 const char *filename,
1614 const char *section,
1615 unsigned section_line,
1622 Service *s = userdata;
1630 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1631 rvalue, data, userdata);
1635 if (streq(lvalue, "TimeoutSec")) {
1636 s->start_timeout_defined = true;
1637 s->timeout_stop_usec = s->timeout_start_usec;
1638 } else if (streq(lvalue, "TimeoutStartSec"))
1639 s->start_timeout_defined = true;
1644 int config_parse_busname_service(
1646 const char *filename,
1648 const char *section,
1649 unsigned section_line,
1656 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1660 _cleanup_free_ char *p = NULL;
1667 r = unit_name_printf(UNIT(n), rvalue, &p);
1669 log_syntax(unit, LOG_ERR, filename, line, -r,
1670 "Failed to resolve specifiers, ignoring: %s", rvalue);
1674 if (!endswith(p, ".service")) {
1675 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1676 "Unit must be of type service, ignoring: %s", rvalue);
1680 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1682 log_syntax(unit, LOG_ERR, filename, line, -r,
1683 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1687 unit_ref_set(&n->service, x);
1692 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1694 int config_parse_bus_policy(
1696 const char *filename,
1698 const char *section,
1699 unsigned section_line,
1706 _cleanup_free_ BusNamePolicy *p = NULL;
1707 _cleanup_free_ char *id_str = NULL;
1708 BusName *busname = data;
1716 p = new0(BusNamePolicy, 1);
1720 if (streq(lvalue, "AllowUser"))
1721 p->type = BUSNAME_POLICY_TYPE_USER;
1722 else if (streq(lvalue, "AllowGroup"))
1723 p->type = BUSNAME_POLICY_TYPE_GROUP;
1725 assert_not_reached("Unknown lvalue");
1727 id_str = strdup(rvalue);
1731 access_str = strpbrk(id_str, WHITESPACE);
1733 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1734 "Invalid busname policy value '%s'", rvalue);
1740 access_str += strspn(access_str, WHITESPACE);
1742 p->access = bus_policy_access_from_string(access_str);
1743 if (p->access < 0) {
1744 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1745 "Invalid busname policy access type '%s'", access_str);
1752 LIST_PREPEND(policy, busname->policy, p);
1758 int config_parse_bus_endpoint_policy(
1760 const char *filename,
1762 const char *section,
1763 unsigned section_line,
1770 _cleanup_free_ char *name = NULL;
1771 BusPolicyAccess access;
1772 ExecContext *c = data;
1781 name = strdup(rvalue);
1785 access_str = strpbrk(name, WHITESPACE);
1787 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1788 "Invalid endpoint policy value '%s'", rvalue);
1794 access_str += strspn(access_str, WHITESPACE);
1796 access = bus_policy_access_from_string(access_str);
1797 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1798 access >= _BUS_POLICY_ACCESS_MAX) {
1799 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1800 "Invalid endpoint policy access type '%s'", access_str);
1804 if (!c->bus_endpoint) {
1805 r = bus_endpoint_new(&c->bus_endpoint);
1811 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1814 int config_parse_unit_env_file(const char *unit,
1815 const char *filename,
1817 const char *section,
1818 unsigned section_line,
1827 _cleanup_free_ char *n = NULL;
1836 if (isempty(rvalue)) {
1837 /* Empty assignment frees the list */
1843 r = unit_full_printf(u, rvalue, &n);
1845 log_syntax(unit, LOG_ERR, filename, line, -r,
1846 "Failed to resolve specifiers, ignoring: %s", rvalue);
1849 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1850 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1851 "Path '%s' is not absolute, ignoring.", s);
1855 r = strv_extend(env, s);
1862 int config_parse_environ(const char *unit,
1863 const char *filename,
1865 const char *section,
1866 unsigned section_line,
1875 const char *word, *state;
1877 _cleanup_free_ char *k = NULL;
1885 if (isempty(rvalue)) {
1886 /* Empty assignment resets the list */
1893 r = unit_full_printf(u, rvalue, &k);
1895 log_syntax(unit, LOG_ERR, filename, line, -r,
1896 "Failed to resolve specifiers, ignoring: %s", rvalue);
1904 FOREACH_WORD_QUOTED(word, l, k, state) {
1905 _cleanup_free_ char *n;
1908 n = cunescape_length(word, l);
1912 if (!env_assignment_is_valid(n)) {
1913 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1914 "Invalid environment assignment, ignoring: %s", rvalue);
1918 x = strv_env_set(*env, n);
1925 if (!isempty(state))
1926 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1927 "Trailing garbage, ignoring.");
1932 int config_parse_ip_tos(const char *unit,
1933 const char *filename,
1935 const char *section,
1936 unsigned section_line,
1943 int *ip_tos = data, x;
1950 x = ip_tos_from_string(rvalue);
1952 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1953 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1961 int config_parse_unit_condition_path(const char *unit,
1962 const char *filename,
1964 const char *section,
1965 unsigned section_line,
1972 ConditionType cond = ltype;
1974 bool trigger, negate;
1976 _cleanup_free_ char *p = NULL;
1984 if (isempty(rvalue)) {
1985 /* Empty assignment resets the list */
1986 condition_free_list(u->conditions);
1987 u->conditions = NULL;
1991 trigger = rvalue[0] == '|';
1995 negate = rvalue[0] == '!';
1999 r = unit_full_printf(u, rvalue, &p);
2001 log_syntax(unit, LOG_ERR, filename, line, -r,
2002 "Failed to resolve specifiers, ignoring: %s", rvalue);
2009 if (!path_is_absolute(p)) {
2010 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2011 "Path in condition not absolute, ignoring: %s", p);
2015 c = condition_new(cond, p, trigger, negate);
2019 LIST_PREPEND(conditions, u->conditions, c);
2023 int config_parse_unit_condition_string(const char *unit,
2024 const char *filename,
2026 const char *section,
2027 unsigned section_line,
2034 ConditionType cond = ltype;
2036 bool trigger, negate;
2038 _cleanup_free_ char *s = NULL;
2046 if (isempty(rvalue)) {
2047 /* Empty assignment resets the list */
2048 condition_free_list(u->conditions);
2049 u->conditions = NULL;
2053 trigger = rvalue[0] == '|';
2057 negate = rvalue[0] == '!';
2061 r = unit_full_printf(u, rvalue, &s);
2063 log_syntax(unit, LOG_ERR, filename, line, -r,
2064 "Failed to resolve specifiers, ignoring: %s", rvalue);
2071 c = condition_new(cond, s, trigger, negate);
2075 LIST_PREPEND(conditions, u->conditions, c);
2079 int config_parse_unit_condition_null(const char *unit,
2080 const char *filename,
2082 const char *section,
2083 unsigned section_line,
2092 bool trigger, negate;
2100 if (isempty(rvalue)) {
2101 /* Empty assignment resets the list */
2102 condition_free_list(u->conditions);
2103 u->conditions = NULL;
2107 trigger = rvalue[0] == '|';
2111 negate = rvalue[0] == '!';
2115 b = parse_boolean(rvalue);
2117 log_syntax(unit, LOG_ERR, filename, line, -b,
2118 "Failed to parse boolean value in condition, ignoring: %s",
2126 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2130 LIST_PREPEND(conditions, u->conditions, c);
2134 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2135 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2137 int config_parse_unit_requires_mounts_for(
2139 const char *filename,
2141 const char *section,
2142 unsigned section_line,
2150 const char *word, *state;
2158 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2160 _cleanup_free_ char *n;
2162 n = strndup(word, l);
2166 if (!utf8_is_valid(n)) {
2167 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2171 r = unit_require_mounts_for(u, n);
2173 log_syntax(unit, LOG_ERR, filename, line, -r,
2174 "Failed to add required mount for, ignoring: %s", rvalue);
2178 if (!isempty(state))
2179 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2180 "Trailing garbage, ignoring.");
2185 int config_parse_documentation(const char *unit,
2186 const char *filename,
2188 const char *section,
2189 unsigned section_line,
2205 if (isempty(rvalue)) {
2206 /* Empty assignment resets the list */
2207 strv_free(u->documentation);
2208 u->documentation = NULL;
2212 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2213 rvalue, data, userdata);
2217 for (a = b = u->documentation; a && *a; a++) {
2219 if (is_valid_documentation_url(*a))
2222 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2223 "Invalid URL, ignoring: %s", *a);
2234 int config_parse_syscall_filter(
2236 const char *filename,
2238 const char *section,
2239 unsigned section_line,
2246 static const char default_syscalls[] =
2253 ExecContext *c = data;
2255 bool invert = false;
2256 const char *word, *state;
2265 if (isempty(rvalue)) {
2266 /* Empty assignment resets the list */
2267 set_free(c->syscall_filter);
2268 c->syscall_filter = NULL;
2269 c->syscall_whitelist = false;
2273 if (rvalue[0] == '~') {
2278 if (!c->syscall_filter) {
2279 c->syscall_filter = set_new(NULL);
2280 if (!c->syscall_filter)
2284 /* Allow everything but the ones listed */
2285 c->syscall_whitelist = false;
2289 /* Allow nothing but the ones listed */
2290 c->syscall_whitelist = true;
2292 /* Accept default syscalls if we are on a whitelist */
2293 NULSTR_FOREACH(i, default_syscalls) {
2296 id = seccomp_syscall_resolve_name(i);
2300 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2309 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2310 _cleanup_free_ char *t = NULL;
2313 t = strndup(word, l);
2317 id = seccomp_syscall_resolve_name(t);
2319 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2320 "Failed to parse system call, ignoring: %s", t);
2324 /* If we previously wanted to forbid a syscall and now
2325 * we want to allow it, then remove it from the list
2327 if (!invert == c->syscall_whitelist) {
2328 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2334 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2336 if (!isempty(state))
2337 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2338 "Trailing garbage, ignoring.");
2340 /* Turn on NNP, but only if it wasn't configured explicitly
2341 * before, and only if we are in user mode. */
2342 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2343 c->no_new_privileges = true;
2348 int config_parse_syscall_archs(
2350 const char *filename,
2352 const char *section,
2353 unsigned section_line,
2361 const char *word, *state;
2365 if (isempty(rvalue)) {
2371 r = set_ensure_allocated(archs, NULL);
2375 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2376 _cleanup_free_ char *t = NULL;
2379 t = strndup(word, l);
2383 r = seccomp_arch_from_string(t, &a);
2385 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2386 "Failed to parse system call architecture, ignoring: %s", t);
2390 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2396 if (!isempty(state))
2397 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2398 "Trailing garbage, ignoring.");
2403 int config_parse_syscall_errno(
2405 const char *filename,
2407 const char *section,
2408 unsigned section_line,
2415 ExecContext *c = data;
2422 if (isempty(rvalue)) {
2423 /* Empty assignment resets to KILL */
2424 c->syscall_errno = 0;
2428 e = errno_from_name(rvalue);
2430 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2431 "Failed to parse error number, ignoring: %s", rvalue);
2435 c->syscall_errno = e;
2439 int config_parse_address_families(
2441 const char *filename,
2443 const char *section,
2444 unsigned section_line,
2451 ExecContext *c = data;
2453 bool invert = false;
2454 const char *word, *state;
2463 if (isempty(rvalue)) {
2464 /* Empty assignment resets the list */
2465 set_free(c->address_families);
2466 c->address_families = NULL;
2467 c->address_families_whitelist = false;
2471 if (rvalue[0] == '~') {
2476 if (!c->address_families) {
2477 c->address_families = set_new(NULL);
2478 if (!c->address_families)
2481 c->address_families_whitelist = !invert;
2484 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2485 _cleanup_free_ char *t = NULL;
2488 t = strndup(word, l);
2492 af = af_from_name(t);
2494 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2495 "Failed to parse address family, ignoring: %s", t);
2499 /* If we previously wanted to forbid an address family and now
2500 * we want to allow it, then remove it from the list
2502 if (!invert == c->address_families_whitelist) {
2503 r = set_put(c->address_families, INT_TO_PTR(af));
2509 set_remove(c->address_families, INT_TO_PTR(af));
2511 if (!isempty(state))
2512 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2513 "Trailing garbage, ignoring.");
2519 int config_parse_unit_slice(
2521 const char *filename,
2523 const char *section,
2524 unsigned section_line,
2531 _cleanup_free_ char *k = NULL;
2532 Unit *u = userdata, *slice;
2540 r = unit_name_printf(u, rvalue, &k);
2542 log_syntax(unit, LOG_ERR, filename, line, -r,
2543 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2550 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2552 log_syntax(unit, LOG_ERR, filename, line, -r,
2553 "Failed to load slice unit %s. Ignoring.", k);
2557 if (slice->type != UNIT_SLICE) {
2558 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2559 "Slice unit %s is not a slice. Ignoring.", k);
2563 unit_ref_set(&u->slice, slice);
2567 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2569 int config_parse_cpu_shares(
2571 const char *filename,
2573 const char *section,
2574 unsigned section_line,
2581 unsigned long *shares = data, lu;
2588 if (isempty(rvalue)) {
2589 *shares = (unsigned long) -1;
2593 r = safe_atolu(rvalue, &lu);
2594 if (r < 0 || lu <= 0) {
2595 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2596 "CPU shares '%s' invalid. Ignoring.", rvalue);
2604 int config_parse_cpu_quota(
2606 const char *filename,
2608 const char *section,
2609 unsigned section_line,
2616 CGroupContext *c = data;
2623 if (isempty(rvalue)) {
2624 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2628 if (!endswith(rvalue, "%")) {
2630 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2631 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2635 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2636 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2637 "CPU quota '%s' invalid. Ignoring.", rvalue);
2641 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2646 int config_parse_memory_limit(
2648 const char *filename,
2650 const char *section,
2651 unsigned section_line,
2658 CGroupContext *c = data;
2662 if (isempty(rvalue)) {
2663 c->memory_limit = (uint64_t) -1;
2667 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2669 r = parse_size(rvalue, 1024, &bytes);
2671 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2672 "Memory limit '%s' invalid. Ignoring.", rvalue);
2676 c->memory_limit = (uint64_t) bytes;
2680 int config_parse_device_allow(
2682 const char *filename,
2684 const char *section,
2685 unsigned section_line,
2692 _cleanup_free_ char *path = NULL;
2693 CGroupContext *c = data;
2694 CGroupDeviceAllow *a;
2698 if (isempty(rvalue)) {
2699 while (c->device_allow)
2700 cgroup_context_free_device_allow(c, c->device_allow);
2705 n = strcspn(rvalue, WHITESPACE);
2706 path = strndup(rvalue, n);
2710 if (!startswith(path, "/dev/") &&
2711 !startswith(path, "block-") &&
2712 !startswith(path, "char-")) {
2713 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2714 "Invalid device node path '%s'. Ignoring.", path);
2718 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2722 if (!in_charset(m, "rwm")) {
2723 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2724 "Invalid device rights '%s'. Ignoring.", m);
2728 a = new0(CGroupDeviceAllow, 1);
2734 a->r = !!strchr(m, 'r');
2735 a->w = !!strchr(m, 'w');
2736 a->m = !!strchr(m, 'm');
2738 LIST_PREPEND(device_allow, c->device_allow, a);
2742 int config_parse_blockio_weight(
2744 const char *filename,
2746 const char *section,
2747 unsigned section_line,
2754 unsigned long *weight = data, lu;
2761 if (isempty(rvalue)) {
2762 *weight = (unsigned long) -1;
2766 r = safe_atolu(rvalue, &lu);
2767 if (r < 0 || lu < 10 || lu > 1000) {
2768 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2769 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2777 int config_parse_blockio_device_weight(
2779 const char *filename,
2781 const char *section,
2782 unsigned section_line,
2789 _cleanup_free_ char *path = NULL;
2790 CGroupBlockIODeviceWeight *w;
2791 CGroupContext *c = data;
2801 if (isempty(rvalue)) {
2802 while (c->blockio_device_weights)
2803 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2808 n = strcspn(rvalue, WHITESPACE);
2809 weight = rvalue + n;
2811 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2812 "Expected block device and device weight. Ignoring.");
2816 path = strndup(rvalue, n);
2820 if (!path_startswith(path, "/dev")) {
2821 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2822 "Invalid device node path '%s'. Ignoring.", path);
2826 weight += strspn(weight, WHITESPACE);
2827 r = safe_atolu(weight, &lu);
2828 if (r < 0 || lu < 10 || lu > 1000) {
2829 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2830 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2834 w = new0(CGroupBlockIODeviceWeight, 1);
2843 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2847 int config_parse_blockio_bandwidth(
2849 const char *filename,
2851 const char *section,
2852 unsigned section_line,
2859 _cleanup_free_ char *path = NULL;
2860 CGroupBlockIODeviceBandwidth *b;
2861 CGroupContext *c = data;
2862 const char *bandwidth;
2872 read = streq("BlockIOReadBandwidth", lvalue);
2874 if (isempty(rvalue)) {
2875 CGroupBlockIODeviceBandwidth *next;
2877 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2878 if (b->read == read)
2879 cgroup_context_free_blockio_device_bandwidth(c, b);
2884 n = strcspn(rvalue, WHITESPACE);
2885 bandwidth = rvalue + n;
2886 bandwidth += strspn(bandwidth, WHITESPACE);
2889 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2890 "Expected space separated pair of device node and bandwidth. Ignoring.");
2894 path = strndup(rvalue, n);
2898 if (!path_startswith(path, "/dev")) {
2899 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2900 "Invalid device node path '%s'. Ignoring.", path);
2904 r = parse_size(bandwidth, 1000, &bytes);
2905 if (r < 0 || bytes <= 0) {
2906 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2907 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2911 b = new0(CGroupBlockIODeviceBandwidth, 1);
2917 b->bandwidth = (uint64_t) bytes;
2920 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2925 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2927 int config_parse_job_mode_isolate(
2929 const char *filename,
2931 const char *section,
2932 unsigned section_line,
2946 r = parse_boolean(rvalue);
2948 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2949 "Failed to parse boolean, ignoring: %s", rvalue);
2953 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2957 int config_parse_personality(
2959 const char *filename,
2961 const char *section,
2962 unsigned section_line,
2969 unsigned long *personality = data, p;
2974 assert(personality);
2976 p = personality_from_string(rvalue);
2977 if (p == 0xffffffffUL) {
2978 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2979 "Failed to parse personality, ignoring: %s", rvalue);
2987 int config_parse_runtime_directory(
2989 const char *filename,
2991 const char *section,
2992 unsigned section_line,
3000 const char *word, *state;
3009 if (isempty(rvalue)) {
3010 /* Empty assignment resets the list */
3016 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3017 _cleanup_free_ char *n;
3019 n = strndup(word, l);
3023 if (!filename_is_safe(n)) {
3024 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3025 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3029 r = strv_push(rt, n);
3035 if (!isempty(state))
3036 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3037 "Trailing garbage, ignoring.");
3042 int config_parse_set_status(
3044 const char *filename,
3046 const char *section,
3047 unsigned section_line,
3055 const char *word, *state;
3057 ExitStatusSet *status_set = data;
3064 /* Empty assignment resets the list */
3065 if (isempty(rvalue)) {
3066 exit_status_set_free(status_set);
3070 FOREACH_WORD(word, l, rvalue, state) {
3071 _cleanup_free_ char *temp;
3074 temp = strndup(word, l);
3078 r = safe_atoi(temp, &val);
3080 val = signal_from_string_try_harder(temp);
3083 log_syntax(unit, LOG_ERR, filename, line, -val,
3084 "Failed to parse value, ignoring: %s", word);
3088 if (val < 0 || val > 255) {
3089 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3090 "Value %d is outside range 0-255, ignoring", val);
3095 r = set_ensure_allocated(&status_set->status, NULL);
3099 r = set_put(status_set->status, INT_TO_PTR(val));
3101 log_syntax(unit, LOG_ERR, filename, line, -r,
3102 "Unable to store: %s", word);
3106 if (!isempty(state))
3107 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3108 "Trailing garbage, ignoring.");
3113 int config_parse_namespace_path_strv(
3115 const char *filename,
3117 const char *section,
3118 unsigned section_line,
3126 const char *word, *state;
3135 if (isempty(rvalue)) {
3136 /* Empty assignment resets the list */
3142 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3143 _cleanup_free_ char *n;
3146 n = strndup(word, l);
3150 if (!utf8_is_valid(n)) {
3151 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3155 offset = n[0] == '-';
3156 if (!path_is_absolute(n + offset)) {
3157 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3158 "Not an absolute path, ignoring: %s", rvalue);
3162 path_kill_slashes(n);
3164 r = strv_push(sv, n);
3170 if (!isempty(state))
3171 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3172 "Trailing garbage, ignoring.");
3177 int config_parse_no_new_privileges(
3179 const char *filename,
3181 const char *section,
3182 unsigned section_line,
3189 ExecContext *c = data;
3197 k = parse_boolean(rvalue);
3199 log_syntax(unit, LOG_ERR, filename, line, -k,
3200 "Failed to parse boolean value, ignoring: %s", rvalue);
3204 c->no_new_privileges = !!k;
3205 c->no_new_privileges_set = true;
3210 int config_parse_protect_home(
3212 const char *filename,
3214 const char *section,
3215 unsigned section_line,
3222 ExecContext *c = data;
3230 /* Our enum shall be a superset of booleans, hence first try
3231 * to parse as as boolean, and then as enum */
3233 k = parse_boolean(rvalue);
3235 c->protect_home = PROTECT_HOME_YES;
3237 c->protect_home = PROTECT_HOME_NO;
3241 h = protect_home_from_string(rvalue);
3243 log_syntax(unit, LOG_ERR, filename, line, -h,
3244 "Failed to parse protect home value, ignoring: %s", rvalue);
3248 c->protect_home = h;
3254 int config_parse_protect_system(
3256 const char *filename,
3258 const char *section,
3259 unsigned section_line,
3266 ExecContext *c = data;
3274 /* Our enum shall be a superset of booleans, hence first try
3275 * to parse as as boolean, and then as enum */
3277 k = parse_boolean(rvalue);
3279 c->protect_system = PROTECT_SYSTEM_YES;
3281 c->protect_system = PROTECT_SYSTEM_NO;
3285 s = protect_system_from_string(rvalue);
3287 log_syntax(unit, LOG_ERR, filename, line, -s,
3288 "Failed to parse protect system value, ignoring: %s", rvalue);
3292 c->protect_system = s;
3298 #define FOLLOW_MAX 8
3300 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3311 /* This will update the filename pointer if the loaded file is
3312 * reached by a symlink. The old string will be freed. */
3315 char *target, *name;
3317 if (c++ >= FOLLOW_MAX)
3320 path_kill_slashes(*filename);
3322 /* Add the file name we are currently looking at to
3323 * the names of this unit, but only if it is a valid
3325 name = basename(*filename);
3327 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3329 id = set_get(names, name);
3335 r = set_consume(names, id);
3341 /* Try to open the file name, but don't if its a symlink */
3342 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3349 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3350 r = readlink_and_make_absolute(*filename, &target);
3358 f = fdopen(fd, "re");
3370 static int merge_by_names(Unit **u, Set *names, const char *id) {
3378 /* Let's try to add in all symlink names we found */
3379 while ((k = set_steal_first(names))) {
3381 /* First try to merge in the other name into our
3383 r = unit_merge_by_name(*u, k);
3387 /* Hmm, we couldn't merge the other unit into
3388 * ours? Then let's try it the other way
3391 other = manager_get_unit((*u)->manager, k);
3395 r = unit_merge(other, *u);
3398 return merge_by_names(u, names, NULL);
3406 unit_choose_id(*u, id);
3414 static int load_from_path(Unit *u, const char *path) {
3416 _cleanup_set_free_free_ Set *symlink_names = NULL;
3417 _cleanup_fclose_ FILE *f = NULL;
3418 _cleanup_free_ char *filename = NULL;
3426 symlink_names = set_new(&string_hash_ops);
3430 if (path_is_absolute(path)) {
3432 filename = strdup(path);
3436 r = open_follow(&filename, &f, symlink_names, &id);
3448 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3450 /* Instead of opening the path right away, we manually
3451 * follow all symlinks and add their name to our unit
3452 * name set while doing so */
3453 filename = path_make_absolute(path, *p);
3457 if (u->manager->unit_path_cache &&
3458 !set_get(u->manager->unit_path_cache, filename))
3461 r = open_follow(&filename, &f, symlink_names, &id);
3470 /* Empty the symlink names for the next run */
3471 set_clear_free(symlink_names);
3480 /* Hmm, no suitable file found? */
3484 r = merge_by_names(&merged, symlink_names, id);
3489 u->load_state = UNIT_MERGED;
3493 if (fstat(fileno(f), &st) < 0)
3496 if (null_or_empty(&st))
3497 u->load_state = UNIT_MASKED;
3499 u->load_state = UNIT_LOADED;
3501 /* Now, parse the file contents */
3502 r = config_parse(u->id, filename, f,
3503 UNIT_VTABLE(u)->sections,
3504 config_item_perf_lookup, load_fragment_gperf_lookup,
3505 false, true, false, u);
3510 free(u->fragment_path);
3511 u->fragment_path = filename;
3514 u->fragment_mtime = timespec_load(&st.st_mtim);
3516 if (u->source_path) {
3517 if (stat(u->source_path, &st) >= 0)
3518 u->source_mtime = timespec_load(&st.st_mtim);
3520 u->source_mtime = 0;
3526 int unit_load_fragment(Unit *u) {
3532 assert(u->load_state == UNIT_STUB);
3535 /* First, try to find the unit under its id. We always look
3536 * for unit files in the default directories, to make it easy
3537 * to override things by placing things in /etc/systemd/system */
3538 r = load_from_path(u, u->id);
3542 /* Try to find an alias we can load this with */
3543 if (u->load_state == UNIT_STUB)
3544 SET_FOREACH(t, u->names, i) {
3549 r = load_from_path(u, t);
3553 if (u->load_state != UNIT_STUB)
3557 /* And now, try looking for it under the suggested (originally linked) path */
3558 if (u->load_state == UNIT_STUB && u->fragment_path) {
3560 r = load_from_path(u, u->fragment_path);
3564 if (u->load_state == UNIT_STUB) {
3565 /* Hmm, this didn't work? Then let's get rid
3566 * of the fragment path stored for us, so that
3567 * we don't point to an invalid location. */
3568 free(u->fragment_path);
3569 u->fragment_path = NULL;
3573 /* Look for a template */
3574 if (u->load_state == UNIT_STUB && u->instance) {
3575 _cleanup_free_ char *k;
3577 k = unit_name_template(u->id);
3581 r = load_from_path(u, k);
3585 if (u->load_state == UNIT_STUB)
3586 SET_FOREACH(t, u->names, i) {
3587 _cleanup_free_ char *z = NULL;
3592 z = unit_name_template(t);
3596 r = load_from_path(u, z);
3600 if (u->load_state != UNIT_STUB)
3608 void unit_dump_config_items(FILE *f) {
3609 static const struct {
3610 const ConfigParserCallback callback;
3613 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3614 { config_parse_warn_compat, "NOTSUPPORTED" },
3616 { config_parse_int, "INTEGER" },
3617 { config_parse_unsigned, "UNSIGNED" },
3618 { config_parse_iec_size, "SIZE" },
3619 { config_parse_iec_off, "SIZE" },
3620 { config_parse_si_size, "SIZE" },
3621 { config_parse_bool, "BOOLEAN" },
3622 { config_parse_string, "STRING" },
3623 { config_parse_path, "PATH" },
3624 { config_parse_unit_path_printf, "PATH" },
3625 { config_parse_strv, "STRING [...]" },
3626 { config_parse_exec_nice, "NICE" },
3627 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3628 { config_parse_exec_io_class, "IOCLASS" },
3629 { config_parse_exec_io_priority, "IOPRIORITY" },
3630 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3631 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3632 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3633 { config_parse_mode, "MODE" },
3634 { config_parse_unit_env_file, "FILE" },
3635 { config_parse_output, "OUTPUT" },
3636 { config_parse_input, "INPUT" },
3637 { config_parse_log_facility, "FACILITY" },
3638 { config_parse_log_level, "LEVEL" },
3639 { config_parse_exec_capabilities, "CAPABILITIES" },
3640 { config_parse_exec_secure_bits, "SECUREBITS" },
3641 { config_parse_bounding_set, "BOUNDINGSET" },
3642 { config_parse_limit, "LIMIT" },
3643 { config_parse_unit_deps, "UNIT [...]" },
3644 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3645 { config_parse_service_type, "SERVICETYPE" },
3646 { config_parse_service_restart, "SERVICERESTART" },
3647 #ifdef HAVE_SYSV_COMPAT
3648 { config_parse_sysv_priority, "SYSVPRIORITY" },
3650 { config_parse_kill_mode, "KILLMODE" },
3651 { config_parse_kill_signal, "SIGNAL" },
3652 { config_parse_socket_listen, "SOCKET [...]" },
3653 { config_parse_socket_bind, "SOCKETBIND" },
3654 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3655 { config_parse_sec, "SECONDS" },
3656 { config_parse_nsec, "NANOSECONDS" },
3657 { config_parse_namespace_path_strv, "PATH [...]" },
3658 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3659 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3660 { config_parse_unit_string_printf, "STRING" },
3661 { config_parse_trigger_unit, "UNIT" },
3662 { config_parse_timer, "TIMER" },
3663 { config_parse_path_spec, "PATH" },
3664 { config_parse_notify_access, "ACCESS" },
3665 { config_parse_ip_tos, "TOS" },
3666 { config_parse_unit_condition_path, "CONDITION" },
3667 { config_parse_unit_condition_string, "CONDITION" },
3668 { config_parse_unit_condition_null, "CONDITION" },
3669 { config_parse_unit_slice, "SLICE" },
3670 { config_parse_documentation, "URL" },
3671 { config_parse_service_timeout, "SECONDS" },
3672 { config_parse_failure_action, "ACTION" },
3673 { config_parse_set_status, "STATUS" },
3674 { config_parse_service_sockets, "SOCKETS" },
3675 { config_parse_environ, "ENVIRON" },
3677 { config_parse_syscall_filter, "SYSCALLS" },
3678 { config_parse_syscall_archs, "ARCHS" },
3679 { config_parse_syscall_errno, "ERRNO" },
3680 { config_parse_address_families, "FAMILIES" },
3682 { config_parse_cpu_shares, "SHARES" },
3683 { config_parse_memory_limit, "LIMIT" },
3684 { config_parse_device_allow, "DEVICE" },
3685 { config_parse_device_policy, "POLICY" },
3686 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3687 { config_parse_blockio_weight, "WEIGHT" },
3688 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3689 { config_parse_long, "LONG" },
3690 { config_parse_socket_service, "SERVICE" },
3692 { config_parse_exec_selinux_context, "LABEL" },
3694 { config_parse_job_mode, "MODE" },
3695 { config_parse_job_mode_isolate, "BOOLEAN" },
3696 { config_parse_personality, "PERSONALITY" },
3699 const char *prev = NULL;
3704 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3705 const char *rvalue = "OTHER", *lvalue;
3709 const ConfigPerfItem *p;
3711 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3713 dot = strchr(i, '.');
3714 lvalue = dot ? dot + 1 : i;
3718 if (!prev || !strneq(prev, i, prefix_len+1)) {
3722 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3725 for (j = 0; j < ELEMENTSOF(table); j++)
3726 if (p->parse == table[j].callback) {
3727 rvalue = table[j].rvalue;
3731 fprintf(f, "%s=%s\n", lvalue, rvalue);