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, *reason;
552 bool separate_argv0 = false, ignore = false;
558 rvalue += strspn(rvalue, WHITESPACE);
564 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
566 for (i = 0; i < 2; i++) {
567 if (*word == '-' && !ignore) {
572 if (*word == '@' && !separate_argv0) {
573 separate_argv0 = true;
578 if (strneq(word, ";", MAX(l, 1U)))
583 if (!isempty(state)) {
584 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
585 "Trailing garbage, ignoring.");
590 n = new(char*, k + !separate_argv0);
595 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
599 if (separate_argv0 ? path == NULL : k == 0) {
600 /* first word, very special */
601 skip = separate_argv0 + ignore;
603 /* skip special chars in the beginning */
606 } else if (strneq(word, ";", MAX(l, 1U)))
607 /* new commandline */
611 skip = strneq(word, "\\;", MAX(l, 1U));
613 c = cunescape_length(word + skip, l - skip);
619 if (!utf8_is_valid(c)) {
620 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
625 /* where to stuff this? */
626 if (separate_argv0 && path == NULL)
634 log_debug("path: %s", path ?: n[0]);
637 reason = "Empty executable name or zeroeth argument";
638 else if (!string_is_safe(path ?: n[0]))
639 reason = "Executable path contains special characters";
640 else if (!path_is_absolute(path ?: n[0]))
641 reason = "Executable path is not absolute";
642 else if (endswith(path ?: n[0], "/"))
643 reason = "Executable path specifies a directory";
647 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
648 "%s, ignoring: %s", reason, rvalue);
661 nce = new0(ExecCommand, 1);
669 nce->ignore = ignore;
671 path_kill_slashes(nce->path);
673 exec_command_append_list(e, nce);
689 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
690 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
692 int config_parse_socket_bindtodevice(const char* unit,
693 const char *filename,
696 unsigned section_line,
711 if (rvalue[0] && !streq(rvalue, "*")) {
718 free(s->bind_to_device);
719 s->bind_to_device = n;
724 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
725 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
727 int config_parse_exec_io_class(const char *unit,
728 const char *filename,
731 unsigned section_line,
738 ExecContext *c = data;
746 x = ioprio_class_from_string(rvalue);
748 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
749 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
753 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
754 c->ioprio_set = true;
759 int config_parse_exec_io_priority(const char *unit,
760 const char *filename,
763 unsigned section_line,
770 ExecContext *c = data;
778 r = safe_atoi(rvalue, &i);
779 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
780 log_syntax(unit, LOG_ERR, filename, line, -r,
781 "Failed to parse IO priority, ignoring: %s", rvalue);
785 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
786 c->ioprio_set = true;
791 int config_parse_exec_cpu_sched_policy(const char *unit,
792 const char *filename,
795 unsigned section_line,
803 ExecContext *c = data;
811 x = sched_policy_from_string(rvalue);
813 log_syntax(unit, LOG_ERR, filename, line, -x,
814 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
818 c->cpu_sched_policy = x;
819 /* Moving to or from real-time policy? We need to adjust the priority */
820 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
821 c->cpu_sched_set = true;
826 int config_parse_exec_cpu_sched_prio(const char *unit,
827 const char *filename,
830 unsigned section_line,
837 ExecContext *c = data;
845 r = safe_atoi(rvalue, &i);
847 log_syntax(unit, LOG_ERR, filename, line, -r,
848 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
852 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
853 min = sched_get_priority_min(c->cpu_sched_policy);
854 max = sched_get_priority_max(c->cpu_sched_policy);
856 if (i < min || i > max) {
857 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
858 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
862 c->cpu_sched_priority = i;
863 c->cpu_sched_set = true;
868 int config_parse_exec_cpu_affinity(const char *unit,
869 const char *filename,
872 unsigned section_line,
879 ExecContext *c = data;
880 const char *word, *state;
888 if (isempty(rvalue)) {
889 /* An empty assignment resets the CPU list */
896 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
897 _cleanup_free_ char *t = NULL;
901 t = strndup(word, l);
905 r = safe_atou(t, &cpu);
908 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
913 if (r < 0 || cpu >= c->cpuset_ncpus) {
914 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
915 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
919 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
922 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
923 "Trailing garbage, ignoring.");
928 int config_parse_exec_capabilities(const char *unit,
929 const char *filename,
932 unsigned section_line,
939 ExecContext *c = data;
947 cap = cap_from_text(rvalue);
949 log_syntax(unit, LOG_ERR, filename, line, errno,
950 "Failed to parse capabilities, ignoring: %s", rvalue);
955 cap_free(c->capabilities);
956 c->capabilities = cap;
961 int config_parse_exec_secure_bits(const char *unit,
962 const char *filename,
965 unsigned section_line,
972 ExecContext *c = data;
974 const char *word, *state;
981 if (isempty(rvalue)) {
982 /* An empty assignment resets the field */
987 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
988 if (first_word(word, "keep-caps"))
989 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
990 else if (first_word(word, "keep-caps-locked"))
991 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
992 else if (first_word(word, "no-setuid-fixup"))
993 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
994 else if (first_word(word, "no-setuid-fixup-locked"))
995 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
996 else if (first_word(word, "noroot"))
997 c->secure_bits |= 1<<SECURE_NOROOT;
998 else if (first_word(word, "noroot-locked"))
999 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
1001 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1002 "Failed to parse secure bits, ignoring: %s", rvalue);
1006 if (!isempty(state))
1007 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1008 "Invalid syntax, garbage at the end, ignoring.");
1013 int config_parse_bounding_set(const char *unit,
1014 const char *filename,
1016 const char *section,
1017 unsigned section_line,
1024 uint64_t *capability_bounding_set_drop = data;
1025 const char *word, *state;
1027 bool invert = false;
1035 if (rvalue[0] == '~') {
1040 /* Note that we store this inverted internally, since the
1041 * kernel wants it like this. But we actually expose it
1042 * non-inverted everywhere to have a fully normalized
1045 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1046 _cleanup_free_ char *t = NULL;
1049 t = strndup(word, l);
1053 cap = capability_from_name(t);
1055 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
1059 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1061 if (!isempty(state))
1062 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1063 "Trailing garbage, ignoring.");
1066 *capability_bounding_set_drop |= sum;
1068 *capability_bounding_set_drop |= ~sum;
1073 int config_parse_limit(const char *unit,
1074 const char *filename,
1076 const char *section,
1077 unsigned section_line,
1084 struct rlimit **rl = data;
1085 unsigned long long u;
1094 if (streq(rvalue, "infinity"))
1095 u = (unsigned long long) RLIM_INFINITY;
1099 r = safe_atollu(rvalue, &u);
1101 log_syntax(unit, LOG_ERR, filename, line, -r,
1102 "Failed to parse resource value, ignoring: %s", rvalue);
1108 *rl = new(struct rlimit, 1);
1113 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1117 #ifdef HAVE_SYSV_COMPAT
1118 int config_parse_sysv_priority(const char *unit,
1119 const char *filename,
1121 const char *section,
1122 unsigned section_line,
1129 int *priority = data;
1137 r = safe_atoi(rvalue, &i);
1138 if (r < 0 || i < 0) {
1139 log_syntax(unit, LOG_ERR, filename, line, -r,
1140 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1144 *priority = (int) i;
1149 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1151 int config_parse_kill_signal(const char *unit,
1152 const char *filename,
1154 const char *section,
1155 unsigned section_line,
1170 r = signal_from_string_try_harder(rvalue);
1172 log_syntax(unit, LOG_ERR, filename, line, -r,
1173 "Failed to parse kill signal, ignoring: %s", rvalue);
1181 int config_parse_exec_mount_flags(const char *unit,
1182 const char *filename,
1184 const char *section,
1185 unsigned section_line,
1192 ExecContext *c = data;
1193 const char *word, *state;
1195 unsigned long flags = 0;
1202 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1203 _cleanup_free_ char *t;
1205 t = strndup(word, l);
1209 if (streq(t, "shared"))
1211 else if (streq(t, "slave"))
1213 else if (streq(word, "private"))
1216 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1217 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1221 if (!isempty(state))
1222 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1223 "Trailing garbage, ignoring.");
1225 c->mount_flags = flags;
1229 int config_parse_exec_selinux_context(
1231 const char *filename,
1233 const char *section,
1234 unsigned section_line,
1241 ExecContext *c = data;
1252 if (isempty(rvalue)) {
1253 free(c->selinux_context);
1254 c->selinux_context = NULL;
1255 c->selinux_context_ignore = false;
1259 if (rvalue[0] == '-') {
1265 r = unit_name_printf(u, rvalue, &k);
1267 log_syntax(unit, LOG_ERR, filename, line, -r,
1268 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1272 free(c->selinux_context);
1273 c->selinux_context = k;
1274 c->selinux_context_ignore = ignore;
1279 int config_parse_exec_apparmor_profile(
1281 const char *filename,
1283 const char *section,
1284 unsigned section_line,
1291 ExecContext *c = data;
1302 if (isempty(rvalue)) {
1303 free(c->apparmor_profile);
1304 c->apparmor_profile = NULL;
1305 c->apparmor_profile_ignore = false;
1309 if (rvalue[0] == '-') {
1315 r = unit_name_printf(u, rvalue, &k);
1317 log_syntax(unit, LOG_ERR, filename, line, -r,
1318 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1322 free(c->apparmor_profile);
1323 c->apparmor_profile = k;
1324 c->apparmor_profile_ignore = ignore;
1329 int config_parse_exec_smack_process_label(
1331 const char *filename,
1333 const char *section,
1334 unsigned section_line,
1341 ExecContext *c = data;
1352 if (isempty(rvalue)) {
1353 free(c->smack_process_label);
1354 c->smack_process_label = NULL;
1355 c->smack_process_label_ignore = false;
1359 if (rvalue[0] == '-') {
1365 r = unit_name_printf(u, rvalue, &k);
1367 log_syntax(unit, LOG_ERR, filename, line, -r,
1368 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1372 free(c->smack_process_label);
1373 c->smack_process_label = k;
1374 c->smack_process_label_ignore = ignore;
1379 int config_parse_timer(const char *unit,
1380 const char *filename,
1382 const char *section,
1383 unsigned section_line,
1394 CalendarSpec *c = NULL;
1401 if (isempty(rvalue)) {
1402 /* Empty assignment resets list */
1403 timer_free_values(t);
1407 b = timer_base_from_string(lvalue);
1409 log_syntax(unit, LOG_ERR, filename, line, -b,
1410 "Failed to parse timer base, ignoring: %s", lvalue);
1414 if (b == TIMER_CALENDAR) {
1415 if (calendar_spec_from_string(rvalue, &c) < 0) {
1416 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1417 "Failed to parse calendar specification, ignoring: %s",
1422 if (parse_sec(rvalue, &u) < 0) {
1423 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1424 "Failed to parse timer value, ignoring: %s",
1430 v = new0(TimerValue, 1);
1432 calendar_spec_free(c);
1438 v->calendar_spec = c;
1440 LIST_PREPEND(value, t->values, v);
1445 int config_parse_trigger_unit(
1447 const char *filename,
1449 const char *section,
1450 unsigned section_line,
1457 _cleanup_free_ char *p = NULL;
1467 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1468 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1469 "Multiple units to trigger specified, ignoring: %s", rvalue);
1473 r = unit_name_printf(u, rvalue, &p);
1475 log_syntax(unit, LOG_ERR, filename, line, -r,
1476 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1478 type = unit_name_to_type(p ?: rvalue);
1480 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1481 "Unit type not valid, ignoring: %s", rvalue);
1485 if (type == u->type) {
1486 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1487 "Trigger cannot be of same type, ignoring: %s", rvalue);
1491 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1493 log_syntax(unit, LOG_ERR, filename, line, -r,
1494 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1501 int config_parse_path_spec(const char *unit,
1502 const char *filename,
1504 const char *section,
1505 unsigned section_line,
1515 _cleanup_free_ char *k = NULL;
1523 if (isempty(rvalue)) {
1524 /* Empty assignment clears list */
1529 b = path_type_from_string(lvalue);
1531 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1532 "Failed to parse path type, ignoring: %s", lvalue);
1536 r = unit_full_printf(UNIT(p), rvalue, &k);
1542 log_syntax(unit, LOG_ERR, filename, line, -r,
1543 "Failed to resolve unit specifiers on %s. Ignoring.",
1547 if (!path_is_absolute(k)) {
1548 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1549 "Path is not absolute, ignoring: %s", k);
1553 s = new0(PathSpec, 1);
1558 s->path = path_kill_slashes(k);
1563 LIST_PREPEND(spec, p->specs, s);
1568 int config_parse_socket_service(const char *unit,
1569 const char *filename,
1571 const char *section,
1572 unsigned section_line,
1579 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1583 _cleanup_free_ char *p = NULL;
1590 r = unit_name_printf(UNIT(s), rvalue, &p);
1592 log_syntax(unit, LOG_ERR, filename, line, -r,
1593 "Failed to resolve specifiers, ignoring: %s", rvalue);
1597 if (!endswith(p, ".service")) {
1598 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1599 "Unit must be of type service, ignoring: %s", rvalue);
1603 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1605 log_syntax(unit, LOG_ERR, filename, line, -r,
1606 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1610 unit_ref_set(&s->service, x);
1615 int config_parse_service_sockets(const char *unit,
1616 const char *filename,
1618 const char *section,
1619 unsigned section_line,
1628 const char *word, *state;
1636 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1637 _cleanup_free_ char *t = NULL, *k = NULL;
1639 t = strndup(word, l);
1643 r = unit_name_printf(UNIT(s), t, &k);
1645 log_syntax(unit, LOG_ERR, filename, line, -r,
1646 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1648 if (!endswith(k ?: t, ".socket")) {
1649 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1650 "Unit must be of type socket, ignoring: %s", k ?: t);
1654 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1656 log_syntax(unit, LOG_ERR, filename, line, -r,
1657 "Failed to add dependency on %s, ignoring: %s",
1658 k ?: t, strerror(-r));
1660 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1664 if (!isempty(state))
1665 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1666 "Trailing garbage, ignoring.");
1671 int config_parse_service_timeout(const char *unit,
1672 const char *filename,
1674 const char *section,
1675 unsigned section_line,
1682 Service *s = userdata;
1690 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1691 rvalue, data, userdata);
1695 if (streq(lvalue, "TimeoutSec")) {
1696 s->start_timeout_defined = true;
1697 s->timeout_stop_usec = s->timeout_start_usec;
1698 } else if (streq(lvalue, "TimeoutStartSec"))
1699 s->start_timeout_defined = true;
1704 int config_parse_busname_service(
1706 const char *filename,
1708 const char *section,
1709 unsigned section_line,
1716 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1720 _cleanup_free_ char *p = NULL;
1727 r = unit_name_printf(UNIT(n), rvalue, &p);
1729 log_syntax(unit, LOG_ERR, filename, line, -r,
1730 "Failed to resolve specifiers, ignoring: %s", rvalue);
1734 if (!endswith(p, ".service")) {
1735 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1736 "Unit must be of type service, ignoring: %s", rvalue);
1740 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1742 log_syntax(unit, LOG_ERR, filename, line, -r,
1743 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1747 unit_ref_set(&n->service, x);
1752 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1754 int config_parse_bus_policy(
1756 const char *filename,
1758 const char *section,
1759 unsigned section_line,
1766 _cleanup_free_ BusNamePolicy *p = NULL;
1767 _cleanup_free_ char *id_str = NULL;
1768 BusName *busname = data;
1776 p = new0(BusNamePolicy, 1);
1780 if (streq(lvalue, "AllowUser"))
1781 p->type = BUSNAME_POLICY_TYPE_USER;
1782 else if (streq(lvalue, "AllowGroup"))
1783 p->type = BUSNAME_POLICY_TYPE_GROUP;
1785 assert_not_reached("Unknown lvalue");
1787 id_str = strdup(rvalue);
1791 access_str = strpbrk(id_str, WHITESPACE);
1793 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1794 "Invalid busname policy value '%s'", rvalue);
1800 access_str += strspn(access_str, WHITESPACE);
1802 p->access = bus_policy_access_from_string(access_str);
1803 if (p->access < 0) {
1804 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1805 "Invalid busname policy access type '%s'", access_str);
1812 LIST_PREPEND(policy, busname->policy, p);
1818 int config_parse_bus_endpoint_policy(
1820 const char *filename,
1822 const char *section,
1823 unsigned section_line,
1830 _cleanup_free_ char *name = NULL;
1831 BusPolicyAccess access;
1832 ExecContext *c = data;
1841 name = strdup(rvalue);
1845 access_str = strpbrk(name, WHITESPACE);
1847 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1848 "Invalid endpoint policy value '%s'", rvalue);
1854 access_str += strspn(access_str, WHITESPACE);
1856 access = bus_policy_access_from_string(access_str);
1857 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1858 access >= _BUS_POLICY_ACCESS_MAX) {
1859 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1860 "Invalid endpoint policy access type '%s'", access_str);
1864 if (!c->bus_endpoint) {
1865 r = bus_endpoint_new(&c->bus_endpoint);
1871 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1874 int config_parse_unit_env_file(const char *unit,
1875 const char *filename,
1877 const char *section,
1878 unsigned section_line,
1887 _cleanup_free_ char *n = NULL;
1896 if (isempty(rvalue)) {
1897 /* Empty assignment frees the list */
1903 r = unit_full_printf(u, rvalue, &n);
1905 log_syntax(unit, LOG_ERR, filename, line, -r,
1906 "Failed to resolve specifiers, ignoring: %s", rvalue);
1909 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1910 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1911 "Path '%s' is not absolute, ignoring.", s);
1915 r = strv_extend(env, s);
1922 int config_parse_environ(const char *unit,
1923 const char *filename,
1925 const char *section,
1926 unsigned section_line,
1935 const char *word, *state;
1937 _cleanup_free_ char *k = NULL;
1945 if (isempty(rvalue)) {
1946 /* Empty assignment resets the list */
1953 r = unit_full_printf(u, rvalue, &k);
1955 log_syntax(unit, LOG_ERR, filename, line, -r,
1956 "Failed to resolve specifiers, ignoring: %s", rvalue);
1964 FOREACH_WORD_QUOTED(word, l, k, state) {
1965 _cleanup_free_ char *n;
1968 n = cunescape_length(word, l);
1972 if (!env_assignment_is_valid(n)) {
1973 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1974 "Invalid environment assignment, ignoring: %s", rvalue);
1978 x = strv_env_set(*env, n);
1985 if (!isempty(state))
1986 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1987 "Trailing garbage, ignoring.");
1992 int config_parse_ip_tos(const char *unit,
1993 const char *filename,
1995 const char *section,
1996 unsigned section_line,
2003 int *ip_tos = data, x;
2010 x = ip_tos_from_string(rvalue);
2012 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2013 "Failed to parse IP TOS value, ignoring: %s", rvalue);
2021 int config_parse_unit_condition_path(
2023 const char *filename,
2025 const char *section,
2026 unsigned section_line,
2033 _cleanup_free_ char *p = NULL;
2034 Condition **list = data, *c;
2035 ConditionType t = ltype;
2036 bool trigger, negate;
2045 if (isempty(rvalue)) {
2046 /* Empty assignment resets the list */
2047 *list = condition_free_list(*list);
2051 trigger = rvalue[0] == '|';
2055 negate = rvalue[0] == '!';
2059 r = unit_full_printf(u, rvalue, &p);
2061 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2065 if (!path_is_absolute(p)) {
2066 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2070 c = condition_new(t, p, trigger, negate);
2074 LIST_PREPEND(conditions, *list, c);
2078 int config_parse_unit_condition_string(
2080 const char *filename,
2082 const char *section,
2083 unsigned section_line,
2090 _cleanup_free_ char *s = NULL;
2091 Condition **list = data, *c;
2092 ConditionType t = ltype;
2093 bool trigger, negate;
2102 if (isempty(rvalue)) {
2103 /* Empty assignment resets the list */
2104 *list = condition_free_list(*list);
2108 trigger = rvalue[0] == '|';
2112 negate = rvalue[0] == '!';
2116 r = unit_full_printf(u, rvalue, &s);
2118 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2122 c = condition_new(t, s, trigger, negate);
2126 LIST_PREPEND(conditions, *list, c);
2130 int config_parse_unit_condition_null(
2132 const char *filename,
2134 const char *section,
2135 unsigned section_line,
2142 Condition **list = data, *c;
2143 bool trigger, negate;
2151 if (isempty(rvalue)) {
2152 /* Empty assignment resets the list */
2153 *list = condition_free_list(*list);
2157 trigger = rvalue[0] == '|';
2161 negate = rvalue[0] == '!';
2165 b = parse_boolean(rvalue);
2167 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2174 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2178 LIST_PREPEND(conditions, *list, c);
2182 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2183 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2185 int config_parse_unit_requires_mounts_for(
2187 const char *filename,
2189 const char *section,
2190 unsigned section_line,
2198 const char *word, *state;
2206 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2208 _cleanup_free_ char *n;
2210 n = strndup(word, l);
2214 if (!utf8_is_valid(n)) {
2215 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2219 r = unit_require_mounts_for(u, n);
2221 log_syntax(unit, LOG_ERR, filename, line, -r,
2222 "Failed to add required mount for, ignoring: %s", rvalue);
2226 if (!isempty(state))
2227 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2228 "Trailing garbage, ignoring.");
2233 int config_parse_documentation(const char *unit,
2234 const char *filename,
2236 const char *section,
2237 unsigned section_line,
2253 if (isempty(rvalue)) {
2254 /* Empty assignment resets the list */
2255 strv_free(u->documentation);
2256 u->documentation = NULL;
2260 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2261 rvalue, data, userdata);
2265 for (a = b = u->documentation; a && *a; a++) {
2267 if (is_valid_documentation_url(*a))
2270 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2271 "Invalid URL, ignoring: %s", *a);
2282 int config_parse_syscall_filter(
2284 const char *filename,
2286 const char *section,
2287 unsigned section_line,
2294 static const char default_syscalls[] =
2301 ExecContext *c = data;
2303 bool invert = false;
2304 const char *word, *state;
2313 if (isempty(rvalue)) {
2314 /* Empty assignment resets the list */
2315 set_free(c->syscall_filter);
2316 c->syscall_filter = NULL;
2317 c->syscall_whitelist = false;
2321 if (rvalue[0] == '~') {
2326 if (!c->syscall_filter) {
2327 c->syscall_filter = set_new(NULL);
2328 if (!c->syscall_filter)
2332 /* Allow everything but the ones listed */
2333 c->syscall_whitelist = false;
2337 /* Allow nothing but the ones listed */
2338 c->syscall_whitelist = true;
2340 /* Accept default syscalls if we are on a whitelist */
2341 NULSTR_FOREACH(i, default_syscalls) {
2344 id = seccomp_syscall_resolve_name(i);
2348 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2357 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2358 _cleanup_free_ char *t = NULL;
2361 t = strndup(word, l);
2365 id = seccomp_syscall_resolve_name(t);
2367 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2368 "Failed to parse system call, ignoring: %s", t);
2372 /* If we previously wanted to forbid a syscall and now
2373 * we want to allow it, then remove it from the list
2375 if (!invert == c->syscall_whitelist) {
2376 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2382 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2384 if (!isempty(state))
2385 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2386 "Trailing garbage, ignoring.");
2388 /* Turn on NNP, but only if it wasn't configured explicitly
2389 * before, and only if we are in user mode. */
2390 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2391 c->no_new_privileges = true;
2396 int config_parse_syscall_archs(
2398 const char *filename,
2400 const char *section,
2401 unsigned section_line,
2409 const char *word, *state;
2413 if (isempty(rvalue)) {
2419 r = set_ensure_allocated(archs, NULL);
2423 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2424 _cleanup_free_ char *t = NULL;
2427 t = strndup(word, l);
2431 r = seccomp_arch_from_string(t, &a);
2433 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2434 "Failed to parse system call architecture, ignoring: %s", t);
2438 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2444 if (!isempty(state))
2445 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2446 "Trailing garbage, ignoring.");
2451 int config_parse_syscall_errno(
2453 const char *filename,
2455 const char *section,
2456 unsigned section_line,
2463 ExecContext *c = data;
2470 if (isempty(rvalue)) {
2471 /* Empty assignment resets to KILL */
2472 c->syscall_errno = 0;
2476 e = errno_from_name(rvalue);
2478 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2479 "Failed to parse error number, ignoring: %s", rvalue);
2483 c->syscall_errno = e;
2487 int config_parse_address_families(
2489 const char *filename,
2491 const char *section,
2492 unsigned section_line,
2499 ExecContext *c = data;
2500 bool invert = false;
2501 const char *word, *state;
2509 if (isempty(rvalue)) {
2510 /* Empty assignment resets the list */
2511 set_free(c->address_families);
2512 c->address_families = NULL;
2513 c->address_families_whitelist = false;
2517 if (rvalue[0] == '~') {
2522 if (!c->address_families) {
2523 c->address_families = set_new(NULL);
2524 if (!c->address_families)
2527 c->address_families_whitelist = !invert;
2530 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2531 _cleanup_free_ char *t = NULL;
2534 t = strndup(word, l);
2538 af = af_from_name(t);
2540 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2541 "Failed to parse address family, ignoring: %s", t);
2545 /* If we previously wanted to forbid an address family and now
2546 * we want to allow it, then remove it from the list
2548 if (!invert == c->address_families_whitelist) {
2549 r = set_put(c->address_families, INT_TO_PTR(af));
2555 set_remove(c->address_families, INT_TO_PTR(af));
2557 if (!isempty(state))
2558 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2559 "Trailing garbage, ignoring.");
2565 int config_parse_unit_slice(
2567 const char *filename,
2569 const char *section,
2570 unsigned section_line,
2577 _cleanup_free_ char *k = NULL;
2578 Unit *u = userdata, *slice;
2586 r = unit_name_printf(u, rvalue, &k);
2588 log_syntax(unit, LOG_ERR, filename, line, -r,
2589 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2596 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2598 log_syntax(unit, LOG_ERR, filename, line, -r,
2599 "Failed to load slice unit %s. Ignoring.", k);
2603 if (slice->type != UNIT_SLICE) {
2604 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2605 "Slice unit %s is not a slice. Ignoring.", k);
2609 unit_ref_set(&u->slice, slice);
2613 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2615 int config_parse_cpu_shares(
2617 const char *filename,
2619 const char *section,
2620 unsigned section_line,
2627 unsigned long *shares = data, lu;
2634 if (isempty(rvalue)) {
2635 *shares = (unsigned long) -1;
2639 r = safe_atolu(rvalue, &lu);
2640 if (r < 0 || lu <= 0) {
2641 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2642 "CPU shares '%s' invalid. Ignoring.", rvalue);
2650 int config_parse_cpu_quota(
2652 const char *filename,
2654 const char *section,
2655 unsigned section_line,
2662 CGroupContext *c = data;
2669 if (isempty(rvalue)) {
2670 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2674 if (!endswith(rvalue, "%")) {
2676 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2677 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2681 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2682 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2683 "CPU quota '%s' invalid. Ignoring.", rvalue);
2687 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2692 int config_parse_memory_limit(
2694 const char *filename,
2696 const char *section,
2697 unsigned section_line,
2704 CGroupContext *c = data;
2708 if (isempty(rvalue)) {
2709 c->memory_limit = (uint64_t) -1;
2713 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2715 r = parse_size(rvalue, 1024, &bytes);
2717 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2718 "Memory limit '%s' invalid. Ignoring.", rvalue);
2722 c->memory_limit = (uint64_t) bytes;
2726 int config_parse_device_allow(
2728 const char *filename,
2730 const char *section,
2731 unsigned section_line,
2738 _cleanup_free_ char *path = NULL;
2739 CGroupContext *c = data;
2740 CGroupDeviceAllow *a;
2744 if (isempty(rvalue)) {
2745 while (c->device_allow)
2746 cgroup_context_free_device_allow(c, c->device_allow);
2751 n = strcspn(rvalue, WHITESPACE);
2752 path = strndup(rvalue, n);
2756 if (!startswith(path, "/dev/") &&
2757 !startswith(path, "block-") &&
2758 !startswith(path, "char-")) {
2759 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2760 "Invalid device node path '%s'. Ignoring.", path);
2764 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2768 if (!in_charset(m, "rwm")) {
2769 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2770 "Invalid device rights '%s'. Ignoring.", m);
2774 a = new0(CGroupDeviceAllow, 1);
2780 a->r = !!strchr(m, 'r');
2781 a->w = !!strchr(m, 'w');
2782 a->m = !!strchr(m, 'm');
2784 LIST_PREPEND(device_allow, c->device_allow, a);
2788 int config_parse_blockio_weight(
2790 const char *filename,
2792 const char *section,
2793 unsigned section_line,
2800 unsigned long *weight = data, lu;
2807 if (isempty(rvalue)) {
2808 *weight = (unsigned long) -1;
2812 r = safe_atolu(rvalue, &lu);
2813 if (r < 0 || lu < 10 || lu > 1000) {
2814 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2815 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2823 int config_parse_blockio_device_weight(
2825 const char *filename,
2827 const char *section,
2828 unsigned section_line,
2835 _cleanup_free_ char *path = NULL;
2836 CGroupBlockIODeviceWeight *w;
2837 CGroupContext *c = data;
2847 if (isempty(rvalue)) {
2848 while (c->blockio_device_weights)
2849 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2854 n = strcspn(rvalue, WHITESPACE);
2855 weight = rvalue + n;
2857 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2858 "Expected block device and device weight. Ignoring.");
2862 path = strndup(rvalue, n);
2866 if (!path_startswith(path, "/dev")) {
2867 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2868 "Invalid device node path '%s'. Ignoring.", path);
2872 weight += strspn(weight, WHITESPACE);
2873 r = safe_atolu(weight, &lu);
2874 if (r < 0 || lu < 10 || lu > 1000) {
2875 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2876 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2880 w = new0(CGroupBlockIODeviceWeight, 1);
2889 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2893 int config_parse_blockio_bandwidth(
2895 const char *filename,
2897 const char *section,
2898 unsigned section_line,
2905 _cleanup_free_ char *path = NULL;
2906 CGroupBlockIODeviceBandwidth *b;
2907 CGroupContext *c = data;
2908 const char *bandwidth;
2918 read = streq("BlockIOReadBandwidth", lvalue);
2920 if (isempty(rvalue)) {
2921 CGroupBlockIODeviceBandwidth *next;
2923 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2924 if (b->read == read)
2925 cgroup_context_free_blockio_device_bandwidth(c, b);
2930 n = strcspn(rvalue, WHITESPACE);
2931 bandwidth = rvalue + n;
2932 bandwidth += strspn(bandwidth, WHITESPACE);
2935 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2936 "Expected space separated pair of device node and bandwidth. Ignoring.");
2940 path = strndup(rvalue, n);
2944 if (!path_startswith(path, "/dev")) {
2945 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2946 "Invalid device node path '%s'. Ignoring.", path);
2950 r = parse_size(bandwidth, 1000, &bytes);
2951 if (r < 0 || bytes <= 0) {
2952 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2953 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2957 b = new0(CGroupBlockIODeviceBandwidth, 1);
2963 b->bandwidth = (uint64_t) bytes;
2966 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2971 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2973 int config_parse_job_mode_isolate(
2975 const char *filename,
2977 const char *section,
2978 unsigned section_line,
2992 r = parse_boolean(rvalue);
2994 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2995 "Failed to parse boolean, ignoring: %s", rvalue);
2999 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3003 int config_parse_personality(
3005 const char *filename,
3007 const char *section,
3008 unsigned section_line,
3015 unsigned long *personality = data, p;
3020 assert(personality);
3022 p = personality_from_string(rvalue);
3023 if (p == 0xffffffffUL) {
3024 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3025 "Failed to parse personality, ignoring: %s", rvalue);
3033 int config_parse_runtime_directory(
3035 const char *filename,
3037 const char *section,
3038 unsigned section_line,
3046 const char *word, *state;
3055 if (isempty(rvalue)) {
3056 /* Empty assignment resets the list */
3062 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3063 _cleanup_free_ char *n;
3065 n = strndup(word, l);
3069 if (!filename_is_valid(n)) {
3070 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3071 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3075 r = strv_push(rt, n);
3081 if (!isempty(state))
3082 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3083 "Trailing garbage, ignoring.");
3088 int config_parse_set_status(
3090 const char *filename,
3092 const char *section,
3093 unsigned section_line,
3101 const char *word, *state;
3103 ExitStatusSet *status_set = data;
3110 /* Empty assignment resets the list */
3111 if (isempty(rvalue)) {
3112 exit_status_set_free(status_set);
3116 FOREACH_WORD(word, l, rvalue, state) {
3117 _cleanup_free_ char *temp;
3120 temp = strndup(word, l);
3124 r = safe_atoi(temp, &val);
3126 val = signal_from_string_try_harder(temp);
3129 log_syntax(unit, LOG_ERR, filename, line, -val,
3130 "Failed to parse value, ignoring: %s", word);
3134 if (val < 0 || val > 255) {
3135 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3136 "Value %d is outside range 0-255, ignoring", val);
3141 r = set_ensure_allocated(&status_set->status, NULL);
3145 r = set_put(status_set->status, INT_TO_PTR(val));
3147 log_syntax(unit, LOG_ERR, filename, line, -r,
3148 "Unable to store: %s", word);
3152 if (!isempty(state))
3153 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3154 "Trailing garbage, ignoring.");
3159 int config_parse_namespace_path_strv(
3161 const char *filename,
3163 const char *section,
3164 unsigned section_line,
3172 const char *word, *state;
3181 if (isempty(rvalue)) {
3182 /* Empty assignment resets the list */
3188 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3189 _cleanup_free_ char *n;
3192 n = strndup(word, l);
3196 if (!utf8_is_valid(n)) {
3197 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3201 offset = n[0] == '-';
3202 if (!path_is_absolute(n + offset)) {
3203 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3204 "Not an absolute path, ignoring: %s", rvalue);
3208 path_kill_slashes(n);
3210 r = strv_push(sv, n);
3216 if (!isempty(state))
3217 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3218 "Trailing garbage, ignoring.");
3223 int config_parse_no_new_privileges(
3225 const char *filename,
3227 const char *section,
3228 unsigned section_line,
3235 ExecContext *c = data;
3243 k = parse_boolean(rvalue);
3245 log_syntax(unit, LOG_ERR, filename, line, -k,
3246 "Failed to parse boolean value, ignoring: %s", rvalue);
3250 c->no_new_privileges = !!k;
3251 c->no_new_privileges_set = true;
3256 int config_parse_protect_home(
3258 const char *filename,
3260 const char *section,
3261 unsigned section_line,
3268 ExecContext *c = data;
3276 /* Our enum shall be a superset of booleans, hence first try
3277 * to parse as as boolean, and then as enum */
3279 k = parse_boolean(rvalue);
3281 c->protect_home = PROTECT_HOME_YES;
3283 c->protect_home = PROTECT_HOME_NO;
3287 h = protect_home_from_string(rvalue);
3289 log_syntax(unit, LOG_ERR, filename, line, -h,
3290 "Failed to parse protect home value, ignoring: %s", rvalue);
3294 c->protect_home = h;
3300 int config_parse_protect_system(
3302 const char *filename,
3304 const char *section,
3305 unsigned section_line,
3312 ExecContext *c = data;
3320 /* Our enum shall be a superset of booleans, hence first try
3321 * to parse as as boolean, and then as enum */
3323 k = parse_boolean(rvalue);
3325 c->protect_system = PROTECT_SYSTEM_YES;
3327 c->protect_system = PROTECT_SYSTEM_NO;
3331 s = protect_system_from_string(rvalue);
3333 log_syntax(unit, LOG_ERR, filename, line, -s,
3334 "Failed to parse protect system value, ignoring: %s", rvalue);
3338 c->protect_system = s;
3344 #define FOLLOW_MAX 8
3346 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3357 /* This will update the filename pointer if the loaded file is
3358 * reached by a symlink. The old string will be freed. */
3361 char *target, *name;
3363 if (c++ >= FOLLOW_MAX)
3366 path_kill_slashes(*filename);
3368 /* Add the file name we are currently looking at to
3369 * the names of this unit, but only if it is a valid
3371 name = basename(*filename);
3373 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3375 id = set_get(names, name);
3381 r = set_consume(names, id);
3387 /* Try to open the file name, but don't if its a symlink */
3388 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3395 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3396 r = readlink_and_make_absolute(*filename, &target);
3404 f = fdopen(fd, "re");
3416 static int merge_by_names(Unit **u, Set *names, const char *id) {
3424 /* Let's try to add in all symlink names we found */
3425 while ((k = set_steal_first(names))) {
3427 /* First try to merge in the other name into our
3429 r = unit_merge_by_name(*u, k);
3433 /* Hmm, we couldn't merge the other unit into
3434 * ours? Then let's try it the other way
3437 other = manager_get_unit((*u)->manager, k);
3441 r = unit_merge(other, *u);
3444 return merge_by_names(u, names, NULL);
3452 unit_choose_id(*u, id);
3460 static int load_from_path(Unit *u, const char *path) {
3462 _cleanup_set_free_free_ Set *symlink_names = NULL;
3463 _cleanup_fclose_ FILE *f = NULL;
3464 _cleanup_free_ char *filename = NULL;
3472 symlink_names = set_new(&string_hash_ops);
3476 if (path_is_absolute(path)) {
3478 filename = strdup(path);
3482 r = open_follow(&filename, &f, symlink_names, &id);
3494 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3496 /* Instead of opening the path right away, we manually
3497 * follow all symlinks and add their name to our unit
3498 * name set while doing so */
3499 filename = path_make_absolute(path, *p);
3503 if (u->manager->unit_path_cache &&
3504 !set_get(u->manager->unit_path_cache, filename))
3507 r = open_follow(&filename, &f, symlink_names, &id);
3516 /* Empty the symlink names for the next run */
3517 set_clear_free(symlink_names);
3526 /* Hmm, no suitable file found? */
3530 r = merge_by_names(&merged, symlink_names, id);
3535 u->load_state = UNIT_MERGED;
3539 if (fstat(fileno(f), &st) < 0)
3542 if (null_or_empty(&st))
3543 u->load_state = UNIT_MASKED;
3545 u->load_state = UNIT_LOADED;
3547 /* Now, parse the file contents */
3548 r = config_parse(u->id, filename, f,
3549 UNIT_VTABLE(u)->sections,
3550 config_item_perf_lookup, load_fragment_gperf_lookup,
3551 false, true, false, u);
3556 free(u->fragment_path);
3557 u->fragment_path = filename;
3560 u->fragment_mtime = timespec_load(&st.st_mtim);
3562 if (u->source_path) {
3563 if (stat(u->source_path, &st) >= 0)
3564 u->source_mtime = timespec_load(&st.st_mtim);
3566 u->source_mtime = 0;
3572 int unit_load_fragment(Unit *u) {
3578 assert(u->load_state == UNIT_STUB);
3581 /* First, try to find the unit under its id. We always look
3582 * for unit files in the default directories, to make it easy
3583 * to override things by placing things in /etc/systemd/system */
3584 r = load_from_path(u, u->id);
3588 /* Try to find an alias we can load this with */
3589 if (u->load_state == UNIT_STUB) {
3590 SET_FOREACH(t, u->names, i) {
3595 r = load_from_path(u, t);
3599 if (u->load_state != UNIT_STUB)
3604 /* And now, try looking for it under the suggested (originally linked) path */
3605 if (u->load_state == UNIT_STUB && u->fragment_path) {
3607 r = load_from_path(u, u->fragment_path);
3611 if (u->load_state == UNIT_STUB) {
3612 /* Hmm, this didn't work? Then let's get rid
3613 * of the fragment path stored for us, so that
3614 * we don't point to an invalid location. */
3615 free(u->fragment_path);
3616 u->fragment_path = NULL;
3620 /* Look for a template */
3621 if (u->load_state == UNIT_STUB && u->instance) {
3622 _cleanup_free_ char *k;
3624 k = unit_name_template(u->id);
3628 r = load_from_path(u, k);
3632 if (u->load_state == UNIT_STUB) {
3633 SET_FOREACH(t, u->names, i) {
3634 _cleanup_free_ char *z = NULL;
3639 z = unit_name_template(t);
3643 r = load_from_path(u, z);
3647 if (u->load_state != UNIT_STUB)
3656 void unit_dump_config_items(FILE *f) {
3657 static const struct {
3658 const ConfigParserCallback callback;
3661 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3662 { config_parse_warn_compat, "NOTSUPPORTED" },
3664 { config_parse_int, "INTEGER" },
3665 { config_parse_unsigned, "UNSIGNED" },
3666 { config_parse_iec_size, "SIZE" },
3667 { config_parse_iec_off, "SIZE" },
3668 { config_parse_si_size, "SIZE" },
3669 { config_parse_bool, "BOOLEAN" },
3670 { config_parse_string, "STRING" },
3671 { config_parse_path, "PATH" },
3672 { config_parse_unit_path_printf, "PATH" },
3673 { config_parse_strv, "STRING [...]" },
3674 { config_parse_exec_nice, "NICE" },
3675 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3676 { config_parse_exec_io_class, "IOCLASS" },
3677 { config_parse_exec_io_priority, "IOPRIORITY" },
3678 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3679 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3680 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3681 { config_parse_mode, "MODE" },
3682 { config_parse_unit_env_file, "FILE" },
3683 { config_parse_output, "OUTPUT" },
3684 { config_parse_input, "INPUT" },
3685 { config_parse_log_facility, "FACILITY" },
3686 { config_parse_log_level, "LEVEL" },
3687 { config_parse_exec_capabilities, "CAPABILITIES" },
3688 { config_parse_exec_secure_bits, "SECUREBITS" },
3689 { config_parse_bounding_set, "BOUNDINGSET" },
3690 { config_parse_limit, "LIMIT" },
3691 { config_parse_unit_deps, "UNIT [...]" },
3692 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3693 { config_parse_service_type, "SERVICETYPE" },
3694 { config_parse_service_restart, "SERVICERESTART" },
3695 #ifdef HAVE_SYSV_COMPAT
3696 { config_parse_sysv_priority, "SYSVPRIORITY" },
3698 { config_parse_kill_mode, "KILLMODE" },
3699 { config_parse_kill_signal, "SIGNAL" },
3700 { config_parse_socket_listen, "SOCKET [...]" },
3701 { config_parse_socket_bind, "SOCKETBIND" },
3702 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3703 { config_parse_sec, "SECONDS" },
3704 { config_parse_nsec, "NANOSECONDS" },
3705 { config_parse_namespace_path_strv, "PATH [...]" },
3706 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3707 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3708 { config_parse_unit_string_printf, "STRING" },
3709 { config_parse_trigger_unit, "UNIT" },
3710 { config_parse_timer, "TIMER" },
3711 { config_parse_path_spec, "PATH" },
3712 { config_parse_notify_access, "ACCESS" },
3713 { config_parse_ip_tos, "TOS" },
3714 { config_parse_unit_condition_path, "CONDITION" },
3715 { config_parse_unit_condition_string, "CONDITION" },
3716 { config_parse_unit_condition_null, "CONDITION" },
3717 { config_parse_unit_slice, "SLICE" },
3718 { config_parse_documentation, "URL" },
3719 { config_parse_service_timeout, "SECONDS" },
3720 { config_parse_failure_action, "ACTION" },
3721 { config_parse_set_status, "STATUS" },
3722 { config_parse_service_sockets, "SOCKETS" },
3723 { config_parse_environ, "ENVIRON" },
3725 { config_parse_syscall_filter, "SYSCALLS" },
3726 { config_parse_syscall_archs, "ARCHS" },
3727 { config_parse_syscall_errno, "ERRNO" },
3728 { config_parse_address_families, "FAMILIES" },
3730 { config_parse_cpu_shares, "SHARES" },
3731 { config_parse_memory_limit, "LIMIT" },
3732 { config_parse_device_allow, "DEVICE" },
3733 { config_parse_device_policy, "POLICY" },
3734 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3735 { config_parse_blockio_weight, "WEIGHT" },
3736 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3737 { config_parse_long, "LONG" },
3738 { config_parse_socket_service, "SERVICE" },
3740 { config_parse_exec_selinux_context, "LABEL" },
3742 { config_parse_job_mode, "MODE" },
3743 { config_parse_job_mode_isolate, "BOOLEAN" },
3744 { config_parse_personality, "PERSONALITY" },
3747 const char *prev = NULL;
3752 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3753 const char *rvalue = "OTHER", *lvalue;
3757 const ConfigPerfItem *p;
3759 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3761 dot = strchr(i, '.');
3762 lvalue = dot ? dot + 1 : i;
3766 if (!prev || !strneq(prev, i, prefix_len+1)) {
3770 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3773 for (j = 0; j < ELEMENTSOF(table); j++)
3774 if (p->parse == table[j].callback) {
3775 rvalue = table[j].rvalue;
3779 fprintf(f, "%s=%s\n", lvalue, rvalue);