1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
7 Copyright 2012 Holger Hans Peter Freyther
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <linux/oom.h>
30 #include <sys/prctl.h>
31 #include <sys/mount.h>
35 #include <sys/resource.h>
36 #include <sys/types.h>
43 #include "sd-messages.h"
46 #include "conf-parser.h"
47 #include "load-fragment.h"
50 #include "securebits.h"
52 #include "unit-name.h"
53 #include "unit-printf.h"
55 #include "path-util.h"
59 #include "bus-error.h"
60 #include "errno-list.h"
64 #include "seccomp-util.h"
67 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
68 int config_parse_warn_compat(
73 unsigned section_line,
80 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
81 "Support for option %s= has been disabled at compile time and is ignored",
87 int config_parse_unit_deps(const char *unit,
91 unsigned section_line,
98 UnitDependency d = ltype;
100 const char *word, *state;
107 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
108 _cleanup_free_ char *t = NULL, *k = NULL;
111 t = strndup(word, l);
115 r = unit_name_printf(u, t, &k);
117 log_syntax(unit, LOG_ERR, filename, line, -r,
118 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
122 r = unit_add_dependency_by_name(u, d, k, NULL, true);
124 log_syntax(unit, LOG_ERR, filename, line, -r,
125 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
128 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
133 int config_parse_unit_string_printf(const char *unit,
134 const char *filename,
137 unsigned section_line,
145 _cleanup_free_ char *k = NULL;
153 r = unit_full_printf(u, rvalue, &k);
155 log_syntax(unit, LOG_ERR, filename, line, -r,
156 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
158 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
159 k ? k : rvalue, data, userdata);
162 int config_parse_unit_strv_printf(const char *unit,
163 const char *filename,
166 unsigned section_line,
174 _cleanup_free_ char *k = NULL;
182 r = unit_full_printf(u, rvalue, &k);
184 log_syntax(unit, LOG_ERR, filename, line, -r,
185 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
187 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
188 k ? k : rvalue, data, userdata);
191 int config_parse_unit_path_printf(const char *unit,
192 const char *filename,
195 unsigned section_line,
202 _cleanup_free_ char *k = NULL;
211 r = unit_full_printf(u, rvalue, &k);
213 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
217 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
220 int config_parse_unit_path_strv_printf(
222 const char *filename,
225 unsigned section_line,
233 const char *word, *state;
243 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
244 _cleanup_free_ char *k = NULL;
250 r = unit_full_printf(u, t, &k);
252 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
256 if (!utf8_is_valid(k)) {
257 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
261 if (!path_is_absolute(k)) {
262 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
266 path_kill_slashes(k);
275 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
280 int config_parse_socket_listen(const char *unit,
281 const char *filename,
284 unsigned section_line,
291 SocketPort *p, *tail;
302 if (isempty(rvalue)) {
303 /* An empty assignment removes all ports */
304 socket_free_ports(s);
308 p = new0(SocketPort, 1);
312 if (ltype != SOCKET_SOCKET) {
315 r = unit_full_printf(UNIT(s), rvalue, &p->path);
317 p->path = strdup(rvalue);
322 log_syntax(unit, LOG_ERR, filename, line, -r,
323 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
326 path_kill_slashes(p->path);
328 } else if (streq(lvalue, "ListenNetlink")) {
329 _cleanup_free_ char *k = NULL;
331 p->type = SOCKET_SOCKET;
332 r = unit_full_printf(UNIT(s), rvalue, &k);
334 log_syntax(unit, LOG_ERR, filename, line, -r,
335 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
337 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
339 log_syntax(unit, LOG_ERR, filename, line, -r,
340 "Failed to parse address value, ignoring: %s", rvalue);
346 _cleanup_free_ char *k = NULL;
348 p->type = SOCKET_SOCKET;
349 r = unit_full_printf(UNIT(s), rvalue, &k);
351 log_syntax(unit, LOG_ERR, filename, line, -r,
352 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
354 r = socket_address_parse(&p->address, k ? k : rvalue);
356 log_syntax(unit, LOG_ERR, filename, line, -r,
357 "Failed to parse address value, ignoring: %s", rvalue);
362 if (streq(lvalue, "ListenStream"))
363 p->address.type = SOCK_STREAM;
364 else if (streq(lvalue, "ListenDatagram"))
365 p->address.type = SOCK_DGRAM;
367 assert(streq(lvalue, "ListenSequentialPacket"));
368 p->address.type = SOCK_SEQPACKET;
371 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
372 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
373 "Address family not supported, ignoring: %s", rvalue);
383 LIST_FIND_TAIL(port, s->ports, tail);
384 LIST_INSERT_AFTER(port, s->ports, tail, p);
386 LIST_PREPEND(port, s->ports, p);
391 int config_parse_socket_bind(const char *unit,
392 const char *filename,
395 unsigned section_line,
403 SocketAddressBindIPv6Only b;
412 b = socket_address_bind_ipv6_only_from_string(rvalue);
416 r = parse_boolean(rvalue);
418 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
419 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
423 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
425 s->bind_ipv6_only = b;
430 int config_parse_exec_nice(const char *unit,
431 const char *filename,
434 unsigned section_line,
441 ExecContext *c = data;
449 r = safe_atoi(rvalue, &priority);
451 log_syntax(unit, LOG_ERR, filename, line, -r,
452 "Failed to parse nice priority, ignoring: %s. ", rvalue);
456 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
457 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
458 "Nice priority out of range, ignoring: %s", rvalue);
468 int config_parse_exec_oom_score_adjust(const char* unit,
469 const char *filename,
472 unsigned section_line,
479 ExecContext *c = data;
487 r = safe_atoi(rvalue, &oa);
489 log_syntax(unit, LOG_ERR, filename, line, -r,
490 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
494 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
495 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
496 "OOM score adjust value out of range, ignoring: %s", rvalue);
500 c->oom_score_adjust = oa;
501 c->oom_score_adjust_set = true;
506 int config_parse_exec(const char *unit,
507 const char *filename,
510 unsigned section_line,
517 ExecCommand **e = data, *nce;
529 if (isempty(rvalue)) {
530 /* An empty assignment resets the list */
531 exec_command_free_list(*e);
536 /* We accept an absolute path as first argument, or
537 * alternatively an absolute prefixed with @ to allow
538 * overriding of argv[0]. */
541 const char *word, *state;
543 bool honour_argv0 = false, ignore = false;
549 rvalue += strspn(rvalue, WHITESPACE);
554 for (i = 0; i < 2; i++) {
555 if (rvalue[0] == '-' && !ignore) {
560 if (rvalue[0] == '@' && !honour_argv0) {
566 if (*rvalue != '/') {
567 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
568 "Executable path is not absolute, ignoring: %s", rvalue);
573 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
574 if (strneq(word, ";", MAX(l, 1U)))
579 if (!isempty(state)) {
580 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
581 "Trailing garbage, ignoring.");
586 n = new(char*, k + !honour_argv0);
591 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
592 if (strneq(word, ";", MAX(l, 1U)))
594 else if (strneq(word, "\\;", MAX(l, 1U)))
597 if (honour_argv0 && word == rvalue) {
600 path = strndup(word, l);
606 if (!utf8_is_valid(path)) {
607 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
615 c = n[k++] = cunescape_length(word, l);
621 if (!utf8_is_valid(c)) {
622 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
632 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
633 "Invalid command line, ignoring: %s", rvalue);
646 assert(path_is_absolute(path));
648 nce = new0(ExecCommand, 1);
656 nce->ignore = ignore;
658 path_kill_slashes(nce->path);
660 exec_command_append_list(e, nce);
676 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
677 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
679 int config_parse_socket_bindtodevice(const char* unit,
680 const char *filename,
683 unsigned section_line,
698 if (rvalue[0] && !streq(rvalue, "*")) {
705 free(s->bind_to_device);
706 s->bind_to_device = n;
711 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
712 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
714 int config_parse_exec_io_class(const char *unit,
715 const char *filename,
718 unsigned section_line,
725 ExecContext *c = data;
733 x = ioprio_class_from_string(rvalue);
735 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
736 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
740 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
741 c->ioprio_set = true;
746 int config_parse_exec_io_priority(const char *unit,
747 const char *filename,
750 unsigned section_line,
757 ExecContext *c = data;
765 r = safe_atoi(rvalue, &i);
766 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
767 log_syntax(unit, LOG_ERR, filename, line, -r,
768 "Failed to parse IO priority, ignoring: %s", rvalue);
772 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
773 c->ioprio_set = true;
778 int config_parse_exec_cpu_sched_policy(const char *unit,
779 const char *filename,
782 unsigned section_line,
790 ExecContext *c = data;
798 x = sched_policy_from_string(rvalue);
800 log_syntax(unit, LOG_ERR, filename, line, -x,
801 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
805 c->cpu_sched_policy = x;
806 /* Moving to or from real-time policy? We need to adjust the priority */
807 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
808 c->cpu_sched_set = true;
813 int config_parse_exec_cpu_sched_prio(const char *unit,
814 const char *filename,
817 unsigned section_line,
824 ExecContext *c = data;
832 r = safe_atoi(rvalue, &i);
834 log_syntax(unit, LOG_ERR, filename, line, -r,
835 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
839 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
840 min = sched_get_priority_min(c->cpu_sched_policy);
841 max = sched_get_priority_max(c->cpu_sched_policy);
843 if (i < min || i > max) {
844 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
845 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
849 c->cpu_sched_priority = i;
850 c->cpu_sched_set = true;
855 int config_parse_exec_cpu_affinity(const char *unit,
856 const char *filename,
859 unsigned section_line,
866 ExecContext *c = data;
867 const char *word, *state;
875 if (isempty(rvalue)) {
876 /* An empty assignment resets the CPU list */
883 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
884 _cleanup_free_ char *t = NULL;
888 t = strndup(word, l);
892 r = safe_atou(t, &cpu);
895 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
900 if (r < 0 || cpu >= c->cpuset_ncpus) {
901 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
902 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
906 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
909 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
910 "Trailing garbage, ignoring.");
915 int config_parse_exec_capabilities(const char *unit,
916 const char *filename,
919 unsigned section_line,
926 ExecContext *c = data;
934 cap = cap_from_text(rvalue);
936 log_syntax(unit, LOG_ERR, filename, line, errno,
937 "Failed to parse capabilities, ignoring: %s", rvalue);
942 cap_free(c->capabilities);
943 c->capabilities = cap;
948 int config_parse_exec_secure_bits(const char *unit,
949 const char *filename,
952 unsigned section_line,
959 ExecContext *c = data;
961 const char *word, *state;
968 if (isempty(rvalue)) {
969 /* An empty assignment resets the field */
974 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
975 if (first_word(word, "keep-caps"))
976 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
977 else if (first_word(word, "keep-caps-locked"))
978 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
979 else if (first_word(word, "no-setuid-fixup"))
980 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
981 else if (first_word(word, "no-setuid-fixup-locked"))
982 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
983 else if (first_word(word, "noroot"))
984 c->secure_bits |= 1<<SECURE_NOROOT;
985 else if (first_word(word, "noroot-locked"))
986 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
988 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
989 "Failed to parse secure bits, ignoring: %s", rvalue);
994 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
995 "Invalid syntax, garbage at the end, ignoring.");
1000 int config_parse_bounding_set(const char *unit,
1001 const char *filename,
1003 const char *section,
1004 unsigned section_line,
1011 uint64_t *capability_bounding_set_drop = data;
1012 const char *word, *state;
1014 bool invert = false;
1022 if (rvalue[0] == '~') {
1027 /* Note that we store this inverted internally, since the
1028 * kernel wants it like this. But we actually expose it
1029 * non-inverted everywhere to have a fully normalized
1032 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1033 _cleanup_free_ char *t = NULL;
1037 t = strndup(word, l);
1041 r = cap_from_name(t, &cap);
1043 log_syntax(unit, LOG_ERR, filename, line, errno,
1044 "Failed to parse capability in bounding set, ignoring: %s", t);
1048 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1050 if (!isempty(state))
1051 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1052 "Trailing garbage, ignoring.");
1055 *capability_bounding_set_drop |= sum;
1057 *capability_bounding_set_drop |= ~sum;
1062 int config_parse_limit(const char *unit,
1063 const char *filename,
1065 const char *section,
1066 unsigned section_line,
1073 struct rlimit **rl = data;
1074 unsigned long long u;
1083 if (streq(rvalue, "infinity"))
1084 u = (unsigned long long) RLIM_INFINITY;
1088 r = safe_atollu(rvalue, &u);
1090 log_syntax(unit, LOG_ERR, filename, line, -r,
1091 "Failed to parse resource value, ignoring: %s", rvalue);
1097 *rl = new(struct rlimit, 1);
1102 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1106 #ifdef HAVE_SYSV_COMPAT
1107 int config_parse_sysv_priority(const char *unit,
1108 const char *filename,
1110 const char *section,
1111 unsigned section_line,
1118 int *priority = data;
1126 r = safe_atoi(rvalue, &i);
1127 if (r < 0 || i < 0) {
1128 log_syntax(unit, LOG_ERR, filename, line, -r,
1129 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1133 *priority = (int) i;
1138 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1140 int config_parse_kill_signal(const char *unit,
1141 const char *filename,
1143 const char *section,
1144 unsigned section_line,
1159 r = signal_from_string_try_harder(rvalue);
1161 log_syntax(unit, LOG_ERR, filename, line, -r,
1162 "Failed to parse kill signal, ignoring: %s", rvalue);
1170 int config_parse_exec_mount_flags(const char *unit,
1171 const char *filename,
1173 const char *section,
1174 unsigned section_line,
1181 ExecContext *c = data;
1182 const char *word, *state;
1184 unsigned long flags = 0;
1191 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1192 _cleanup_free_ char *t;
1194 t = strndup(word, l);
1198 if (streq(t, "shared"))
1200 else if (streq(t, "slave"))
1202 else if (streq(word, "private"))
1205 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1206 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1210 if (!isempty(state))
1211 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1212 "Trailing garbage, ignoring.");
1214 c->mount_flags = flags;
1218 int config_parse_exec_selinux_context(
1220 const char *filename,
1222 const char *section,
1223 unsigned section_line,
1230 ExecContext *c = data;
1241 if (isempty(rvalue)) {
1242 free(c->selinux_context);
1243 c->selinux_context = NULL;
1244 c->selinux_context_ignore = false;
1248 if (rvalue[0] == '-') {
1254 r = unit_name_printf(u, rvalue, &k);
1256 log_syntax(unit, LOG_ERR, filename, line, -r,
1257 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1261 free(c->selinux_context);
1262 c->selinux_context = k;
1263 c->selinux_context_ignore = ignore;
1268 int config_parse_exec_apparmor_profile(
1270 const char *filename,
1272 const char *section,
1273 unsigned section_line,
1280 ExecContext *c = data;
1291 if (isempty(rvalue)) {
1292 free(c->apparmor_profile);
1293 c->apparmor_profile = NULL;
1294 c->apparmor_profile_ignore = false;
1298 if (rvalue[0] == '-') {
1304 r = unit_name_printf(u, rvalue, &k);
1306 log_syntax(unit, LOG_ERR, filename, line, -r,
1307 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1311 free(c->apparmor_profile);
1312 c->apparmor_profile = k;
1313 c->apparmor_profile_ignore = ignore;
1318 int config_parse_timer(const char *unit,
1319 const char *filename,
1321 const char *section,
1322 unsigned section_line,
1333 CalendarSpec *c = NULL;
1340 if (isempty(rvalue)) {
1341 /* Empty assignment resets list */
1342 timer_free_values(t);
1346 b = timer_base_from_string(lvalue);
1348 log_syntax(unit, LOG_ERR, filename, line, -b,
1349 "Failed to parse timer base, ignoring: %s", lvalue);
1353 if (b == TIMER_CALENDAR) {
1354 if (calendar_spec_from_string(rvalue, &c) < 0) {
1355 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1356 "Failed to parse calendar specification, ignoring: %s",
1361 if (parse_sec(rvalue, &u) < 0) {
1362 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1363 "Failed to parse timer value, ignoring: %s",
1369 v = new0(TimerValue, 1);
1375 v->calendar_spec = c;
1377 LIST_PREPEND(value, t->values, v);
1382 int config_parse_trigger_unit(
1384 const char *filename,
1386 const char *section,
1387 unsigned section_line,
1394 _cleanup_free_ char *p = NULL;
1404 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1405 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1406 "Multiple units to trigger specified, ignoring: %s", rvalue);
1410 r = unit_name_printf(u, rvalue, &p);
1412 log_syntax(unit, LOG_ERR, filename, line, -r,
1413 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1415 type = unit_name_to_type(p ?: rvalue);
1417 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1418 "Unit type not valid, ignoring: %s", rvalue);
1422 if (type == u->type) {
1423 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1424 "Trigger cannot be of same type, ignoring: %s", rvalue);
1428 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1430 log_syntax(unit, LOG_ERR, filename, line, -r,
1431 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1438 int config_parse_path_spec(const char *unit,
1439 const char *filename,
1441 const char *section,
1442 unsigned section_line,
1452 _cleanup_free_ char *k = NULL;
1460 if (isempty(rvalue)) {
1461 /* Empty assignment clears list */
1466 b = path_type_from_string(lvalue);
1468 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1469 "Failed to parse path type, ignoring: %s", lvalue);
1473 r = unit_full_printf(UNIT(p), rvalue, &k);
1479 log_syntax(unit, LOG_ERR, filename, line, -r,
1480 "Failed to resolve unit specifiers on %s. Ignoring.",
1484 if (!path_is_absolute(k)) {
1485 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1486 "Path is not absolute, ignoring: %s", k);
1490 s = new0(PathSpec, 1);
1495 s->path = path_kill_slashes(k);
1500 LIST_PREPEND(spec, p->specs, s);
1505 int config_parse_socket_service(const char *unit,
1506 const char *filename,
1508 const char *section,
1509 unsigned section_line,
1516 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1520 _cleanup_free_ char *p = NULL;
1527 r = unit_name_printf(UNIT(s), rvalue, &p);
1529 log_syntax(unit, LOG_ERR, filename, line, -r,
1530 "Failed to resolve specifiers, ignoring: %s", rvalue);
1534 if (!endswith(p, ".service")) {
1535 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1536 "Unit must be of type service, ignoring: %s", rvalue);
1540 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1542 log_syntax(unit, LOG_ERR, filename, line, -r,
1543 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1547 unit_ref_set(&s->service, x);
1552 int config_parse_service_sockets(const char *unit,
1553 const char *filename,
1555 const char *section,
1556 unsigned section_line,
1565 const char *word, *state;
1573 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1574 _cleanup_free_ char *t = NULL, *k = NULL;
1576 t = strndup(word, l);
1580 r = unit_name_printf(UNIT(s), t, &k);
1582 log_syntax(unit, LOG_ERR, filename, line, -r,
1583 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1585 if (!endswith(k ?: t, ".socket")) {
1586 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1587 "Unit must be of type socket, ignoring: %s", k ?: t);
1591 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1593 log_syntax(unit, LOG_ERR, filename, line, -r,
1594 "Failed to add dependency on %s, ignoring: %s",
1595 k ?: t, strerror(-r));
1597 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1601 if (!isempty(state))
1602 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1603 "Trailing garbage, ignoring.");
1608 int config_parse_service_timeout(const char *unit,
1609 const char *filename,
1611 const char *section,
1612 unsigned section_line,
1619 Service *s = userdata;
1627 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1628 rvalue, data, userdata);
1632 if (streq(lvalue, "TimeoutSec")) {
1633 s->start_timeout_defined = true;
1634 s->timeout_stop_usec = s->timeout_start_usec;
1635 } else if (streq(lvalue, "TimeoutStartSec"))
1636 s->start_timeout_defined = true;
1641 int config_parse_busname_service(
1643 const char *filename,
1645 const char *section,
1646 unsigned section_line,
1653 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1657 _cleanup_free_ char *p = NULL;
1664 r = unit_name_printf(UNIT(n), rvalue, &p);
1666 log_syntax(unit, LOG_ERR, filename, line, -r,
1667 "Failed to resolve specifiers, ignoring: %s", rvalue);
1671 if (!endswith(p, ".service")) {
1672 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1673 "Unit must be of type service, ignoring: %s", rvalue);
1677 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1679 log_syntax(unit, LOG_ERR, filename, line, -r,
1680 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1684 unit_ref_set(&n->service, x);
1689 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, busname_policy_access, BusNamePolicyAccess, "Failed to parse bus name policy access");
1691 int config_parse_bus_policy(
1693 const char *filename,
1695 const char *section,
1696 unsigned section_line,
1703 _cleanup_free_ BusNamePolicy *p = NULL;
1704 _cleanup_free_ char *id_str = NULL;
1705 BusName *busname = data;
1713 p = new0(BusNamePolicy, 1);
1717 if (streq(lvalue, "AllowUser"))
1718 p->type = BUSNAME_POLICY_TYPE_USER;
1719 else if (streq(lvalue, "AllowGroup"))
1720 p->type = BUSNAME_POLICY_TYPE_GROUP;
1722 assert_not_reached("Unknown lvalue");
1724 id_str = strdup(rvalue);
1728 access_str = strpbrk(id_str, WHITESPACE);
1730 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1731 "Invalid busname policy value '%s'", rvalue);
1737 access_str += strspn(access_str, WHITESPACE);
1739 p->access = busname_policy_access_from_string(access_str);
1740 if (p->access < 0) {
1741 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1742 "Invalid busname policy access type '%s'", access_str);
1749 LIST_PREPEND(policy, busname->policy, p);
1755 int config_parse_unit_env_file(const char *unit,
1756 const char *filename,
1758 const char *section,
1759 unsigned section_line,
1768 _cleanup_free_ char *n = NULL;
1777 if (isempty(rvalue)) {
1778 /* Empty assignment frees the list */
1784 r = unit_full_printf(u, rvalue, &n);
1786 log_syntax(unit, LOG_ERR, filename, line, -r,
1787 "Failed to resolve specifiers, ignoring: %s", rvalue);
1790 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1791 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1792 "Path '%s' is not absolute, ignoring.", s);
1796 r = strv_extend(env, s);
1803 int config_parse_environ(const char *unit,
1804 const char *filename,
1806 const char *section,
1807 unsigned section_line,
1816 const char *word, *state;
1818 _cleanup_free_ char *k = NULL;
1826 if (isempty(rvalue)) {
1827 /* Empty assignment resets the list */
1834 r = unit_full_printf(u, rvalue, &k);
1836 log_syntax(unit, LOG_ERR, filename, line, -r,
1837 "Failed to resolve specifiers, ignoring: %s", rvalue);
1845 FOREACH_WORD_QUOTED(word, l, k, state) {
1846 _cleanup_free_ char *n;
1849 n = cunescape_length(word, l);
1853 if (!env_assignment_is_valid(n)) {
1854 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1855 "Invalid environment assignment, ignoring: %s", rvalue);
1859 x = strv_env_set(*env, n);
1866 if (!isempty(state))
1867 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1868 "Trailing garbage, ignoring.");
1873 int config_parse_ip_tos(const char *unit,
1874 const char *filename,
1876 const char *section,
1877 unsigned section_line,
1884 int *ip_tos = data, x;
1891 x = ip_tos_from_string(rvalue);
1893 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1894 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1902 int config_parse_unit_condition_path(const char *unit,
1903 const char *filename,
1905 const char *section,
1906 unsigned section_line,
1913 ConditionType cond = ltype;
1915 bool trigger, negate;
1917 _cleanup_free_ char *p = NULL;
1925 if (isempty(rvalue)) {
1926 /* Empty assignment resets the list */
1927 condition_free_list(u->conditions);
1928 u->conditions = NULL;
1932 trigger = rvalue[0] == '|';
1936 negate = rvalue[0] == '!';
1940 r = unit_full_printf(u, rvalue, &p);
1942 log_syntax(unit, LOG_ERR, filename, line, -r,
1943 "Failed to resolve specifiers, ignoring: %s", rvalue);
1950 if (!path_is_absolute(p)) {
1951 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1952 "Path in condition not absolute, ignoring: %s", p);
1956 c = condition_new(cond, p, trigger, negate);
1960 LIST_PREPEND(conditions, u->conditions, c);
1964 int config_parse_unit_condition_string(const char *unit,
1965 const char *filename,
1967 const char *section,
1968 unsigned section_line,
1975 ConditionType cond = ltype;
1977 bool trigger, negate;
1979 _cleanup_free_ char *s = NULL;
1987 if (isempty(rvalue)) {
1988 /* Empty assignment resets the list */
1989 condition_free_list(u->conditions);
1990 u->conditions = NULL;
1994 trigger = rvalue[0] == '|';
1998 negate = rvalue[0] == '!';
2002 r = unit_full_printf(u, rvalue, &s);
2004 log_syntax(unit, LOG_ERR, filename, line, -r,
2005 "Failed to resolve specifiers, ignoring: %s", rvalue);
2012 c = condition_new(cond, s, trigger, negate);
2016 LIST_PREPEND(conditions, u->conditions, c);
2020 int config_parse_unit_condition_null(const char *unit,
2021 const char *filename,
2023 const char *section,
2024 unsigned section_line,
2033 bool trigger, negate;
2041 if (isempty(rvalue)) {
2042 /* Empty assignment resets the list */
2043 condition_free_list(u->conditions);
2044 u->conditions = NULL;
2048 trigger = rvalue[0] == '|';
2052 negate = rvalue[0] == '!';
2056 b = parse_boolean(rvalue);
2058 log_syntax(unit, LOG_ERR, filename, line, -b,
2059 "Failed to parse boolean value in condition, ignoring: %s",
2067 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2071 LIST_PREPEND(conditions, u->conditions, c);
2075 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2076 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2078 int config_parse_unit_requires_mounts_for(
2080 const char *filename,
2082 const char *section,
2083 unsigned section_line,
2091 const char *word, *state;
2099 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2101 _cleanup_free_ char *n;
2103 n = strndup(word, l);
2107 if (!utf8_is_valid(n)) {
2108 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2112 r = unit_require_mounts_for(u, n);
2114 log_syntax(unit, LOG_ERR, filename, line, -r,
2115 "Failed to add required mount for, ignoring: %s", rvalue);
2119 if (!isempty(state))
2120 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2121 "Trailing garbage, ignoring.");
2126 int config_parse_documentation(const char *unit,
2127 const char *filename,
2129 const char *section,
2130 unsigned section_line,
2146 if (isempty(rvalue)) {
2147 /* Empty assignment resets the list */
2148 strv_free(u->documentation);
2149 u->documentation = NULL;
2153 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2154 rvalue, data, userdata);
2158 for (a = b = u->documentation; a && *a; a++) {
2160 if (is_valid_documentation_url(*a))
2163 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2164 "Invalid URL, ignoring: %s", *a);
2175 int config_parse_syscall_filter(
2177 const char *filename,
2179 const char *section,
2180 unsigned section_line,
2187 static const char default_syscalls[] =
2194 ExecContext *c = data;
2196 bool invert = false;
2197 const char *word, *state;
2206 if (isempty(rvalue)) {
2207 /* Empty assignment resets the list */
2208 set_free(c->syscall_filter);
2209 c->syscall_filter = NULL;
2210 c->syscall_whitelist = false;
2214 if (rvalue[0] == '~') {
2219 if (!c->syscall_filter) {
2220 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2221 if (!c->syscall_filter)
2225 /* Allow everything but the ones listed */
2226 c->syscall_whitelist = false;
2230 /* Allow nothing but the ones listed */
2231 c->syscall_whitelist = true;
2233 /* Accept default syscalls if we are on a whitelist */
2234 NULSTR_FOREACH(i, default_syscalls) {
2237 id = seccomp_syscall_resolve_name(i);
2241 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2250 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2251 _cleanup_free_ char *t = NULL;
2254 t = strndup(word, l);
2258 id = seccomp_syscall_resolve_name(t);
2260 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2261 "Failed to parse system call, ignoring: %s", t);
2265 /* If we previously wanted to forbid a syscall and now
2266 * we want to allow it, then remove it from the list
2268 if (!invert == c->syscall_whitelist) {
2269 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2275 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2277 if (!isempty(state))
2278 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2279 "Trailing garbage, ignoring.");
2281 /* Turn on NNP, but only if it wasn't configured explicitly
2282 * before, and only if we are in user mode. */
2283 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2284 c->no_new_privileges = true;
2289 int config_parse_syscall_archs(
2291 const char *filename,
2293 const char *section,
2294 unsigned section_line,
2302 const char *word, *state;
2306 if (isempty(rvalue)) {
2312 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2316 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2317 _cleanup_free_ char *t = NULL;
2320 t = strndup(word, l);
2324 r = seccomp_arch_from_string(t, &a);
2326 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2327 "Failed to parse system call architecture, ignoring: %s", t);
2331 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2337 if (!isempty(state))
2338 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2339 "Trailing garbage, ignoring.");
2344 int config_parse_syscall_errno(
2346 const char *filename,
2348 const char *section,
2349 unsigned section_line,
2356 ExecContext *c = data;
2363 if (isempty(rvalue)) {
2364 /* Empty assignment resets to KILL */
2365 c->syscall_errno = 0;
2369 e = errno_from_name(rvalue);
2371 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2372 "Failed to parse error number, ignoring: %s", rvalue);
2376 c->syscall_errno = e;
2380 int config_parse_address_families(
2382 const char *filename,
2384 const char *section,
2385 unsigned section_line,
2392 ExecContext *c = data;
2394 bool invert = false;
2395 const char *word, *state;
2404 if (isempty(rvalue)) {
2405 /* Empty assignment resets the list */
2406 set_free(c->address_families);
2407 c->address_families = NULL;
2408 c->address_families_whitelist = false;
2412 if (rvalue[0] == '~') {
2417 if (!c->address_families) {
2418 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2419 if (!c->address_families)
2422 c->address_families_whitelist = !invert;
2425 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2426 _cleanup_free_ char *t = NULL;
2429 t = strndup(word, l);
2433 af = af_from_name(t);
2435 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2436 "Failed to parse address family, ignoring: %s", t);
2440 /* If we previously wanted to forbid an address family and now
2441 * we want to allow it, then remove it from the list
2443 if (!invert == c->address_families_whitelist) {
2444 r = set_put(c->address_families, INT_TO_PTR(af));
2450 set_remove(c->address_families, INT_TO_PTR(af));
2452 if (!isempty(state))
2453 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2454 "Trailing garbage, ignoring.");
2460 int config_parse_unit_slice(
2462 const char *filename,
2464 const char *section,
2465 unsigned section_line,
2472 _cleanup_free_ char *k = NULL;
2473 Unit *u = userdata, *slice;
2481 r = unit_name_printf(u, rvalue, &k);
2483 log_syntax(unit, LOG_ERR, filename, line, -r,
2484 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2491 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2493 log_syntax(unit, LOG_ERR, filename, line, -r,
2494 "Failed to load slice unit %s. Ignoring.", k);
2498 if (slice->type != UNIT_SLICE) {
2499 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2500 "Slice unit %s is not a slice. Ignoring.", k);
2504 unit_ref_set(&u->slice, slice);
2508 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2510 int config_parse_cpu_shares(
2512 const char *filename,
2514 const char *section,
2515 unsigned section_line,
2522 unsigned long *shares = data, lu;
2529 if (isempty(rvalue)) {
2530 *shares = (unsigned long) -1;
2534 r = safe_atolu(rvalue, &lu);
2535 if (r < 0 || lu <= 0) {
2536 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2537 "CPU shares '%s' invalid. Ignoring.", rvalue);
2545 int config_parse_cpu_quota(
2547 const char *filename,
2549 const char *section,
2550 unsigned section_line,
2557 CGroupContext *c = data;
2564 if (isempty(rvalue)) {
2565 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2569 if (!endswith(rvalue, "%")) {
2571 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2572 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2576 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2577 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2578 "CPU quota '%s' invalid. Ignoring.", rvalue);
2582 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2587 int config_parse_memory_limit(
2589 const char *filename,
2591 const char *section,
2592 unsigned section_line,
2599 CGroupContext *c = data;
2603 if (isempty(rvalue)) {
2604 c->memory_limit = (uint64_t) -1;
2608 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2610 r = parse_size(rvalue, 1024, &bytes);
2612 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2613 "Memory limit '%s' invalid. Ignoring.", rvalue);
2617 c->memory_limit = (uint64_t) bytes;
2621 int config_parse_device_allow(
2623 const char *filename,
2625 const char *section,
2626 unsigned section_line,
2633 _cleanup_free_ char *path = NULL;
2634 CGroupContext *c = data;
2635 CGroupDeviceAllow *a;
2639 if (isempty(rvalue)) {
2640 while (c->device_allow)
2641 cgroup_context_free_device_allow(c, c->device_allow);
2646 n = strcspn(rvalue, WHITESPACE);
2647 path = strndup(rvalue, n);
2651 if (!startswith(path, "/dev/") &&
2652 !startswith(path, "block-") &&
2653 !startswith(path, "char-")) {
2654 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2655 "Invalid device node path '%s'. Ignoring.", path);
2659 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2663 if (!in_charset(m, "rwm")) {
2664 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2665 "Invalid device rights '%s'. Ignoring.", m);
2669 a = new0(CGroupDeviceAllow, 1);
2675 a->r = !!strchr(m, 'r');
2676 a->w = !!strchr(m, 'w');
2677 a->m = !!strchr(m, 'm');
2679 LIST_PREPEND(device_allow, c->device_allow, a);
2683 int config_parse_blockio_weight(
2685 const char *filename,
2687 const char *section,
2688 unsigned section_line,
2695 unsigned long *weight = data, lu;
2702 if (isempty(rvalue)) {
2703 *weight = (unsigned long) -1;
2707 r = safe_atolu(rvalue, &lu);
2708 if (r < 0 || lu < 10 || lu > 1000) {
2709 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2710 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2718 int config_parse_blockio_device_weight(
2720 const char *filename,
2722 const char *section,
2723 unsigned section_line,
2730 _cleanup_free_ char *path = NULL;
2731 CGroupBlockIODeviceWeight *w;
2732 CGroupContext *c = data;
2742 if (isempty(rvalue)) {
2743 while (c->blockio_device_weights)
2744 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2749 n = strcspn(rvalue, WHITESPACE);
2750 weight = rvalue + n;
2752 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2753 "Expected block device and device weight. Ignoring.");
2757 path = strndup(rvalue, n);
2761 if (!path_startswith(path, "/dev")) {
2762 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2763 "Invalid device node path '%s'. Ignoring.", path);
2767 weight += strspn(weight, WHITESPACE);
2768 r = safe_atolu(weight, &lu);
2769 if (r < 0 || lu < 10 || lu > 1000) {
2770 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2771 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2775 w = new0(CGroupBlockIODeviceWeight, 1);
2784 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2788 int config_parse_blockio_bandwidth(
2790 const char *filename,
2792 const char *section,
2793 unsigned section_line,
2800 _cleanup_free_ char *path = NULL;
2801 CGroupBlockIODeviceBandwidth *b;
2802 CGroupContext *c = data;
2803 const char *bandwidth;
2813 read = streq("BlockIOReadBandwidth", lvalue);
2815 if (isempty(rvalue)) {
2816 CGroupBlockIODeviceBandwidth *next;
2818 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2819 if (b->read == read)
2820 cgroup_context_free_blockio_device_bandwidth(c, b);
2825 n = strcspn(rvalue, WHITESPACE);
2826 bandwidth = rvalue + n;
2827 bandwidth += strspn(bandwidth, WHITESPACE);
2830 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2831 "Expected space separated pair of device node and bandwidth. Ignoring.");
2835 path = strndup(rvalue, n);
2839 if (!path_startswith(path, "/dev")) {
2840 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2841 "Invalid device node path '%s'. Ignoring.", path);
2845 r = parse_size(bandwidth, 1000, &bytes);
2846 if (r < 0 || bytes <= 0) {
2847 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2848 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2852 b = new0(CGroupBlockIODeviceBandwidth, 1);
2858 b->bandwidth = (uint64_t) bytes;
2861 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2866 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2868 int config_parse_job_mode_isolate(
2870 const char *filename,
2872 const char *section,
2873 unsigned section_line,
2887 r = parse_boolean(rvalue);
2889 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2890 "Failed to parse boolean, ignoring: %s", rvalue);
2894 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2898 int config_parse_personality(
2900 const char *filename,
2902 const char *section,
2903 unsigned section_line,
2910 unsigned long *personality = data, p;
2915 assert(personality);
2917 p = personality_from_string(rvalue);
2918 if (p == 0xffffffffUL) {
2919 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2920 "Failed to parse personality, ignoring: %s", rvalue);
2928 int config_parse_runtime_directory(
2930 const char *filename,
2932 const char *section,
2933 unsigned section_line,
2941 const char *word, *state;
2950 if (isempty(rvalue)) {
2951 /* Empty assignment resets the list */
2957 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2958 _cleanup_free_ char *n;
2960 n = strndup(word, l);
2964 if (!filename_is_safe(n)) {
2965 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2966 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2970 r = strv_push(rt, n);
2976 if (!isempty(state))
2977 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2978 "Trailing garbage, ignoring.");
2983 int config_parse_set_status(
2985 const char *filename,
2987 const char *section,
2988 unsigned section_line,
2996 const char *word, *state;
2998 ExitStatusSet *status_set = data;
3005 /* Empty assignment resets the list */
3006 if (isempty(rvalue)) {
3007 exit_status_set_free(status_set);
3011 FOREACH_WORD(word, l, rvalue, state) {
3012 _cleanup_free_ char *temp;
3015 temp = strndup(word, l);
3019 r = safe_atoi(temp, &val);
3021 val = signal_from_string_try_harder(temp);
3024 log_syntax(unit, LOG_ERR, filename, line, -val,
3025 "Failed to parse value, ignoring: %s", word);
3029 if (val < 0 || val > 255) {
3030 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3031 "Value %d is outside range 0-255, ignoring", val);
3036 r = set_ensure_allocated(&status_set->status, NULL, NULL);
3040 r = set_put(status_set->status, INT_TO_PTR(val));
3042 log_syntax(unit, LOG_ERR, filename, line, -r,
3043 "Unable to store: %s", word);
3047 if (!isempty(state))
3048 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3049 "Trailing garbage, ignoring.");
3054 int config_parse_namespace_path_strv(
3056 const char *filename,
3058 const char *section,
3059 unsigned section_line,
3067 const char *word, *state;
3076 if (isempty(rvalue)) {
3077 /* Empty assignment resets the list */
3083 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3084 _cleanup_free_ char *n;
3087 n = strndup(word, l);
3091 if (!utf8_is_valid(n)) {
3092 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3096 offset = n[0] == '-';
3097 if (!path_is_absolute(n + offset)) {
3098 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3099 "Not an absolute path, ignoring: %s", rvalue);
3103 path_kill_slashes(n);
3105 r = strv_push(sv, n);
3111 if (!isempty(state))
3112 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3113 "Trailing garbage, ignoring.");
3118 int config_parse_no_new_privileges(
3120 const char *filename,
3122 const char *section,
3123 unsigned section_line,
3130 ExecContext *c = data;
3138 k = parse_boolean(rvalue);
3140 log_syntax(unit, LOG_ERR, filename, line, -k,
3141 "Failed to parse boolean value, ignoring: %s", rvalue);
3145 c->no_new_privileges = !!k;
3146 c->no_new_privileges_set = true;
3151 int config_parse_protect_home(
3153 const char *filename,
3155 const char *section,
3156 unsigned section_line,
3163 ExecContext *c = data;
3171 /* Our enum shall be a superset of booleans, hence first try
3172 * to parse as as boolean, and then as enum */
3174 k = parse_boolean(rvalue);
3176 c->protect_home = PROTECT_HOME_YES;
3178 c->protect_home = PROTECT_HOME_NO;
3182 h = protect_home_from_string(rvalue);
3184 log_syntax(unit, LOG_ERR, filename, line, -h,
3185 "Failed to parse protect home value, ignoring: %s", rvalue);
3189 c->protect_home = h;
3195 int config_parse_protect_system(
3197 const char *filename,
3199 const char *section,
3200 unsigned section_line,
3207 ExecContext *c = data;
3215 /* Our enum shall be a superset of booleans, hence first try
3216 * to parse as as boolean, and then as enum */
3218 k = parse_boolean(rvalue);
3220 c->protect_system = PROTECT_SYSTEM_YES;
3222 c->protect_system = PROTECT_SYSTEM_NO;
3226 s = protect_system_from_string(rvalue);
3228 log_syntax(unit, LOG_ERR, filename, line, -s,
3229 "Failed to parse protect system value, ignoring: %s", rvalue);
3233 c->protect_system = s;
3239 #define FOLLOW_MAX 8
3241 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3252 /* This will update the filename pointer if the loaded file is
3253 * reached by a symlink. The old string will be freed. */
3256 char *target, *name;
3258 if (c++ >= FOLLOW_MAX)
3261 path_kill_slashes(*filename);
3263 /* Add the file name we are currently looking at to
3264 * the names of this unit, but only if it is a valid
3266 name = basename(*filename);
3268 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3270 id = set_get(names, name);
3276 r = set_consume(names, id);
3282 /* Try to open the file name, but don't if its a symlink */
3283 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3290 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3291 r = readlink_and_make_absolute(*filename, &target);
3299 f = fdopen(fd, "re");
3311 static int merge_by_names(Unit **u, Set *names, const char *id) {
3319 /* Let's try to add in all symlink names we found */
3320 while ((k = set_steal_first(names))) {
3322 /* First try to merge in the other name into our
3324 r = unit_merge_by_name(*u, k);
3328 /* Hmm, we couldn't merge the other unit into
3329 * ours? Then let's try it the other way
3332 other = manager_get_unit((*u)->manager, k);
3336 r = unit_merge(other, *u);
3339 return merge_by_names(u, names, NULL);
3347 unit_choose_id(*u, id);
3355 static int load_from_path(Unit *u, const char *path) {
3357 _cleanup_set_free_free_ Set *symlink_names = NULL;
3358 _cleanup_fclose_ FILE *f = NULL;
3359 _cleanup_free_ char *filename = NULL;
3367 symlink_names = set_new(string_hash_func, string_compare_func);
3371 if (path_is_absolute(path)) {
3373 filename = strdup(path);
3377 r = open_follow(&filename, &f, symlink_names, &id);
3389 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3391 /* Instead of opening the path right away, we manually
3392 * follow all symlinks and add their name to our unit
3393 * name set while doing so */
3394 filename = path_make_absolute(path, *p);
3398 if (u->manager->unit_path_cache &&
3399 !set_get(u->manager->unit_path_cache, filename))
3402 r = open_follow(&filename, &f, symlink_names, &id);
3411 /* Empty the symlink names for the next run */
3412 set_clear_free(symlink_names);
3421 /* Hmm, no suitable file found? */
3425 r = merge_by_names(&merged, symlink_names, id);
3430 u->load_state = UNIT_MERGED;
3434 if (fstat(fileno(f), &st) < 0)
3437 if (null_or_empty(&st))
3438 u->load_state = UNIT_MASKED;
3440 u->load_state = UNIT_LOADED;
3442 /* Now, parse the file contents */
3443 r = config_parse(u->id, filename, f,
3444 UNIT_VTABLE(u)->sections,
3445 config_item_perf_lookup, load_fragment_gperf_lookup,
3446 false, true, false, u);
3451 free(u->fragment_path);
3452 u->fragment_path = filename;
3455 u->fragment_mtime = timespec_load(&st.st_mtim);
3457 if (u->source_path) {
3458 if (stat(u->source_path, &st) >= 0)
3459 u->source_mtime = timespec_load(&st.st_mtim);
3461 u->source_mtime = 0;
3467 int unit_load_fragment(Unit *u) {
3473 assert(u->load_state == UNIT_STUB);
3476 /* First, try to find the unit under its id. We always look
3477 * for unit files in the default directories, to make it easy
3478 * to override things by placing things in /etc/systemd/system */
3479 r = load_from_path(u, u->id);
3483 /* Try to find an alias we can load this with */
3484 if (u->load_state == UNIT_STUB)
3485 SET_FOREACH(t, u->names, i) {
3490 r = load_from_path(u, t);
3494 if (u->load_state != UNIT_STUB)
3498 /* And now, try looking for it under the suggested (originally linked) path */
3499 if (u->load_state == UNIT_STUB && u->fragment_path) {
3501 r = load_from_path(u, u->fragment_path);
3505 if (u->load_state == UNIT_STUB) {
3506 /* Hmm, this didn't work? Then let's get rid
3507 * of the fragment path stored for us, so that
3508 * we don't point to an invalid location. */
3509 free(u->fragment_path);
3510 u->fragment_path = NULL;
3514 /* Look for a template */
3515 if (u->load_state == UNIT_STUB && u->instance) {
3516 _cleanup_free_ char *k;
3518 k = unit_name_template(u->id);
3522 r = load_from_path(u, k);
3526 if (u->load_state == UNIT_STUB)
3527 SET_FOREACH(t, u->names, i) {
3528 _cleanup_free_ char *z = NULL;
3533 z = unit_name_template(t);
3537 r = load_from_path(u, z);
3541 if (u->load_state != UNIT_STUB)
3549 void unit_dump_config_items(FILE *f) {
3550 static const struct {
3551 const ConfigParserCallback callback;
3554 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3555 { config_parse_warn_compat, "NOTSUPPORTED" },
3557 { config_parse_int, "INTEGER" },
3558 { config_parse_unsigned, "UNSIGNED" },
3559 { config_parse_iec_size, "SIZE" },
3560 { config_parse_iec_off, "SIZE" },
3561 { config_parse_si_size, "SIZE" },
3562 { config_parse_bool, "BOOLEAN" },
3563 { config_parse_string, "STRING" },
3564 { config_parse_path, "PATH" },
3565 { config_parse_unit_path_printf, "PATH" },
3566 { config_parse_strv, "STRING [...]" },
3567 { config_parse_exec_nice, "NICE" },
3568 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3569 { config_parse_exec_io_class, "IOCLASS" },
3570 { config_parse_exec_io_priority, "IOPRIORITY" },
3571 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3572 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3573 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3574 { config_parse_mode, "MODE" },
3575 { config_parse_unit_env_file, "FILE" },
3576 { config_parse_output, "OUTPUT" },
3577 { config_parse_input, "INPUT" },
3578 { config_parse_log_facility, "FACILITY" },
3579 { config_parse_log_level, "LEVEL" },
3580 { config_parse_exec_capabilities, "CAPABILITIES" },
3581 { config_parse_exec_secure_bits, "SECUREBITS" },
3582 { config_parse_bounding_set, "BOUNDINGSET" },
3583 { config_parse_limit, "LIMIT" },
3584 { config_parse_unit_deps, "UNIT [...]" },
3585 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3586 { config_parse_service_type, "SERVICETYPE" },
3587 { config_parse_service_restart, "SERVICERESTART" },
3588 #ifdef HAVE_SYSV_COMPAT
3589 { config_parse_sysv_priority, "SYSVPRIORITY" },
3591 { config_parse_kill_mode, "KILLMODE" },
3592 { config_parse_kill_signal, "SIGNAL" },
3593 { config_parse_socket_listen, "SOCKET [...]" },
3594 { config_parse_socket_bind, "SOCKETBIND" },
3595 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3596 { config_parse_sec, "SECONDS" },
3597 { config_parse_nsec, "NANOSECONDS" },
3598 { config_parse_namespace_path_strv, "PATH [...]" },
3599 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3600 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3601 { config_parse_unit_string_printf, "STRING" },
3602 { config_parse_trigger_unit, "UNIT" },
3603 { config_parse_timer, "TIMER" },
3604 { config_parse_path_spec, "PATH" },
3605 { config_parse_notify_access, "ACCESS" },
3606 { config_parse_ip_tos, "TOS" },
3607 { config_parse_unit_condition_path, "CONDITION" },
3608 { config_parse_unit_condition_string, "CONDITION" },
3609 { config_parse_unit_condition_null, "CONDITION" },
3610 { config_parse_unit_slice, "SLICE" },
3611 { config_parse_documentation, "URL" },
3612 { config_parse_service_timeout, "SECONDS" },
3613 { config_parse_failure_action, "ACTION" },
3614 { config_parse_set_status, "STATUS" },
3615 { config_parse_service_sockets, "SOCKETS" },
3616 { config_parse_environ, "ENVIRON" },
3618 { config_parse_syscall_filter, "SYSCALLS" },
3619 { config_parse_syscall_archs, "ARCHS" },
3620 { config_parse_syscall_errno, "ERRNO" },
3621 { config_parse_address_families, "FAMILIES" },
3623 { config_parse_cpu_shares, "SHARES" },
3624 { config_parse_memory_limit, "LIMIT" },
3625 { config_parse_device_allow, "DEVICE" },
3626 { config_parse_device_policy, "POLICY" },
3627 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3628 { config_parse_blockio_weight, "WEIGHT" },
3629 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3630 { config_parse_long, "LONG" },
3631 { config_parse_socket_service, "SERVICE" },
3633 { config_parse_exec_selinux_context, "LABEL" },
3635 { config_parse_job_mode, "MODE" },
3636 { config_parse_job_mode_isolate, "BOOLEAN" },
3637 { config_parse_personality, "PERSONALITY" },
3640 const char *prev = NULL;
3645 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3646 const char *rvalue = "OTHER", *lvalue;
3650 const ConfigPerfItem *p;
3652 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3654 dot = strchr(i, '.');
3655 lvalue = dot ? dot + 1 : i;
3659 if (!prev || !strneq(prev, i, prefix_len+1)) {
3663 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3666 for (j = 0; j < ELEMENTSOF(table); j++)
3667 if (p->parse == table[j].callback) {
3668 rvalue = table[j].rvalue;
3672 fprintf(f, "%s=%s\n", lvalue, rvalue);