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, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1209 if (!isempty(state))
1210 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1211 "Trailing garbage, ignoring.");
1213 c->mount_flags = flags;
1217 int config_parse_exec_selinux_context(
1219 const char *filename,
1221 const char *section,
1222 unsigned section_line,
1229 ExecContext *c = data;
1240 if (isempty(rvalue)) {
1241 free(c->selinux_context);
1242 c->selinux_context = NULL;
1243 c->selinux_context_ignore = false;
1247 if (rvalue[0] == '-') {
1253 r = unit_name_printf(u, rvalue, &k);
1255 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1259 free(c->selinux_context);
1260 c->selinux_context = k;
1261 c->selinux_context_ignore = ignore;
1266 int config_parse_exec_apparmor_profile(
1268 const char *filename,
1270 const char *section,
1271 unsigned section_line,
1278 ExecContext *c = data;
1289 if (isempty(rvalue)) {
1290 free(c->apparmor_profile);
1291 c->apparmor_profile = NULL;
1292 c->apparmor_profile_ignore = false;
1296 if (rvalue[0] == '-') {
1302 r = unit_name_printf(u, rvalue, &k);
1304 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1308 free(c->apparmor_profile);
1309 c->apparmor_profile = k;
1310 c->apparmor_profile_ignore = ignore;
1315 int config_parse_timer(const char *unit,
1316 const char *filename,
1318 const char *section,
1319 unsigned section_line,
1330 CalendarSpec *c = NULL;
1337 if (isempty(rvalue)) {
1338 /* Empty assignment resets list */
1339 timer_free_values(t);
1343 b = timer_base_from_string(lvalue);
1345 log_syntax(unit, LOG_ERR, filename, line, -b,
1346 "Failed to parse timer base, ignoring: %s", lvalue);
1350 if (b == TIMER_CALENDAR) {
1351 if (calendar_spec_from_string(rvalue, &c) < 0) {
1352 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1353 "Failed to parse calendar specification, ignoring: %s",
1358 if (parse_sec(rvalue, &u) < 0) {
1359 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1360 "Failed to parse timer value, ignoring: %s",
1366 v = new0(TimerValue, 1);
1372 v->calendar_spec = c;
1374 LIST_PREPEND(value, t->values, v);
1379 int config_parse_trigger_unit(
1381 const char *filename,
1383 const char *section,
1384 unsigned section_line,
1391 _cleanup_free_ char *p = NULL;
1401 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1402 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1403 "Multiple units to trigger specified, ignoring: %s", rvalue);
1407 r = unit_name_printf(u, rvalue, &p);
1409 log_syntax(unit, LOG_ERR, filename, line, -r,
1410 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1412 type = unit_name_to_type(p ?: rvalue);
1414 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1415 "Unit type not valid, ignoring: %s", rvalue);
1419 if (type == u->type) {
1420 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1421 "Trigger cannot be of same type, ignoring: %s", rvalue);
1425 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1427 log_syntax(unit, LOG_ERR, filename, line, -r,
1428 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1435 int config_parse_path_spec(const char *unit,
1436 const char *filename,
1438 const char *section,
1439 unsigned section_line,
1449 _cleanup_free_ char *k = NULL;
1457 if (isempty(rvalue)) {
1458 /* Empty assignment clears list */
1463 b = path_type_from_string(lvalue);
1465 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1466 "Failed to parse path type, ignoring: %s", lvalue);
1470 r = unit_full_printf(UNIT(p), rvalue, &k);
1476 log_syntax(unit, LOG_ERR, filename, line, -r,
1477 "Failed to resolve unit specifiers on %s. Ignoring.",
1481 if (!path_is_absolute(k)) {
1482 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1483 "Path is not absolute, ignoring: %s", k);
1487 s = new0(PathSpec, 1);
1492 s->path = path_kill_slashes(k);
1497 LIST_PREPEND(spec, p->specs, s);
1502 int config_parse_socket_service(const char *unit,
1503 const char *filename,
1505 const char *section,
1506 unsigned section_line,
1513 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1517 _cleanup_free_ char *p = NULL;
1524 r = unit_name_printf(UNIT(s), rvalue, &p);
1526 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1530 if (!endswith(p, ".service")) {
1531 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1535 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1537 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1541 unit_ref_set(&s->service, x);
1546 int config_parse_service_sockets(const char *unit,
1547 const char *filename,
1549 const char *section,
1550 unsigned section_line,
1559 const char *word, *state;
1567 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1568 _cleanup_free_ char *t = NULL, *k = NULL;
1570 t = strndup(word, l);
1574 r = unit_name_printf(UNIT(s), t, &k);
1576 log_syntax(unit, LOG_ERR, filename, line, -r,
1577 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1579 if (!endswith(k ?: t, ".socket")) {
1580 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1581 "Unit must be of type socket, ignoring: %s", k ?: t);
1585 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1587 log_syntax(unit, LOG_ERR, filename, line, -r,
1588 "Failed to add dependency on %s, ignoring: %s",
1589 k ?: t, strerror(-r));
1591 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1595 if (!isempty(state))
1596 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1597 "Trailing garbage, ignoring.");
1602 int config_parse_service_timeout(const char *unit,
1603 const char *filename,
1605 const char *section,
1606 unsigned section_line,
1613 Service *s = userdata;
1621 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1622 rvalue, data, userdata);
1626 if (streq(lvalue, "TimeoutSec")) {
1627 s->start_timeout_defined = true;
1628 s->timeout_stop_usec = s->timeout_start_usec;
1629 } else if (streq(lvalue, "TimeoutStartSec"))
1630 s->start_timeout_defined = true;
1635 int config_parse_busname_service(
1637 const char *filename,
1639 const char *section,
1640 unsigned section_line,
1647 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1651 _cleanup_free_ char *p = NULL;
1658 r = unit_name_printf(UNIT(n), rvalue, &p);
1660 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1664 if (!endswith(p, ".service")) {
1665 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1669 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1671 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1675 unit_ref_set(&n->service, x);
1680 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, busname_policy_access, BusNamePolicyAccess, "Failed to parse bus name policy access");
1682 int config_parse_bus_policy(
1684 const char *filename,
1686 const char *section,
1687 unsigned section_line,
1694 _cleanup_free_ BusNamePolicy *p = NULL;
1695 _cleanup_free_ char *id_str = NULL;
1696 BusName *busname = data;
1704 p = new0(BusNamePolicy, 1);
1708 if (streq(lvalue, "AllowUser"))
1709 p->type = BUSNAME_POLICY_TYPE_USER;
1710 else if (streq(lvalue, "AllowGroup"))
1711 p->type = BUSNAME_POLICY_TYPE_GROUP;
1713 assert_not_reached("Unknown lvalue");
1715 id_str = strdup(rvalue);
1719 access_str = strpbrk(id_str, WHITESPACE);
1721 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy value '%s'", rvalue);
1727 access_str += strspn(access_str, WHITESPACE);
1729 p->access = busname_policy_access_from_string(access_str);
1730 if (p->access < 0) {
1731 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy access type '%s'", access_str);
1738 LIST_PREPEND(policy, busname->policy, p);
1744 int config_parse_unit_env_file(const char *unit,
1745 const char *filename,
1747 const char *section,
1748 unsigned section_line,
1757 _cleanup_free_ char *n = NULL;
1766 if (isempty(rvalue)) {
1767 /* Empty assignment frees the list */
1773 r = unit_full_printf(u, rvalue, &n);
1775 log_syntax(unit, LOG_ERR, filename, line, r,
1776 "Failed to resolve specifiers, ignoring: %s", rvalue);
1779 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1780 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1781 "Path '%s' is not absolute, ignoring.", s);
1785 r = strv_extend(env, s);
1792 int config_parse_environ(const char *unit,
1793 const char *filename,
1795 const char *section,
1796 unsigned section_line,
1805 const char *word, *state;
1807 _cleanup_free_ char *k = NULL;
1815 if (isempty(rvalue)) {
1816 /* Empty assignment resets the list */
1823 r = unit_full_printf(u, rvalue, &k);
1825 log_syntax(unit, LOG_ERR, filename, line, -r,
1826 "Failed to resolve specifiers, ignoring: %s", rvalue);
1834 FOREACH_WORD_QUOTED(word, l, k, state) {
1835 _cleanup_free_ char *n;
1838 n = cunescape_length(word, l);
1842 if (!env_assignment_is_valid(n)) {
1843 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1844 "Invalid environment assignment, ignoring: %s", rvalue);
1848 x = strv_env_set(*env, n);
1855 if (!isempty(state))
1856 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1857 "Trailing garbage, ignoring.");
1862 int config_parse_ip_tos(const char *unit,
1863 const char *filename,
1865 const char *section,
1866 unsigned section_line,
1873 int *ip_tos = data, x;
1880 x = ip_tos_from_string(rvalue);
1882 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1883 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1891 int config_parse_unit_condition_path(const char *unit,
1892 const char *filename,
1894 const char *section,
1895 unsigned section_line,
1902 ConditionType cond = ltype;
1904 bool trigger, negate;
1906 _cleanup_free_ char *p = NULL;
1914 if (isempty(rvalue)) {
1915 /* Empty assignment resets the list */
1916 condition_free_list(u->conditions);
1917 u->conditions = NULL;
1921 trigger = rvalue[0] == '|';
1925 negate = rvalue[0] == '!';
1929 r = unit_full_printf(u, rvalue, &p);
1931 log_syntax(unit, LOG_ERR, filename, line, -r,
1932 "Failed to resolve specifiers, ignoring: %s", rvalue);
1939 if (!path_is_absolute(p)) {
1940 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1941 "Path in condition not absolute, ignoring: %s", p);
1945 c = condition_new(cond, p, trigger, negate);
1949 LIST_PREPEND(conditions, u->conditions, c);
1953 int config_parse_unit_condition_string(const char *unit,
1954 const char *filename,
1956 const char *section,
1957 unsigned section_line,
1964 ConditionType cond = ltype;
1966 bool trigger, negate;
1968 _cleanup_free_ char *s = NULL;
1976 if (isempty(rvalue)) {
1977 /* Empty assignment resets the list */
1978 condition_free_list(u->conditions);
1979 u->conditions = NULL;
1983 trigger = rvalue[0] == '|';
1987 negate = rvalue[0] == '!';
1991 r = unit_full_printf(u, rvalue, &s);
1993 log_syntax(unit, LOG_ERR, filename, line, -r,
1994 "Failed to resolve specifiers, ignoring: %s", rvalue);
2001 c = condition_new(cond, s, trigger, negate);
2005 LIST_PREPEND(conditions, u->conditions, c);
2009 int config_parse_unit_condition_null(const char *unit,
2010 const char *filename,
2012 const char *section,
2013 unsigned section_line,
2022 bool trigger, negate;
2030 if (isempty(rvalue)) {
2031 /* Empty assignment resets the list */
2032 condition_free_list(u->conditions);
2033 u->conditions = NULL;
2037 trigger = rvalue[0] == '|';
2041 negate = rvalue[0] == '!';
2045 b = parse_boolean(rvalue);
2047 log_syntax(unit, LOG_ERR, filename, line, -b,
2048 "Failed to parse boolean value in condition, ignoring: %s",
2056 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2060 LIST_PREPEND(conditions, u->conditions, c);
2064 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2065 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2067 int config_parse_unit_requires_mounts_for(
2069 const char *filename,
2071 const char *section,
2072 unsigned section_line,
2080 const char *word, *state;
2088 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2090 _cleanup_free_ char *n;
2092 n = strndup(word, l);
2096 if (!utf8_is_valid(n)) {
2097 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2101 r = unit_require_mounts_for(u, n);
2103 log_syntax(unit, LOG_ERR, filename, line, r,
2104 "Failed to add required mount for, ignoring: %s", rvalue);
2108 if (!isempty(state))
2109 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2110 "Trailing garbage, ignoring.");
2115 int config_parse_documentation(const char *unit,
2116 const char *filename,
2118 const char *section,
2119 unsigned section_line,
2135 if (isempty(rvalue)) {
2136 /* Empty assignment resets the list */
2137 strv_free(u->documentation);
2138 u->documentation = NULL;
2142 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2143 rvalue, data, userdata);
2147 for (a = b = u->documentation; a && *a; a++) {
2149 if (is_valid_documentation_url(*a))
2152 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2153 "Invalid URL, ignoring: %s", *a);
2164 int config_parse_syscall_filter(
2166 const char *filename,
2168 const char *section,
2169 unsigned section_line,
2176 static const char default_syscalls[] =
2183 ExecContext *c = data;
2185 bool invert = false;
2186 const char *word, *state;
2195 if (isempty(rvalue)) {
2196 /* Empty assignment resets the list */
2197 set_free(c->syscall_filter);
2198 c->syscall_filter = NULL;
2199 c->syscall_whitelist = false;
2203 if (rvalue[0] == '~') {
2208 if (!c->syscall_filter) {
2209 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2210 if (!c->syscall_filter)
2214 /* Allow everything but the ones listed */
2215 c->syscall_whitelist = false;
2219 /* Allow nothing but the ones listed */
2220 c->syscall_whitelist = true;
2222 /* Accept default syscalls if we are on a whitelist */
2223 NULSTR_FOREACH(i, default_syscalls) {
2226 id = seccomp_syscall_resolve_name(i);
2230 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2239 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2240 _cleanup_free_ char *t = NULL;
2243 t = strndup(word, l);
2247 id = seccomp_syscall_resolve_name(t);
2249 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2253 /* If we previously wanted to forbid a syscall and now
2254 * we want to allow it, then remove it from the list
2256 if (!invert == c->syscall_whitelist) {
2257 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2263 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2265 if (!isempty(state))
2266 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2267 "Trailing garbage, ignoring.");
2269 /* Turn on NNP, but only if it wasn't configured explicitly
2270 * before, and only if we are in user mode. */
2271 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2272 c->no_new_privileges = true;
2277 int config_parse_syscall_archs(
2279 const char *filename,
2281 const char *section,
2282 unsigned section_line,
2290 const char *word, *state;
2294 if (isempty(rvalue)) {
2300 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2304 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2305 _cleanup_free_ char *t = NULL;
2308 t = strndup(word, l);
2312 r = seccomp_arch_from_string(t, &a);
2314 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2318 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2324 if (!isempty(state))
2325 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2326 "Trailing garbage, ignoring.");
2331 int config_parse_syscall_errno(
2333 const char *filename,
2335 const char *section,
2336 unsigned section_line,
2343 ExecContext *c = data;
2350 if (isempty(rvalue)) {
2351 /* Empty assignment resets to KILL */
2352 c->syscall_errno = 0;
2356 e = errno_from_name(rvalue);
2358 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2362 c->syscall_errno = e;
2366 int config_parse_address_families(
2368 const char *filename,
2370 const char *section,
2371 unsigned section_line,
2378 ExecContext *c = data;
2380 bool invert = false;
2381 const char *word, *state;
2390 if (isempty(rvalue)) {
2391 /* Empty assignment resets the list */
2392 set_free(c->address_families);
2393 c->address_families = NULL;
2394 c->address_families_whitelist = false;
2398 if (rvalue[0] == '~') {
2403 if (!c->address_families) {
2404 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2405 if (!c->address_families)
2408 c->address_families_whitelist = !invert;
2411 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2412 _cleanup_free_ char *t = NULL;
2415 t = strndup(word, l);
2419 af = af_from_name(t);
2421 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
2425 /* If we previously wanted to forbid an address family and now
2426 * we want to allow it, then remove it from the list
2428 if (!invert == c->address_families_whitelist) {
2429 r = set_put(c->address_families, INT_TO_PTR(af));
2435 set_remove(c->address_families, INT_TO_PTR(af));
2437 if (!isempty(state))
2438 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2439 "Trailing garbage, ignoring.");
2445 int config_parse_unit_slice(
2447 const char *filename,
2449 const char *section,
2450 unsigned section_line,
2457 _cleanup_free_ char *k = NULL;
2458 Unit *u = userdata, *slice;
2466 r = unit_name_printf(u, rvalue, &k);
2468 log_syntax(unit, LOG_ERR, filename, line, -r,
2469 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2476 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2478 log_syntax(unit, LOG_ERR, filename, line, -r,
2479 "Failed to load slice unit %s. Ignoring.", k);
2483 if (slice->type != UNIT_SLICE) {
2484 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2485 "Slice unit %s is not a slice. Ignoring.", k);
2489 unit_ref_set(&u->slice, slice);
2493 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2495 int config_parse_cpu_shares(
2497 const char *filename,
2499 const char *section,
2500 unsigned section_line,
2507 unsigned long *shares = data, lu;
2514 if (isempty(rvalue)) {
2515 *shares = (unsigned long) -1;
2519 r = safe_atolu(rvalue, &lu);
2520 if (r < 0 || lu <= 0) {
2521 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU shares '%s' invalid. Ignoring.", rvalue);
2529 int config_parse_cpu_quota(
2531 const char *filename,
2533 const char *section,
2534 unsigned section_line,
2541 CGroupContext *c = data;
2548 if (isempty(rvalue)) {
2549 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2553 if (!endswith(rvalue, "%")) {
2555 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2559 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2560 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' invalid. Ignoring.", rvalue);
2564 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2569 int config_parse_memory_limit(
2571 const char *filename,
2573 const char *section,
2574 unsigned section_line,
2581 CGroupContext *c = data;
2585 if (isempty(rvalue)) {
2586 c->memory_limit = (uint64_t) -1;
2590 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2592 r = parse_size(rvalue, 1024, &bytes);
2594 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
2598 c->memory_limit = (uint64_t) bytes;
2602 int config_parse_device_allow(
2604 const char *filename,
2606 const char *section,
2607 unsigned section_line,
2614 _cleanup_free_ char *path = NULL;
2615 CGroupContext *c = data;
2616 CGroupDeviceAllow *a;
2620 if (isempty(rvalue)) {
2621 while (c->device_allow)
2622 cgroup_context_free_device_allow(c, c->device_allow);
2627 n = strcspn(rvalue, WHITESPACE);
2628 path = strndup(rvalue, n);
2632 if (!startswith(path, "/dev/") &&
2633 !startswith(path, "block-") &&
2634 !startswith(path, "char-")) {
2635 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2639 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2643 if (!in_charset(m, "rwm")) {
2644 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
2648 a = new0(CGroupDeviceAllow, 1);
2654 a->r = !!strchr(m, 'r');
2655 a->w = !!strchr(m, 'w');
2656 a->m = !!strchr(m, 'm');
2658 LIST_PREPEND(device_allow, c->device_allow, a);
2662 int config_parse_blockio_weight(
2664 const char *filename,
2666 const char *section,
2667 unsigned section_line,
2674 unsigned long *weight = data, lu;
2681 if (isempty(rvalue)) {
2682 *weight = (unsigned long) -1;
2686 r = safe_atolu(rvalue, &lu);
2687 if (r < 0 || lu < 10 || lu > 1000) {
2688 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
2696 int config_parse_blockio_device_weight(
2698 const char *filename,
2700 const char *section,
2701 unsigned section_line,
2708 _cleanup_free_ char *path = NULL;
2709 CGroupBlockIODeviceWeight *w;
2710 CGroupContext *c = data;
2720 if (isempty(rvalue)) {
2721 while (c->blockio_device_weights)
2722 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2727 n = strcspn(rvalue, WHITESPACE);
2728 weight = rvalue + n;
2730 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Expected block device and device weight. Ignoring.");
2734 path = strndup(rvalue, n);
2738 if (!path_startswith(path, "/dev")) {
2739 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2743 weight += strspn(weight, WHITESPACE);
2744 r = safe_atolu(weight, &lu);
2745 if (r < 0 || lu < 10 || lu > 1000) {
2746 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
2750 w = new0(CGroupBlockIODeviceWeight, 1);
2759 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2763 int config_parse_blockio_bandwidth(
2765 const char *filename,
2767 const char *section,
2768 unsigned section_line,
2775 _cleanup_free_ char *path = NULL;
2776 CGroupBlockIODeviceBandwidth *b;
2777 CGroupContext *c = data;
2778 const char *bandwidth;
2788 read = streq("BlockIOReadBandwidth", lvalue);
2790 if (isempty(rvalue)) {
2791 CGroupBlockIODeviceBandwidth *next;
2793 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2794 if (b->read == read)
2795 cgroup_context_free_blockio_device_bandwidth(c, b);
2800 n = strcspn(rvalue, WHITESPACE);
2801 bandwidth = rvalue + n;
2802 bandwidth += strspn(bandwidth, WHITESPACE);
2805 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2806 "Expected space separated pair of device node and bandwidth. Ignoring.");
2810 path = strndup(rvalue, n);
2814 if (!path_startswith(path, "/dev")) {
2815 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2816 "Invalid device node path '%s'. Ignoring.", path);
2820 r = parse_size(bandwidth, 1000, &bytes);
2821 if (r < 0 || bytes <= 0) {
2822 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2826 b = new0(CGroupBlockIODeviceBandwidth, 1);
2832 b->bandwidth = (uint64_t) bytes;
2835 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2840 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2842 int config_parse_job_mode_isolate(
2844 const char *filename,
2846 const char *section,
2847 unsigned section_line,
2861 r = parse_boolean(rvalue);
2863 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2867 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2871 int config_parse_personality(
2873 const char *filename,
2875 const char *section,
2876 unsigned section_line,
2883 unsigned long *personality = data, p;
2888 assert(personality);
2890 p = personality_from_string(rvalue);
2891 if (p == 0xffffffffUL) {
2892 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2893 "Failed to parse personality, ignoring: %s", rvalue);
2901 int config_parse_runtime_directory(
2903 const char *filename,
2905 const char *section,
2906 unsigned section_line,
2914 const char *word, *state;
2923 if (isempty(rvalue)) {
2924 /* Empty assignment resets the list */
2930 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2931 _cleanup_free_ char *n;
2933 n = strndup(word, l);
2937 if (!filename_is_safe(n)) {
2938 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2942 r = strv_push(rt, n);
2948 if (!isempty(state))
2949 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2950 "Trailing garbage, ignoring.");
2955 int config_parse_set_status(
2957 const char *filename,
2959 const char *section,
2960 unsigned section_line,
2968 const char *word, *state;
2970 ExitStatusSet *status_set = data;
2977 /* Empty assignment resets the list */
2978 if (isempty(rvalue)) {
2979 exit_status_set_free(status_set);
2983 FOREACH_WORD(word, l, rvalue, state) {
2984 _cleanup_free_ char *temp;
2987 temp = strndup(word, l);
2991 r = safe_atoi(temp, &val);
2993 val = signal_from_string_try_harder(temp);
2996 r = set_ensure_allocated(&status_set->signal, NULL, NULL);
3000 r = set_put(status_set->signal, INT_TO_PTR(val));
3002 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", word);
3006 log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", word);
3010 if (val < 0 || val > 255)
3011 log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
3013 r = set_ensure_allocated(&status_set->status, NULL, NULL);
3017 r = set_put(status_set->status, INT_TO_PTR(val));
3019 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", word);
3025 if (!isempty(state))
3026 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3027 "Trailing garbage, ignoring.");
3032 int config_parse_namespace_path_strv(
3034 const char *filename,
3036 const char *section,
3037 unsigned section_line,
3045 const char *word, *state;
3054 if (isempty(rvalue)) {
3055 /* Empty assignment resets the list */
3061 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3062 _cleanup_free_ char *n;
3065 n = strndup(word, l);
3069 if (!utf8_is_valid(n)) {
3070 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3074 offset = n[0] == '-';
3075 if (!path_is_absolute(n + offset)) {
3076 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
3080 path_kill_slashes(n);
3082 r = strv_push(sv, n);
3088 if (!isempty(state))
3089 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3090 "Trailing garbage, ignoring.");
3095 int config_parse_no_new_privileges(
3097 const char *filename,
3099 const char *section,
3100 unsigned section_line,
3107 ExecContext *c = data;
3115 k = parse_boolean(rvalue);
3117 log_syntax(unit, LOG_ERR, filename, line, -k, "Failed to parse boolean value, ignoring: %s", rvalue);
3121 c->no_new_privileges = !!k;
3122 c->no_new_privileges_set = true;
3127 int config_parse_protect_home(
3129 const char *filename,
3131 const char *section,
3132 unsigned section_line,
3139 ExecContext *c = data;
3147 /* Our enum shall be a superset of booleans, hence first try
3148 * to parse as as boolean, and then as enum */
3150 k = parse_boolean(rvalue);
3152 c->protect_home = PROTECT_HOME_YES;
3154 c->protect_home = PROTECT_HOME_NO;
3158 h = protect_home_from_string(rvalue);
3160 log_syntax(unit, LOG_ERR, filename, line, -h, "Failed to parse protect home value, ignoring: %s", rvalue);
3164 c->protect_home = h;
3170 int config_parse_protect_system(
3172 const char *filename,
3174 const char *section,
3175 unsigned section_line,
3182 ExecContext *c = data;
3190 /* Our enum shall be a superset of booleans, hence first try
3191 * to parse as as boolean, and then as enum */
3193 k = parse_boolean(rvalue);
3195 c->protect_system = PROTECT_SYSTEM_YES;
3197 c->protect_system = PROTECT_SYSTEM_NO;
3201 s = protect_system_from_string(rvalue);
3203 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse protect system value, ignoring: %s", rvalue);
3207 c->protect_system = s;
3213 #define FOLLOW_MAX 8
3215 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3226 /* This will update the filename pointer if the loaded file is
3227 * reached by a symlink. The old string will be freed. */
3230 char *target, *name;
3232 if (c++ >= FOLLOW_MAX)
3235 path_kill_slashes(*filename);
3237 /* Add the file name we are currently looking at to
3238 * the names of this unit, but only if it is a valid
3240 name = basename(*filename);
3242 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3244 id = set_get(names, name);
3250 r = set_consume(names, id);
3256 /* Try to open the file name, but don't if its a symlink */
3257 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3264 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3265 r = readlink_and_make_absolute(*filename, &target);
3273 f = fdopen(fd, "re");
3285 static int merge_by_names(Unit **u, Set *names, const char *id) {
3293 /* Let's try to add in all symlink names we found */
3294 while ((k = set_steal_first(names))) {
3296 /* First try to merge in the other name into our
3298 r = unit_merge_by_name(*u, k);
3302 /* Hmm, we couldn't merge the other unit into
3303 * ours? Then let's try it the other way
3306 other = manager_get_unit((*u)->manager, k);
3310 r = unit_merge(other, *u);
3313 return merge_by_names(u, names, NULL);
3321 unit_choose_id(*u, id);
3329 static int load_from_path(Unit *u, const char *path) {
3331 _cleanup_set_free_free_ Set *symlink_names = NULL;
3332 _cleanup_fclose_ FILE *f = NULL;
3333 _cleanup_free_ char *filename = NULL;
3341 symlink_names = set_new(string_hash_func, string_compare_func);
3345 if (path_is_absolute(path)) {
3347 filename = strdup(path);
3351 r = open_follow(&filename, &f, symlink_names, &id);
3363 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3365 /* Instead of opening the path right away, we manually
3366 * follow all symlinks and add their name to our unit
3367 * name set while doing so */
3368 filename = path_make_absolute(path, *p);
3372 if (u->manager->unit_path_cache &&
3373 !set_get(u->manager->unit_path_cache, filename))
3376 r = open_follow(&filename, &f, symlink_names, &id);
3385 /* Empty the symlink names for the next run */
3386 set_clear_free(symlink_names);
3395 /* Hmm, no suitable file found? */
3399 r = merge_by_names(&merged, symlink_names, id);
3404 u->load_state = UNIT_MERGED;
3408 if (fstat(fileno(f), &st) < 0)
3411 if (null_or_empty(&st))
3412 u->load_state = UNIT_MASKED;
3414 u->load_state = UNIT_LOADED;
3416 /* Now, parse the file contents */
3417 r = config_parse(u->id, filename, f,
3418 UNIT_VTABLE(u)->sections,
3419 config_item_perf_lookup, load_fragment_gperf_lookup,
3420 false, true, false, u);
3425 free(u->fragment_path);
3426 u->fragment_path = filename;
3429 u->fragment_mtime = timespec_load(&st.st_mtim);
3431 if (u->source_path) {
3432 if (stat(u->source_path, &st) >= 0)
3433 u->source_mtime = timespec_load(&st.st_mtim);
3435 u->source_mtime = 0;
3441 int unit_load_fragment(Unit *u) {
3447 assert(u->load_state == UNIT_STUB);
3450 /* First, try to find the unit under its id. We always look
3451 * for unit files in the default directories, to make it easy
3452 * to override things by placing things in /etc/systemd/system */
3453 r = load_from_path(u, u->id);
3457 /* Try to find an alias we can load this with */
3458 if (u->load_state == UNIT_STUB)
3459 SET_FOREACH(t, u->names, i) {
3464 r = load_from_path(u, t);
3468 if (u->load_state != UNIT_STUB)
3472 /* And now, try looking for it under the suggested (originally linked) path */
3473 if (u->load_state == UNIT_STUB && u->fragment_path) {
3475 r = load_from_path(u, u->fragment_path);
3479 if (u->load_state == UNIT_STUB) {
3480 /* Hmm, this didn't work? Then let's get rid
3481 * of the fragment path stored for us, so that
3482 * we don't point to an invalid location. */
3483 free(u->fragment_path);
3484 u->fragment_path = NULL;
3488 /* Look for a template */
3489 if (u->load_state == UNIT_STUB && u->instance) {
3490 _cleanup_free_ char *k;
3492 k = unit_name_template(u->id);
3496 r = load_from_path(u, k);
3500 if (u->load_state == UNIT_STUB)
3501 SET_FOREACH(t, u->names, i) {
3502 _cleanup_free_ char *z = NULL;
3507 z = unit_name_template(t);
3511 r = load_from_path(u, z);
3515 if (u->load_state != UNIT_STUB)
3523 void unit_dump_config_items(FILE *f) {
3524 static const struct {
3525 const ConfigParserCallback callback;
3528 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3529 { config_parse_warn_compat, "NOTSUPPORTED" },
3531 { config_parse_int, "INTEGER" },
3532 { config_parse_unsigned, "UNSIGNED" },
3533 { config_parse_iec_size, "SIZE" },
3534 { config_parse_iec_off, "SIZE" },
3535 { config_parse_si_size, "SIZE" },
3536 { config_parse_bool, "BOOLEAN" },
3537 { config_parse_string, "STRING" },
3538 { config_parse_path, "PATH" },
3539 { config_parse_unit_path_printf, "PATH" },
3540 { config_parse_strv, "STRING [...]" },
3541 { config_parse_exec_nice, "NICE" },
3542 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3543 { config_parse_exec_io_class, "IOCLASS" },
3544 { config_parse_exec_io_priority, "IOPRIORITY" },
3545 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3546 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3547 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3548 { config_parse_mode, "MODE" },
3549 { config_parse_unit_env_file, "FILE" },
3550 { config_parse_output, "OUTPUT" },
3551 { config_parse_input, "INPUT" },
3552 { config_parse_log_facility, "FACILITY" },
3553 { config_parse_log_level, "LEVEL" },
3554 { config_parse_exec_capabilities, "CAPABILITIES" },
3555 { config_parse_exec_secure_bits, "SECUREBITS" },
3556 { config_parse_bounding_set, "BOUNDINGSET" },
3557 { config_parse_limit, "LIMIT" },
3558 { config_parse_unit_deps, "UNIT [...]" },
3559 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3560 { config_parse_service_type, "SERVICETYPE" },
3561 { config_parse_service_restart, "SERVICERESTART" },
3562 #ifdef HAVE_SYSV_COMPAT
3563 { config_parse_sysv_priority, "SYSVPRIORITY" },
3565 { config_parse_kill_mode, "KILLMODE" },
3566 { config_parse_kill_signal, "SIGNAL" },
3567 { config_parse_socket_listen, "SOCKET [...]" },
3568 { config_parse_socket_bind, "SOCKETBIND" },
3569 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3570 { config_parse_sec, "SECONDS" },
3571 { config_parse_nsec, "NANOSECONDS" },
3572 { config_parse_namespace_path_strv, "PATH [...]" },
3573 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3574 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3575 { config_parse_unit_string_printf, "STRING" },
3576 { config_parse_trigger_unit, "UNIT" },
3577 { config_parse_timer, "TIMER" },
3578 { config_parse_path_spec, "PATH" },
3579 { config_parse_notify_access, "ACCESS" },
3580 { config_parse_ip_tos, "TOS" },
3581 { config_parse_unit_condition_path, "CONDITION" },
3582 { config_parse_unit_condition_string, "CONDITION" },
3583 { config_parse_unit_condition_null, "CONDITION" },
3584 { config_parse_unit_slice, "SLICE" },
3585 { config_parse_documentation, "URL" },
3586 { config_parse_service_timeout, "SECONDS" },
3587 { config_parse_failure_action, "ACTION" },
3588 { config_parse_set_status, "STATUS" },
3589 { config_parse_service_sockets, "SOCKETS" },
3590 { config_parse_environ, "ENVIRON" },
3592 { config_parse_syscall_filter, "SYSCALLS" },
3593 { config_parse_syscall_archs, "ARCHS" },
3594 { config_parse_syscall_errno, "ERRNO" },
3595 { config_parse_address_families, "FAMILIES" },
3597 { config_parse_cpu_shares, "SHARES" },
3598 { config_parse_memory_limit, "LIMIT" },
3599 { config_parse_device_allow, "DEVICE" },
3600 { config_parse_device_policy, "POLICY" },
3601 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3602 { config_parse_blockio_weight, "WEIGHT" },
3603 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3604 { config_parse_long, "LONG" },
3605 { config_parse_socket_service, "SERVICE" },
3607 { config_parse_exec_selinux_context, "LABEL" },
3609 { config_parse_job_mode, "MODE" },
3610 { config_parse_job_mode_isolate, "BOOLEAN" },
3611 { config_parse_personality, "PERSONALITY" },
3614 const char *prev = NULL;
3619 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3620 const char *rvalue = "OTHER", *lvalue;
3624 const ConfigPerfItem *p;
3626 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3628 dot = strchr(i, '.');
3629 lvalue = dot ? dot + 1 : i;
3633 if (!prev || !strneq(prev, i, prefix_len+1)) {
3637 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3640 for (j = 0; j < ELEMENTSOF(table); j++)
3641 if (p->parse == table[j].callback) {
3642 rvalue = table[j].rvalue;
3646 fprintf(f, "%s=%s\n", lvalue, rvalue);