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"
65 #include "seccomp-util.h"
68 int config_parse_warn_compat(
73 unsigned section_line,
79 Disabled reason = ltype;
82 case DISABLED_CONFIGURATION:
83 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
84 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
87 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
88 "Support for option %s= has been removed and it is ignored", lvalue);
90 case DISABLED_EXPERIMENTAL:
91 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
92 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
99 int config_parse_unit_deps(const char *unit,
100 const char *filename,
103 unsigned section_line,
110 UnitDependency d = ltype;
112 const char *word, *state;
119 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
120 _cleanup_free_ char *t = NULL, *k = NULL;
123 t = strndup(word, l);
127 r = unit_name_printf(u, t, &k);
129 log_syntax(unit, LOG_ERR, filename, line, -r,
130 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
134 r = unit_add_dependency_by_name(u, d, k, NULL, true);
136 log_syntax(unit, LOG_ERR, filename, line, -r,
137 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
140 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
145 int config_parse_unit_string_printf(const char *unit,
146 const char *filename,
149 unsigned section_line,
157 _cleanup_free_ char *k = NULL;
165 r = unit_full_printf(u, rvalue, &k);
167 log_syntax(unit, LOG_ERR, filename, line, -r,
168 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
170 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
171 k ? k : rvalue, data, userdata);
174 int config_parse_unit_strv_printf(const char *unit,
175 const char *filename,
178 unsigned section_line,
186 _cleanup_free_ char *k = NULL;
194 r = unit_full_printf(u, rvalue, &k);
196 log_syntax(unit, LOG_ERR, filename, line, -r,
197 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
199 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
200 k ? k : rvalue, data, userdata);
203 int config_parse_unit_path_printf(const char *unit,
204 const char *filename,
207 unsigned section_line,
214 _cleanup_free_ char *k = NULL;
223 r = unit_full_printf(u, rvalue, &k);
225 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
229 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
232 int config_parse_unit_path_strv_printf(
234 const char *filename,
237 unsigned section_line,
245 const char *word, *state;
255 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
256 _cleanup_free_ char *k = NULL;
262 r = unit_full_printf(u, t, &k);
264 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
268 if (!utf8_is_valid(k)) {
269 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
273 if (!path_is_absolute(k)) {
274 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
278 path_kill_slashes(k);
287 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
292 int config_parse_socket_listen(const char *unit,
293 const char *filename,
296 unsigned section_line,
303 _cleanup_free_ SocketPort *p = NULL;
315 if (isempty(rvalue)) {
316 /* An empty assignment removes all ports */
317 socket_free_ports(s);
321 p = new0(SocketPort, 1);
325 if (ltype != SOCKET_SOCKET) {
328 r = unit_full_printf(UNIT(s), rvalue, &p->path);
330 p->path = strdup(rvalue);
334 log_syntax(unit, LOG_ERR, filename, line, -r,
335 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
338 path_kill_slashes(p->path);
340 } else if (streq(lvalue, "ListenNetlink")) {
341 _cleanup_free_ char *k = NULL;
343 p->type = SOCKET_SOCKET;
344 r = unit_full_printf(UNIT(s), rvalue, &k);
346 log_syntax(unit, LOG_ERR, filename, line, -r,
347 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
349 r = socket_address_parse_netlink(&p->address, k ?: rvalue);
351 log_syntax(unit, LOG_ERR, filename, line, -r,
352 "Failed to parse address value, ignoring: %s", rvalue);
357 _cleanup_free_ char *k = NULL;
359 p->type = SOCKET_SOCKET;
360 r = unit_full_printf(UNIT(s), rvalue, &k);
362 log_syntax(unit, LOG_ERR, filename, line, -r,
363 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
365 r = socket_address_parse(&p->address, k ? k : rvalue);
367 log_syntax(unit, LOG_ERR, filename, line, -r,
368 "Failed to parse address value, ignoring: %s", rvalue);
372 if (streq(lvalue, "ListenStream"))
373 p->address.type = SOCK_STREAM;
374 else if (streq(lvalue, "ListenDatagram"))
375 p->address.type = SOCK_DGRAM;
377 assert(streq(lvalue, "ListenSequentialPacket"));
378 p->address.type = SOCK_SEQPACKET;
381 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
382 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
383 "Address family not supported, ignoring: %s", rvalue);
392 LIST_FIND_TAIL(port, s->ports, tail);
393 LIST_INSERT_AFTER(port, s->ports, tail, p);
395 LIST_PREPEND(port, s->ports, p);
401 int config_parse_socket_bind(const char *unit,
402 const char *filename,
405 unsigned section_line,
413 SocketAddressBindIPv6Only b;
422 b = socket_address_bind_ipv6_only_from_string(rvalue);
426 r = parse_boolean(rvalue);
428 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
429 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
433 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
435 s->bind_ipv6_only = b;
440 int config_parse_exec_nice(const char *unit,
441 const char *filename,
444 unsigned section_line,
451 ExecContext *c = data;
459 r = safe_atoi(rvalue, &priority);
461 log_syntax(unit, LOG_ERR, filename, line, -r,
462 "Failed to parse nice priority, ignoring: %s. ", rvalue);
466 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
467 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
468 "Nice priority out of range, ignoring: %s", rvalue);
478 int config_parse_exec_oom_score_adjust(const char* unit,
479 const char *filename,
482 unsigned section_line,
489 ExecContext *c = data;
497 r = safe_atoi(rvalue, &oa);
499 log_syntax(unit, LOG_ERR, filename, line, -r,
500 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
504 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
505 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
506 "OOM score adjust value out of range, ignoring: %s", rvalue);
510 c->oom_score_adjust = oa;
511 c->oom_score_adjust_set = true;
516 int config_parse_exec(const char *unit,
517 const char *filename,
520 unsigned section_line,
527 ExecCommand **e = data, *nce;
539 if (isempty(rvalue)) {
540 /* An empty assignment resets the list */
541 *e = exec_command_free_list(*e);
545 /* We accept an absolute path as first argument, or
546 * alternatively an absolute prefixed with @ to allow
547 * overriding of argv[0]. */
550 const char *word, *state;
552 bool honour_argv0 = false, ignore = false;
558 rvalue += strspn(rvalue, WHITESPACE);
563 for (i = 0; i < 2; i++) {
564 if (rvalue[0] == '-' && !ignore) {
569 if (rvalue[0] == '@' && !honour_argv0) {
575 if (*rvalue != '/') {
576 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
577 "Executable path is not absolute, ignoring: %s", rvalue);
582 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
583 if (strneq(word, ";", MAX(l, 1U)))
588 if (!isempty(state)) {
589 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
590 "Trailing garbage, ignoring.");
595 n = new(char*, k + !honour_argv0);
600 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
601 if (strneq(word, ";", MAX(l, 1U)))
603 else if (strneq(word, "\\;", MAX(l, 1U))) {
608 if (honour_argv0 && word == rvalue) {
611 path = strndup(word, l);
617 if (!utf8_is_valid(path)) {
618 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
626 c = n[k++] = cunescape_length(word, l);
632 if (!utf8_is_valid(c)) {
633 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
643 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
644 "Invalid command line, ignoring: %s", rvalue);
657 assert(path_is_absolute(path));
659 nce = new0(ExecCommand, 1);
667 nce->ignore = ignore;
669 path_kill_slashes(nce->path);
671 exec_command_append_list(e, nce);
687 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
688 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
690 int config_parse_socket_bindtodevice(const char* unit,
691 const char *filename,
694 unsigned section_line,
709 if (rvalue[0] && !streq(rvalue, "*")) {
716 free(s->bind_to_device);
717 s->bind_to_device = n;
722 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
723 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
725 int config_parse_exec_io_class(const char *unit,
726 const char *filename,
729 unsigned section_line,
736 ExecContext *c = data;
744 x = ioprio_class_from_string(rvalue);
746 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
747 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
751 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
752 c->ioprio_set = true;
757 int config_parse_exec_io_priority(const char *unit,
758 const char *filename,
761 unsigned section_line,
768 ExecContext *c = data;
776 r = safe_atoi(rvalue, &i);
777 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
778 log_syntax(unit, LOG_ERR, filename, line, -r,
779 "Failed to parse IO priority, ignoring: %s", rvalue);
783 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
784 c->ioprio_set = true;
789 int config_parse_exec_cpu_sched_policy(const char *unit,
790 const char *filename,
793 unsigned section_line,
801 ExecContext *c = data;
809 x = sched_policy_from_string(rvalue);
811 log_syntax(unit, LOG_ERR, filename, line, -x,
812 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
816 c->cpu_sched_policy = x;
817 /* Moving to or from real-time policy? We need to adjust the priority */
818 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
819 c->cpu_sched_set = true;
824 int config_parse_exec_cpu_sched_prio(const char *unit,
825 const char *filename,
828 unsigned section_line,
835 ExecContext *c = data;
843 r = safe_atoi(rvalue, &i);
845 log_syntax(unit, LOG_ERR, filename, line, -r,
846 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
850 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
851 min = sched_get_priority_min(c->cpu_sched_policy);
852 max = sched_get_priority_max(c->cpu_sched_policy);
854 if (i < min || i > max) {
855 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
856 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
860 c->cpu_sched_priority = i;
861 c->cpu_sched_set = true;
866 int config_parse_exec_cpu_affinity(const char *unit,
867 const char *filename,
870 unsigned section_line,
877 ExecContext *c = data;
878 const char *word, *state;
886 if (isempty(rvalue)) {
887 /* An empty assignment resets the CPU list */
894 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
895 _cleanup_free_ char *t = NULL;
899 t = strndup(word, l);
903 r = safe_atou(t, &cpu);
906 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
911 if (r < 0 || cpu >= c->cpuset_ncpus) {
912 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
913 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
917 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
920 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
921 "Trailing garbage, ignoring.");
926 int config_parse_exec_capabilities(const char *unit,
927 const char *filename,
930 unsigned section_line,
937 ExecContext *c = data;
945 cap = cap_from_text(rvalue);
947 log_syntax(unit, LOG_ERR, filename, line, errno,
948 "Failed to parse capabilities, ignoring: %s", rvalue);
953 cap_free(c->capabilities);
954 c->capabilities = cap;
959 int config_parse_exec_secure_bits(const char *unit,
960 const char *filename,
963 unsigned section_line,
970 ExecContext *c = data;
972 const char *word, *state;
979 if (isempty(rvalue)) {
980 /* An empty assignment resets the field */
985 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
986 if (first_word(word, "keep-caps"))
987 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
988 else if (first_word(word, "keep-caps-locked"))
989 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
990 else if (first_word(word, "no-setuid-fixup"))
991 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
992 else if (first_word(word, "no-setuid-fixup-locked"))
993 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
994 else if (first_word(word, "noroot"))
995 c->secure_bits |= 1<<SECURE_NOROOT;
996 else if (first_word(word, "noroot-locked"))
997 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
999 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1000 "Failed to parse secure bits, ignoring: %s", rvalue);
1004 if (!isempty(state))
1005 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1006 "Invalid syntax, garbage at the end, ignoring.");
1011 int config_parse_bounding_set(const char *unit,
1012 const char *filename,
1014 const char *section,
1015 unsigned section_line,
1022 uint64_t *capability_bounding_set_drop = data;
1023 const char *word, *state;
1025 bool invert = false;
1033 if (rvalue[0] == '~') {
1038 /* Note that we store this inverted internally, since the
1039 * kernel wants it like this. But we actually expose it
1040 * non-inverted everywhere to have a fully normalized
1043 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1044 _cleanup_free_ char *t = NULL;
1047 t = strndup(word, l);
1051 cap = capability_from_name(t);
1053 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
1057 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1059 if (!isempty(state))
1060 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1061 "Trailing garbage, ignoring.");
1064 *capability_bounding_set_drop |= sum;
1066 *capability_bounding_set_drop |= ~sum;
1071 int config_parse_limit(const char *unit,
1072 const char *filename,
1074 const char *section,
1075 unsigned section_line,
1082 struct rlimit **rl = data;
1083 unsigned long long u;
1092 if (streq(rvalue, "infinity"))
1093 u = (unsigned long long) RLIM_INFINITY;
1097 r = safe_atollu(rvalue, &u);
1099 log_syntax(unit, LOG_ERR, filename, line, -r,
1100 "Failed to parse resource value, ignoring: %s", rvalue);
1106 *rl = new(struct rlimit, 1);
1111 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1115 #ifdef HAVE_SYSV_COMPAT
1116 int config_parse_sysv_priority(const char *unit,
1117 const char *filename,
1119 const char *section,
1120 unsigned section_line,
1127 int *priority = data;
1135 r = safe_atoi(rvalue, &i);
1136 if (r < 0 || i < 0) {
1137 log_syntax(unit, LOG_ERR, filename, line, -r,
1138 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1142 *priority = (int) i;
1147 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1149 int config_parse_kill_signal(const char *unit,
1150 const char *filename,
1152 const char *section,
1153 unsigned section_line,
1168 r = signal_from_string_try_harder(rvalue);
1170 log_syntax(unit, LOG_ERR, filename, line, -r,
1171 "Failed to parse kill signal, ignoring: %s", rvalue);
1179 int config_parse_exec_mount_flags(const char *unit,
1180 const char *filename,
1182 const char *section,
1183 unsigned section_line,
1190 ExecContext *c = data;
1191 const char *word, *state;
1193 unsigned long flags = 0;
1200 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1201 _cleanup_free_ char *t;
1203 t = strndup(word, l);
1207 if (streq(t, "shared"))
1209 else if (streq(t, "slave"))
1211 else if (streq(word, "private"))
1214 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1215 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1219 if (!isempty(state))
1220 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1221 "Trailing garbage, ignoring.");
1223 c->mount_flags = flags;
1227 int config_parse_exec_selinux_context(
1229 const char *filename,
1231 const char *section,
1232 unsigned section_line,
1239 ExecContext *c = data;
1250 if (isempty(rvalue)) {
1251 free(c->selinux_context);
1252 c->selinux_context = NULL;
1253 c->selinux_context_ignore = false;
1257 if (rvalue[0] == '-') {
1263 r = unit_name_printf(u, rvalue, &k);
1265 log_syntax(unit, LOG_ERR, filename, line, -r,
1266 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1270 free(c->selinux_context);
1271 c->selinux_context = k;
1272 c->selinux_context_ignore = ignore;
1277 int config_parse_exec_apparmor_profile(
1279 const char *filename,
1281 const char *section,
1282 unsigned section_line,
1289 ExecContext *c = data;
1300 if (isempty(rvalue)) {
1301 free(c->apparmor_profile);
1302 c->apparmor_profile = NULL;
1303 c->apparmor_profile_ignore = false;
1307 if (rvalue[0] == '-') {
1313 r = unit_name_printf(u, rvalue, &k);
1315 log_syntax(unit, LOG_ERR, filename, line, -r,
1316 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1320 free(c->apparmor_profile);
1321 c->apparmor_profile = k;
1322 c->apparmor_profile_ignore = ignore;
1327 int config_parse_exec_smack_process_label(
1329 const char *filename,
1331 const char *section,
1332 unsigned section_line,
1339 ExecContext *c = data;
1350 if (isempty(rvalue)) {
1351 free(c->smack_process_label);
1352 c->smack_process_label = NULL;
1353 c->smack_process_label_ignore = false;
1357 if (rvalue[0] == '-') {
1363 r = unit_name_printf(u, rvalue, &k);
1365 log_syntax(unit, LOG_ERR, filename, line, -r,
1366 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1370 free(c->smack_process_label);
1371 c->smack_process_label = k;
1372 c->smack_process_label_ignore = ignore;
1377 int config_parse_timer(const char *unit,
1378 const char *filename,
1380 const char *section,
1381 unsigned section_line,
1392 CalendarSpec *c = NULL;
1399 if (isempty(rvalue)) {
1400 /* Empty assignment resets list */
1401 timer_free_values(t);
1405 b = timer_base_from_string(lvalue);
1407 log_syntax(unit, LOG_ERR, filename, line, -b,
1408 "Failed to parse timer base, ignoring: %s", lvalue);
1412 if (b == TIMER_CALENDAR) {
1413 if (calendar_spec_from_string(rvalue, &c) < 0) {
1414 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1415 "Failed to parse calendar specification, ignoring: %s",
1420 if (parse_sec(rvalue, &u) < 0) {
1421 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1422 "Failed to parse timer value, ignoring: %s",
1428 v = new0(TimerValue, 1);
1430 calendar_spec_free(c);
1436 v->calendar_spec = c;
1438 LIST_PREPEND(value, t->values, v);
1443 int config_parse_trigger_unit(
1445 const char *filename,
1447 const char *section,
1448 unsigned section_line,
1455 _cleanup_free_ char *p = NULL;
1465 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1466 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1467 "Multiple units to trigger specified, ignoring: %s", rvalue);
1471 r = unit_name_printf(u, rvalue, &p);
1473 log_syntax(unit, LOG_ERR, filename, line, -r,
1474 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1476 type = unit_name_to_type(p ?: rvalue);
1478 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1479 "Unit type not valid, ignoring: %s", rvalue);
1483 if (type == u->type) {
1484 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1485 "Trigger cannot be of same type, ignoring: %s", rvalue);
1489 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1491 log_syntax(unit, LOG_ERR, filename, line, -r,
1492 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1499 int config_parse_path_spec(const char *unit,
1500 const char *filename,
1502 const char *section,
1503 unsigned section_line,
1513 _cleanup_free_ char *k = NULL;
1521 if (isempty(rvalue)) {
1522 /* Empty assignment clears list */
1527 b = path_type_from_string(lvalue);
1529 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1530 "Failed to parse path type, ignoring: %s", lvalue);
1534 r = unit_full_printf(UNIT(p), rvalue, &k);
1540 log_syntax(unit, LOG_ERR, filename, line, -r,
1541 "Failed to resolve unit specifiers on %s. Ignoring.",
1545 if (!path_is_absolute(k)) {
1546 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1547 "Path is not absolute, ignoring: %s", k);
1551 s = new0(PathSpec, 1);
1556 s->path = path_kill_slashes(k);
1561 LIST_PREPEND(spec, p->specs, s);
1566 int config_parse_socket_service(const char *unit,
1567 const char *filename,
1569 const char *section,
1570 unsigned section_line,
1577 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1581 _cleanup_free_ char *p = NULL;
1588 r = unit_name_printf(UNIT(s), rvalue, &p);
1590 log_syntax(unit, LOG_ERR, filename, line, -r,
1591 "Failed to resolve specifiers, ignoring: %s", rvalue);
1595 if (!endswith(p, ".service")) {
1596 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1597 "Unit must be of type service, ignoring: %s", rvalue);
1601 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1603 log_syntax(unit, LOG_ERR, filename, line, -r,
1604 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1608 unit_ref_set(&s->service, x);
1613 int config_parse_service_sockets(const char *unit,
1614 const char *filename,
1616 const char *section,
1617 unsigned section_line,
1626 const char *word, *state;
1634 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1635 _cleanup_free_ char *t = NULL, *k = NULL;
1637 t = strndup(word, l);
1641 r = unit_name_printf(UNIT(s), t, &k);
1643 log_syntax(unit, LOG_ERR, filename, line, -r,
1644 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1646 if (!endswith(k ?: t, ".socket")) {
1647 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1648 "Unit must be of type socket, ignoring: %s", k ?: t);
1652 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1654 log_syntax(unit, LOG_ERR, filename, line, -r,
1655 "Failed to add dependency on %s, ignoring: %s",
1656 k ?: t, strerror(-r));
1658 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1662 if (!isempty(state))
1663 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1664 "Trailing garbage, ignoring.");
1669 int config_parse_service_timeout(const char *unit,
1670 const char *filename,
1672 const char *section,
1673 unsigned section_line,
1680 Service *s = userdata;
1688 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1689 rvalue, data, userdata);
1693 if (streq(lvalue, "TimeoutSec")) {
1694 s->start_timeout_defined = true;
1695 s->timeout_stop_usec = s->timeout_start_usec;
1696 } else if (streq(lvalue, "TimeoutStartSec"))
1697 s->start_timeout_defined = true;
1702 int config_parse_busname_service(
1704 const char *filename,
1706 const char *section,
1707 unsigned section_line,
1714 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1718 _cleanup_free_ char *p = NULL;
1725 r = unit_name_printf(UNIT(n), rvalue, &p);
1727 log_syntax(unit, LOG_ERR, filename, line, -r,
1728 "Failed to resolve specifiers, ignoring: %s", rvalue);
1732 if (!endswith(p, ".service")) {
1733 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1734 "Unit must be of type service, ignoring: %s", rvalue);
1738 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1740 log_syntax(unit, LOG_ERR, filename, line, -r,
1741 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1745 unit_ref_set(&n->service, x);
1750 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1752 int config_parse_bus_policy(
1754 const char *filename,
1756 const char *section,
1757 unsigned section_line,
1764 _cleanup_free_ BusNamePolicy *p = NULL;
1765 _cleanup_free_ char *id_str = NULL;
1766 BusName *busname = data;
1774 p = new0(BusNamePolicy, 1);
1778 if (streq(lvalue, "AllowUser"))
1779 p->type = BUSNAME_POLICY_TYPE_USER;
1780 else if (streq(lvalue, "AllowGroup"))
1781 p->type = BUSNAME_POLICY_TYPE_GROUP;
1783 assert_not_reached("Unknown lvalue");
1785 id_str = strdup(rvalue);
1789 access_str = strpbrk(id_str, WHITESPACE);
1791 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1792 "Invalid busname policy value '%s'", rvalue);
1798 access_str += strspn(access_str, WHITESPACE);
1800 p->access = bus_policy_access_from_string(access_str);
1801 if (p->access < 0) {
1802 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1803 "Invalid busname policy access type '%s'", access_str);
1810 LIST_PREPEND(policy, busname->policy, p);
1816 int config_parse_bus_endpoint_policy(
1818 const char *filename,
1820 const char *section,
1821 unsigned section_line,
1828 _cleanup_free_ char *name = NULL;
1829 BusPolicyAccess access;
1830 ExecContext *c = data;
1839 name = strdup(rvalue);
1843 access_str = strpbrk(name, WHITESPACE);
1845 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1846 "Invalid endpoint policy value '%s'", rvalue);
1852 access_str += strspn(access_str, WHITESPACE);
1854 access = bus_policy_access_from_string(access_str);
1855 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1856 access >= _BUS_POLICY_ACCESS_MAX) {
1857 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1858 "Invalid endpoint policy access type '%s'", access_str);
1862 if (!c->bus_endpoint) {
1863 r = bus_endpoint_new(&c->bus_endpoint);
1869 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1872 int config_parse_unit_env_file(const char *unit,
1873 const char *filename,
1875 const char *section,
1876 unsigned section_line,
1885 _cleanup_free_ char *n = NULL;
1894 if (isempty(rvalue)) {
1895 /* Empty assignment frees the list */
1901 r = unit_full_printf(u, rvalue, &n);
1903 log_syntax(unit, LOG_ERR, filename, line, -r,
1904 "Failed to resolve specifiers, ignoring: %s", rvalue);
1907 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1908 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1909 "Path '%s' is not absolute, ignoring.", s);
1913 r = strv_extend(env, s);
1920 int config_parse_environ(const char *unit,
1921 const char *filename,
1923 const char *section,
1924 unsigned section_line,
1933 const char *word, *state;
1935 _cleanup_free_ char *k = NULL;
1943 if (isempty(rvalue)) {
1944 /* Empty assignment resets the list */
1951 r = unit_full_printf(u, rvalue, &k);
1953 log_syntax(unit, LOG_ERR, filename, line, -r,
1954 "Failed to resolve specifiers, ignoring: %s", rvalue);
1962 FOREACH_WORD_QUOTED(word, l, k, state) {
1963 _cleanup_free_ char *n;
1966 n = cunescape_length(word, l);
1970 if (!env_assignment_is_valid(n)) {
1971 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1972 "Invalid environment assignment, ignoring: %s", rvalue);
1976 x = strv_env_set(*env, n);
1983 if (!isempty(state))
1984 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1985 "Trailing garbage, ignoring.");
1990 int config_parse_ip_tos(const char *unit,
1991 const char *filename,
1993 const char *section,
1994 unsigned section_line,
2001 int *ip_tos = data, x;
2008 x = ip_tos_from_string(rvalue);
2010 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2011 "Failed to parse IP TOS value, ignoring: %s", rvalue);
2019 int config_parse_unit_condition_path(
2021 const char *filename,
2023 const char *section,
2024 unsigned section_line,
2031 _cleanup_free_ char *p = NULL;
2032 Condition **list = data, *c;
2033 ConditionType t = ltype;
2034 bool trigger, negate;
2043 if (isempty(rvalue)) {
2044 /* Empty assignment resets the list */
2045 *list = condition_free_list(*list);
2049 trigger = rvalue[0] == '|';
2053 negate = rvalue[0] == '!';
2057 r = unit_full_printf(u, rvalue, &p);
2059 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2063 if (!path_is_absolute(p)) {
2064 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2068 c = condition_new(t, p, trigger, negate);
2072 LIST_PREPEND(conditions, *list, c);
2076 int config_parse_unit_condition_string(
2078 const char *filename,
2080 const char *section,
2081 unsigned section_line,
2088 _cleanup_free_ char *s = NULL;
2089 Condition **list = data, *c;
2090 ConditionType t = ltype;
2091 bool trigger, negate;
2100 if (isempty(rvalue)) {
2101 /* Empty assignment resets the list */
2102 *list = condition_free_list(*list);
2106 trigger = rvalue[0] == '|';
2110 negate = rvalue[0] == '!';
2114 r = unit_full_printf(u, rvalue, &s);
2116 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2120 c = condition_new(t, s, trigger, negate);
2124 LIST_PREPEND(conditions, *list, c);
2128 int config_parse_unit_condition_null(
2130 const char *filename,
2132 const char *section,
2133 unsigned section_line,
2140 Condition **list = data, *c;
2141 bool trigger, negate;
2149 if (isempty(rvalue)) {
2150 /* Empty assignment resets the list */
2151 *list = condition_free_list(*list);
2155 trigger = rvalue[0] == '|';
2159 negate = rvalue[0] == '!';
2163 b = parse_boolean(rvalue);
2165 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2172 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2176 LIST_PREPEND(conditions, *list, c);
2180 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2181 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2183 int config_parse_unit_requires_mounts_for(
2185 const char *filename,
2187 const char *section,
2188 unsigned section_line,
2196 const char *word, *state;
2204 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2206 _cleanup_free_ char *n;
2208 n = strndup(word, l);
2212 if (!utf8_is_valid(n)) {
2213 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2217 r = unit_require_mounts_for(u, n);
2219 log_syntax(unit, LOG_ERR, filename, line, -r,
2220 "Failed to add required mount for, ignoring: %s", rvalue);
2224 if (!isempty(state))
2225 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2226 "Trailing garbage, ignoring.");
2231 int config_parse_documentation(const char *unit,
2232 const char *filename,
2234 const char *section,
2235 unsigned section_line,
2251 if (isempty(rvalue)) {
2252 /* Empty assignment resets the list */
2253 strv_free(u->documentation);
2254 u->documentation = NULL;
2258 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2259 rvalue, data, userdata);
2263 for (a = b = u->documentation; a && *a; a++) {
2265 if (is_valid_documentation_url(*a))
2268 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2269 "Invalid URL, ignoring: %s", *a);
2280 int config_parse_syscall_filter(
2282 const char *filename,
2284 const char *section,
2285 unsigned section_line,
2292 static const char default_syscalls[] =
2299 ExecContext *c = data;
2301 bool invert = false;
2302 const char *word, *state;
2311 if (isempty(rvalue)) {
2312 /* Empty assignment resets the list */
2313 set_free(c->syscall_filter);
2314 c->syscall_filter = NULL;
2315 c->syscall_whitelist = false;
2319 if (rvalue[0] == '~') {
2324 if (!c->syscall_filter) {
2325 c->syscall_filter = set_new(NULL);
2326 if (!c->syscall_filter)
2330 /* Allow everything but the ones listed */
2331 c->syscall_whitelist = false;
2335 /* Allow nothing but the ones listed */
2336 c->syscall_whitelist = true;
2338 /* Accept default syscalls if we are on a whitelist */
2339 NULSTR_FOREACH(i, default_syscalls) {
2342 id = seccomp_syscall_resolve_name(i);
2346 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2355 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2356 _cleanup_free_ char *t = NULL;
2359 t = strndup(word, l);
2363 id = seccomp_syscall_resolve_name(t);
2365 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2366 "Failed to parse system call, ignoring: %s", t);
2370 /* If we previously wanted to forbid a syscall and now
2371 * we want to allow it, then remove it from the list
2373 if (!invert == c->syscall_whitelist) {
2374 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2380 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2382 if (!isempty(state))
2383 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2384 "Trailing garbage, ignoring.");
2386 /* Turn on NNP, but only if it wasn't configured explicitly
2387 * before, and only if we are in user mode. */
2388 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2389 c->no_new_privileges = true;
2394 int config_parse_syscall_archs(
2396 const char *filename,
2398 const char *section,
2399 unsigned section_line,
2407 const char *word, *state;
2411 if (isempty(rvalue)) {
2417 r = set_ensure_allocated(archs, NULL);
2421 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2422 _cleanup_free_ char *t = NULL;
2425 t = strndup(word, l);
2429 r = seccomp_arch_from_string(t, &a);
2431 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2432 "Failed to parse system call architecture, ignoring: %s", t);
2436 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2442 if (!isempty(state))
2443 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2444 "Trailing garbage, ignoring.");
2449 int config_parse_syscall_errno(
2451 const char *filename,
2453 const char *section,
2454 unsigned section_line,
2461 ExecContext *c = data;
2468 if (isempty(rvalue)) {
2469 /* Empty assignment resets to KILL */
2470 c->syscall_errno = 0;
2474 e = errno_from_name(rvalue);
2476 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2477 "Failed to parse error number, ignoring: %s", rvalue);
2481 c->syscall_errno = e;
2485 int config_parse_address_families(
2487 const char *filename,
2489 const char *section,
2490 unsigned section_line,
2497 ExecContext *c = data;
2498 bool invert = false;
2499 const char *word, *state;
2507 if (isempty(rvalue)) {
2508 /* Empty assignment resets the list */
2509 set_free(c->address_families);
2510 c->address_families = NULL;
2511 c->address_families_whitelist = false;
2515 if (rvalue[0] == '~') {
2520 if (!c->address_families) {
2521 c->address_families = set_new(NULL);
2522 if (!c->address_families)
2525 c->address_families_whitelist = !invert;
2528 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2529 _cleanup_free_ char *t = NULL;
2532 t = strndup(word, l);
2536 af = af_from_name(t);
2538 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2539 "Failed to parse address family, ignoring: %s", t);
2543 /* If we previously wanted to forbid an address family and now
2544 * we want to allow it, then remove it from the list
2546 if (!invert == c->address_families_whitelist) {
2547 r = set_put(c->address_families, INT_TO_PTR(af));
2553 set_remove(c->address_families, INT_TO_PTR(af));
2555 if (!isempty(state))
2556 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2557 "Trailing garbage, ignoring.");
2563 int config_parse_unit_slice(
2565 const char *filename,
2567 const char *section,
2568 unsigned section_line,
2575 _cleanup_free_ char *k = NULL;
2576 Unit *u = userdata, *slice;
2584 r = unit_name_printf(u, rvalue, &k);
2586 log_syntax(unit, LOG_ERR, filename, line, -r,
2587 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2594 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2596 log_syntax(unit, LOG_ERR, filename, line, -r,
2597 "Failed to load slice unit %s. Ignoring.", k);
2601 if (slice->type != UNIT_SLICE) {
2602 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2603 "Slice unit %s is not a slice. Ignoring.", k);
2607 unit_ref_set(&u->slice, slice);
2611 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2613 int config_parse_cpu_shares(
2615 const char *filename,
2617 const char *section,
2618 unsigned section_line,
2625 unsigned long *shares = data, lu;
2632 if (isempty(rvalue)) {
2633 *shares = (unsigned long) -1;
2637 r = safe_atolu(rvalue, &lu);
2638 if (r < 0 || lu <= 0) {
2639 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2640 "CPU shares '%s' invalid. Ignoring.", rvalue);
2648 int config_parse_cpu_quota(
2650 const char *filename,
2652 const char *section,
2653 unsigned section_line,
2660 CGroupContext *c = data;
2667 if (isempty(rvalue)) {
2668 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2672 if (!endswith(rvalue, "%")) {
2674 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2675 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2679 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2680 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2681 "CPU quota '%s' invalid. Ignoring.", rvalue);
2685 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2690 int config_parse_memory_limit(
2692 const char *filename,
2694 const char *section,
2695 unsigned section_line,
2702 CGroupContext *c = data;
2706 if (isempty(rvalue)) {
2707 c->memory_limit = (uint64_t) -1;
2711 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2713 r = parse_size(rvalue, 1024, &bytes);
2715 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2716 "Memory limit '%s' invalid. Ignoring.", rvalue);
2720 c->memory_limit = (uint64_t) bytes;
2724 int config_parse_device_allow(
2726 const char *filename,
2728 const char *section,
2729 unsigned section_line,
2736 _cleanup_free_ char *path = NULL;
2737 CGroupContext *c = data;
2738 CGroupDeviceAllow *a;
2742 if (isempty(rvalue)) {
2743 while (c->device_allow)
2744 cgroup_context_free_device_allow(c, c->device_allow);
2749 n = strcspn(rvalue, WHITESPACE);
2750 path = strndup(rvalue, n);
2754 if (!startswith(path, "/dev/") &&
2755 !startswith(path, "block-") &&
2756 !startswith(path, "char-")) {
2757 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2758 "Invalid device node path '%s'. Ignoring.", path);
2762 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2766 if (!in_charset(m, "rwm")) {
2767 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2768 "Invalid device rights '%s'. Ignoring.", m);
2772 a = new0(CGroupDeviceAllow, 1);
2778 a->r = !!strchr(m, 'r');
2779 a->w = !!strchr(m, 'w');
2780 a->m = !!strchr(m, 'm');
2782 LIST_PREPEND(device_allow, c->device_allow, a);
2786 int config_parse_blockio_weight(
2788 const char *filename,
2790 const char *section,
2791 unsigned section_line,
2798 unsigned long *weight = data, lu;
2805 if (isempty(rvalue)) {
2806 *weight = (unsigned long) -1;
2810 r = safe_atolu(rvalue, &lu);
2811 if (r < 0 || lu < 10 || lu > 1000) {
2812 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2813 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2821 int config_parse_blockio_device_weight(
2823 const char *filename,
2825 const char *section,
2826 unsigned section_line,
2833 _cleanup_free_ char *path = NULL;
2834 CGroupBlockIODeviceWeight *w;
2835 CGroupContext *c = data;
2845 if (isempty(rvalue)) {
2846 while (c->blockio_device_weights)
2847 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2852 n = strcspn(rvalue, WHITESPACE);
2853 weight = rvalue + n;
2855 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2856 "Expected block device and device weight. Ignoring.");
2860 path = strndup(rvalue, n);
2864 if (!path_startswith(path, "/dev")) {
2865 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2866 "Invalid device node path '%s'. Ignoring.", path);
2870 weight += strspn(weight, WHITESPACE);
2871 r = safe_atolu(weight, &lu);
2872 if (r < 0 || lu < 10 || lu > 1000) {
2873 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2874 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2878 w = new0(CGroupBlockIODeviceWeight, 1);
2887 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2891 int config_parse_blockio_bandwidth(
2893 const char *filename,
2895 const char *section,
2896 unsigned section_line,
2903 _cleanup_free_ char *path = NULL;
2904 CGroupBlockIODeviceBandwidth *b;
2905 CGroupContext *c = data;
2906 const char *bandwidth;
2916 read = streq("BlockIOReadBandwidth", lvalue);
2918 if (isempty(rvalue)) {
2919 CGroupBlockIODeviceBandwidth *next;
2921 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2922 if (b->read == read)
2923 cgroup_context_free_blockio_device_bandwidth(c, b);
2928 n = strcspn(rvalue, WHITESPACE);
2929 bandwidth = rvalue + n;
2930 bandwidth += strspn(bandwidth, WHITESPACE);
2933 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2934 "Expected space separated pair of device node and bandwidth. Ignoring.");
2938 path = strndup(rvalue, n);
2942 if (!path_startswith(path, "/dev")) {
2943 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2944 "Invalid device node path '%s'. Ignoring.", path);
2948 r = parse_size(bandwidth, 1000, &bytes);
2949 if (r < 0 || bytes <= 0) {
2950 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2951 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2955 b = new0(CGroupBlockIODeviceBandwidth, 1);
2961 b->bandwidth = (uint64_t) bytes;
2964 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2969 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2971 int config_parse_job_mode_isolate(
2973 const char *filename,
2975 const char *section,
2976 unsigned section_line,
2990 r = parse_boolean(rvalue);
2992 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2993 "Failed to parse boolean, ignoring: %s", rvalue);
2997 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3001 int config_parse_personality(
3003 const char *filename,
3005 const char *section,
3006 unsigned section_line,
3013 unsigned long *personality = data, p;
3018 assert(personality);
3020 p = personality_from_string(rvalue);
3021 if (p == 0xffffffffUL) {
3022 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3023 "Failed to parse personality, ignoring: %s", rvalue);
3031 int config_parse_runtime_directory(
3033 const char *filename,
3035 const char *section,
3036 unsigned section_line,
3044 const char *word, *state;
3053 if (isempty(rvalue)) {
3054 /* Empty assignment resets the list */
3060 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3061 _cleanup_free_ char *n;
3063 n = strndup(word, l);
3067 if (!filename_is_valid(n)) {
3068 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3069 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3073 r = strv_push(rt, n);
3079 if (!isempty(state))
3080 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3081 "Trailing garbage, ignoring.");
3086 int config_parse_set_status(
3088 const char *filename,
3090 const char *section,
3091 unsigned section_line,
3099 const char *word, *state;
3101 ExitStatusSet *status_set = data;
3108 /* Empty assignment resets the list */
3109 if (isempty(rvalue)) {
3110 exit_status_set_free(status_set);
3114 FOREACH_WORD(word, l, rvalue, state) {
3115 _cleanup_free_ char *temp;
3118 temp = strndup(word, l);
3122 r = safe_atoi(temp, &val);
3124 val = signal_from_string_try_harder(temp);
3127 log_syntax(unit, LOG_ERR, filename, line, -val,
3128 "Failed to parse value, ignoring: %s", word);
3132 if (val < 0 || val > 255) {
3133 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3134 "Value %d is outside range 0-255, ignoring", val);
3139 r = set_ensure_allocated(&status_set->status, NULL);
3143 r = set_put(status_set->status, INT_TO_PTR(val));
3145 log_syntax(unit, LOG_ERR, filename, line, -r,
3146 "Unable to store: %s", word);
3150 if (!isempty(state))
3151 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3152 "Trailing garbage, ignoring.");
3157 int config_parse_namespace_path_strv(
3159 const char *filename,
3161 const char *section,
3162 unsigned section_line,
3170 const char *word, *state;
3179 if (isempty(rvalue)) {
3180 /* Empty assignment resets the list */
3186 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3187 _cleanup_free_ char *n;
3190 n = strndup(word, l);
3194 if (!utf8_is_valid(n)) {
3195 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3199 offset = n[0] == '-';
3200 if (!path_is_absolute(n + offset)) {
3201 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3202 "Not an absolute path, ignoring: %s", rvalue);
3206 path_kill_slashes(n);
3208 r = strv_push(sv, n);
3214 if (!isempty(state))
3215 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3216 "Trailing garbage, ignoring.");
3221 int config_parse_no_new_privileges(
3223 const char *filename,
3225 const char *section,
3226 unsigned section_line,
3233 ExecContext *c = data;
3241 k = parse_boolean(rvalue);
3243 log_syntax(unit, LOG_ERR, filename, line, -k,
3244 "Failed to parse boolean value, ignoring: %s", rvalue);
3248 c->no_new_privileges = !!k;
3249 c->no_new_privileges_set = true;
3254 int config_parse_protect_home(
3256 const char *filename,
3258 const char *section,
3259 unsigned section_line,
3266 ExecContext *c = data;
3274 /* Our enum shall be a superset of booleans, hence first try
3275 * to parse as as boolean, and then as enum */
3277 k = parse_boolean(rvalue);
3279 c->protect_home = PROTECT_HOME_YES;
3281 c->protect_home = PROTECT_HOME_NO;
3285 h = protect_home_from_string(rvalue);
3287 log_syntax(unit, LOG_ERR, filename, line, -h,
3288 "Failed to parse protect home value, ignoring: %s", rvalue);
3292 c->protect_home = h;
3298 int config_parse_protect_system(
3300 const char *filename,
3302 const char *section,
3303 unsigned section_line,
3310 ExecContext *c = data;
3318 /* Our enum shall be a superset of booleans, hence first try
3319 * to parse as as boolean, and then as enum */
3321 k = parse_boolean(rvalue);
3323 c->protect_system = PROTECT_SYSTEM_YES;
3325 c->protect_system = PROTECT_SYSTEM_NO;
3329 s = protect_system_from_string(rvalue);
3331 log_syntax(unit, LOG_ERR, filename, line, -s,
3332 "Failed to parse protect system value, ignoring: %s", rvalue);
3336 c->protect_system = s;
3342 #define FOLLOW_MAX 8
3344 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3355 /* This will update the filename pointer if the loaded file is
3356 * reached by a symlink. The old string will be freed. */
3359 char *target, *name;
3361 if (c++ >= FOLLOW_MAX)
3364 path_kill_slashes(*filename);
3366 /* Add the file name we are currently looking at to
3367 * the names of this unit, but only if it is a valid
3369 name = basename(*filename);
3371 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3373 id = set_get(names, name);
3379 r = set_consume(names, id);
3385 /* Try to open the file name, but don't if its a symlink */
3386 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3393 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3394 r = readlink_and_make_absolute(*filename, &target);
3402 f = fdopen(fd, "re");
3414 static int merge_by_names(Unit **u, Set *names, const char *id) {
3422 /* Let's try to add in all symlink names we found */
3423 while ((k = set_steal_first(names))) {
3425 /* First try to merge in the other name into our
3427 r = unit_merge_by_name(*u, k);
3431 /* Hmm, we couldn't merge the other unit into
3432 * ours? Then let's try it the other way
3435 other = manager_get_unit((*u)->manager, k);
3439 r = unit_merge(other, *u);
3442 return merge_by_names(u, names, NULL);
3450 unit_choose_id(*u, id);
3458 static int load_from_path(Unit *u, const char *path) {
3460 _cleanup_set_free_free_ Set *symlink_names = NULL;
3461 _cleanup_fclose_ FILE *f = NULL;
3462 _cleanup_free_ char *filename = NULL;
3470 symlink_names = set_new(&string_hash_ops);
3474 if (path_is_absolute(path)) {
3476 filename = strdup(path);
3480 r = open_follow(&filename, &f, symlink_names, &id);
3492 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3494 /* Instead of opening the path right away, we manually
3495 * follow all symlinks and add their name to our unit
3496 * name set while doing so */
3497 filename = path_make_absolute(path, *p);
3501 if (u->manager->unit_path_cache &&
3502 !set_get(u->manager->unit_path_cache, filename))
3505 r = open_follow(&filename, &f, symlink_names, &id);
3514 /* Empty the symlink names for the next run */
3515 set_clear_free(symlink_names);
3524 /* Hmm, no suitable file found? */
3528 r = merge_by_names(&merged, symlink_names, id);
3533 u->load_state = UNIT_MERGED;
3537 if (fstat(fileno(f), &st) < 0)
3540 if (null_or_empty(&st))
3541 u->load_state = UNIT_MASKED;
3543 u->load_state = UNIT_LOADED;
3545 /* Now, parse the file contents */
3546 r = config_parse(u->id, filename, f,
3547 UNIT_VTABLE(u)->sections,
3548 config_item_perf_lookup, load_fragment_gperf_lookup,
3549 false, true, false, u);
3554 free(u->fragment_path);
3555 u->fragment_path = filename;
3558 u->fragment_mtime = timespec_load(&st.st_mtim);
3560 if (u->source_path) {
3561 if (stat(u->source_path, &st) >= 0)
3562 u->source_mtime = timespec_load(&st.st_mtim);
3564 u->source_mtime = 0;
3570 int unit_load_fragment(Unit *u) {
3576 assert(u->load_state == UNIT_STUB);
3579 /* First, try to find the unit under its id. We always look
3580 * for unit files in the default directories, to make it easy
3581 * to override things by placing things in /etc/systemd/system */
3582 r = load_from_path(u, u->id);
3586 /* Try to find an alias we can load this with */
3587 if (u->load_state == UNIT_STUB) {
3588 SET_FOREACH(t, u->names, i) {
3593 r = load_from_path(u, t);
3597 if (u->load_state != UNIT_STUB)
3602 /* And now, try looking for it under the suggested (originally linked) path */
3603 if (u->load_state == UNIT_STUB && u->fragment_path) {
3605 r = load_from_path(u, u->fragment_path);
3609 if (u->load_state == UNIT_STUB) {
3610 /* Hmm, this didn't work? Then let's get rid
3611 * of the fragment path stored for us, so that
3612 * we don't point to an invalid location. */
3613 free(u->fragment_path);
3614 u->fragment_path = NULL;
3618 /* Look for a template */
3619 if (u->load_state == UNIT_STUB && u->instance) {
3620 _cleanup_free_ char *k;
3622 k = unit_name_template(u->id);
3626 r = load_from_path(u, k);
3630 if (u->load_state == UNIT_STUB) {
3631 SET_FOREACH(t, u->names, i) {
3632 _cleanup_free_ char *z = NULL;
3637 z = unit_name_template(t);
3641 r = load_from_path(u, z);
3645 if (u->load_state != UNIT_STUB)
3654 void unit_dump_config_items(FILE *f) {
3655 static const struct {
3656 const ConfigParserCallback callback;
3659 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3660 { config_parse_warn_compat, "NOTSUPPORTED" },
3662 { config_parse_int, "INTEGER" },
3663 { config_parse_unsigned, "UNSIGNED" },
3664 { config_parse_iec_size, "SIZE" },
3665 { config_parse_iec_off, "SIZE" },
3666 { config_parse_si_size, "SIZE" },
3667 { config_parse_bool, "BOOLEAN" },
3668 { config_parse_string, "STRING" },
3669 { config_parse_path, "PATH" },
3670 { config_parse_unit_path_printf, "PATH" },
3671 { config_parse_strv, "STRING [...]" },
3672 { config_parse_exec_nice, "NICE" },
3673 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3674 { config_parse_exec_io_class, "IOCLASS" },
3675 { config_parse_exec_io_priority, "IOPRIORITY" },
3676 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3677 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3678 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3679 { config_parse_mode, "MODE" },
3680 { config_parse_unit_env_file, "FILE" },
3681 { config_parse_output, "OUTPUT" },
3682 { config_parse_input, "INPUT" },
3683 { config_parse_log_facility, "FACILITY" },
3684 { config_parse_log_level, "LEVEL" },
3685 { config_parse_exec_capabilities, "CAPABILITIES" },
3686 { config_parse_exec_secure_bits, "SECUREBITS" },
3687 { config_parse_bounding_set, "BOUNDINGSET" },
3688 { config_parse_limit, "LIMIT" },
3689 { config_parse_unit_deps, "UNIT [...]" },
3690 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3691 { config_parse_service_type, "SERVICETYPE" },
3692 { config_parse_service_restart, "SERVICERESTART" },
3693 #ifdef HAVE_SYSV_COMPAT
3694 { config_parse_sysv_priority, "SYSVPRIORITY" },
3696 { config_parse_kill_mode, "KILLMODE" },
3697 { config_parse_kill_signal, "SIGNAL" },
3698 { config_parse_socket_listen, "SOCKET [...]" },
3699 { config_parse_socket_bind, "SOCKETBIND" },
3700 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3701 { config_parse_sec, "SECONDS" },
3702 { config_parse_nsec, "NANOSECONDS" },
3703 { config_parse_namespace_path_strv, "PATH [...]" },
3704 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3705 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3706 { config_parse_unit_string_printf, "STRING" },
3707 { config_parse_trigger_unit, "UNIT" },
3708 { config_parse_timer, "TIMER" },
3709 { config_parse_path_spec, "PATH" },
3710 { config_parse_notify_access, "ACCESS" },
3711 { config_parse_ip_tos, "TOS" },
3712 { config_parse_unit_condition_path, "CONDITION" },
3713 { config_parse_unit_condition_string, "CONDITION" },
3714 { config_parse_unit_condition_null, "CONDITION" },
3715 { config_parse_unit_slice, "SLICE" },
3716 { config_parse_documentation, "URL" },
3717 { config_parse_service_timeout, "SECONDS" },
3718 { config_parse_failure_action, "ACTION" },
3719 { config_parse_set_status, "STATUS" },
3720 { config_parse_service_sockets, "SOCKETS" },
3721 { config_parse_environ, "ENVIRON" },
3723 { config_parse_syscall_filter, "SYSCALLS" },
3724 { config_parse_syscall_archs, "ARCHS" },
3725 { config_parse_syscall_errno, "ERRNO" },
3726 { config_parse_address_families, "FAMILIES" },
3728 { config_parse_cpu_shares, "SHARES" },
3729 { config_parse_memory_limit, "LIMIT" },
3730 { config_parse_device_allow, "DEVICE" },
3731 { config_parse_device_policy, "POLICY" },
3732 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3733 { config_parse_blockio_weight, "WEIGHT" },
3734 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3735 { config_parse_long, "LONG" },
3736 { config_parse_socket_service, "SERVICE" },
3738 { config_parse_exec_selinux_context, "LABEL" },
3740 { config_parse_job_mode, "MODE" },
3741 { config_parse_job_mode_isolate, "BOOLEAN" },
3742 { config_parse_personality, "PERSONALITY" },
3745 const char *prev = NULL;
3750 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3751 const char *rvalue = "OTHER", *lvalue;
3755 const ConfigPerfItem *p;
3757 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3759 dot = strchr(i, '.');
3760 lvalue = dot ? dot + 1 : i;
3764 if (!prev || !strneq(prev, i, prefix_len+1)) {
3768 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3771 for (j = 0; j < ELEMENTSOF(table); j++)
3772 if (p->parse == table[j].callback) {
3773 rvalue = table[j].rvalue;
3777 fprintf(f, "%s=%s\n", lvalue, rvalue);