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/resource.h>
38 #include "conf-parser.h"
39 #include "load-fragment.h"
42 #include "securebits.h"
44 #include "unit-name.h"
45 #include "unit-printf.h"
47 #include "path-util.h"
51 #include "bus-error.h"
52 #include "errno-list.h"
55 #include "bus-internal.h"
58 #include "seccomp-util.h"
61 int config_parse_warn_compat(
66 unsigned section_line,
72 Disabled reason = ltype;
75 case DISABLED_CONFIGURATION:
76 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
77 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
80 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
81 "Support for option %s= has been removed and it is ignored", lvalue);
83 case DISABLED_EXPERIMENTAL:
84 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
85 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
92 int config_parse_unit_deps(const char *unit,
96 unsigned section_line,
103 UnitDependency d = ltype;
105 const char *word, *state;
112 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
113 _cleanup_free_ char *t = NULL, *k = NULL;
116 t = strndup(word, l);
120 r = unit_name_printf(u, t, &k);
122 log_syntax(unit, LOG_ERR, filename, line, -r,
123 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
127 r = unit_add_dependency_by_name(u, d, k, NULL, true);
129 log_syntax(unit, LOG_ERR, filename, line, -r,
130 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
133 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
138 int config_parse_unit_string_printf(
140 const char *filename,
143 unsigned section_line,
150 _cleanup_free_ char *k = NULL;
159 r = unit_full_printf(u, rvalue, &k);
161 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
165 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
168 int config_parse_unit_strv_printf(const char *unit,
169 const char *filename,
172 unsigned section_line,
180 _cleanup_free_ char *k = NULL;
188 r = unit_full_printf(u, rvalue, &k);
190 log_syntax(unit, LOG_ERR, filename, line, -r,
191 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
193 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
194 k ? k : rvalue, data, userdata);
197 int config_parse_unit_path_printf(const char *unit,
198 const char *filename,
201 unsigned section_line,
208 _cleanup_free_ char *k = NULL;
217 r = unit_full_printf(u, rvalue, &k);
219 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
223 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
226 int config_parse_unit_path_strv_printf(
228 const char *filename,
231 unsigned section_line,
239 const char *word, *state;
249 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
250 _cleanup_free_ char *k = NULL;
256 r = unit_full_printf(u, t, &k);
258 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
262 if (!utf8_is_valid(k)) {
263 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
267 if (!path_is_absolute(k)) {
268 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
272 path_kill_slashes(k);
281 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
286 int config_parse_socket_listen(const char *unit,
287 const char *filename,
290 unsigned section_line,
297 _cleanup_free_ SocketPort *p = NULL;
309 if (isempty(rvalue)) {
310 /* An empty assignment removes all ports */
311 socket_free_ports(s);
315 p = new0(SocketPort, 1);
319 if (ltype != SOCKET_SOCKET) {
322 r = unit_full_printf(UNIT(s), rvalue, &p->path);
324 p->path = strdup(rvalue);
328 log_syntax(unit, LOG_ERR, filename, line, -r,
329 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
332 path_kill_slashes(p->path);
334 } else if (streq(lvalue, "ListenNetlink")) {
335 _cleanup_free_ char *k = NULL;
337 p->type = SOCKET_SOCKET;
338 r = unit_full_printf(UNIT(s), rvalue, &k);
340 log_syntax(unit, LOG_ERR, filename, line, -r,
341 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
343 r = socket_address_parse_netlink(&p->address, k ?: rvalue);
345 log_syntax(unit, LOG_ERR, filename, line, -r,
346 "Failed to parse address value, ignoring: %s", rvalue);
351 _cleanup_free_ char *k = NULL;
353 p->type = SOCKET_SOCKET;
354 r = unit_full_printf(UNIT(s), rvalue, &k);
356 log_syntax(unit, LOG_ERR, filename, line, -r,
357 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
359 r = socket_address_parse(&p->address, k ? k : rvalue);
361 log_syntax(unit, LOG_ERR, filename, line, -r,
362 "Failed to parse address value, ignoring: %s", rvalue);
366 if (streq(lvalue, "ListenStream"))
367 p->address.type = SOCK_STREAM;
368 else if (streq(lvalue, "ListenDatagram"))
369 p->address.type = SOCK_DGRAM;
371 assert(streq(lvalue, "ListenSequentialPacket"));
372 p->address.type = SOCK_SEQPACKET;
375 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
376 log_syntax(unit, LOG_ERR, filename, line, EOPNOTSUPP,
377 "Address family not supported, ignoring: %s", rvalue);
386 LIST_FIND_TAIL(port, s->ports, tail);
387 LIST_INSERT_AFTER(port, s->ports, tail, p);
389 LIST_PREPEND(port, s->ports, p);
395 int config_parse_socket_bind(const char *unit,
396 const char *filename,
399 unsigned section_line,
407 SocketAddressBindIPv6Only b;
416 b = socket_address_bind_ipv6_only_from_string(rvalue);
420 r = parse_boolean(rvalue);
422 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
423 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
427 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
429 s->bind_ipv6_only = b;
434 int config_parse_exec_nice(const char *unit,
435 const char *filename,
438 unsigned section_line,
445 ExecContext *c = data;
453 r = safe_atoi(rvalue, &priority);
455 log_syntax(unit, LOG_ERR, filename, line, -r,
456 "Failed to parse nice priority, ignoring: %s. ", rvalue);
460 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
461 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
462 "Nice priority out of range, ignoring: %s", rvalue);
472 int config_parse_exec_oom_score_adjust(const char* unit,
473 const char *filename,
476 unsigned section_line,
483 ExecContext *c = data;
491 r = safe_atoi(rvalue, &oa);
493 log_syntax(unit, LOG_ERR, filename, line, -r,
494 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
498 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
499 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
500 "OOM score adjust value out of range, ignoring: %s", rvalue);
504 c->oom_score_adjust = oa;
505 c->oom_score_adjust_set = true;
510 int config_parse_exec(const char *unit,
511 const char *filename,
514 unsigned section_line,
521 ExecCommand **e = data, *nce;
533 if (isempty(rvalue)) {
534 /* An empty assignment resets the list */
535 *e = exec_command_free_list(*e);
539 /* We accept an absolute path as first argument, or
540 * alternatively an absolute prefixed with @ to allow
541 * overriding of argv[0]. */
544 const char *word, *state, *reason;
546 bool separate_argv0 = false, ignore = false;
552 rvalue += strspn(rvalue, WHITESPACE);
558 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
560 for (i = 0; i < 2; i++) {
561 if (*word == '-' && !ignore) {
566 if (*word == '@' && !separate_argv0) {
567 separate_argv0 = true;
572 if (strneq(word, ";", MAX(l, 1U)))
577 if (!isempty(state)) {
578 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
579 "Trailing garbage, ignoring.");
584 /* If separate_argv0, we'll move first element to path variable */
585 n = new(char*, MAX(k + !separate_argv0, 1u));
590 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
594 if (separate_argv0 ? path == NULL : k == 0) {
595 /* first word, very special */
596 skip = separate_argv0 + ignore;
598 /* skip special chars in the beginning */
601 } else if (strneq(word, ";", MAX(l, 1U)))
602 /* new commandline */
606 skip = strneq(word, "\\;", MAX(l, 1U));
608 c = cunescape_length(word + skip, l - skip);
614 if (!utf8_is_valid(c)) {
615 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
620 /* where to stuff this? */
621 if (separate_argv0 && path == NULL)
630 reason = "Empty executable name or zeroeth argument";
631 else if (!string_is_safe(path ?: n[0]))
632 reason = "Executable path contains special characters";
633 else if (!path_is_absolute(path ?: n[0]))
634 reason = "Executable path is not absolute";
635 else if (endswith(path ?: n[0], "/"))
636 reason = "Executable path specifies a directory";
640 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
641 "%s, ignoring: %s", reason, rvalue);
654 nce = new0(ExecCommand, 1);
662 nce->ignore = ignore;
664 path_kill_slashes(nce->path);
666 exec_command_append_list(e, nce);
682 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
683 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
685 int config_parse_socket_bindtodevice(const char* unit,
686 const char *filename,
689 unsigned section_line,
704 if (rvalue[0] && !streq(rvalue, "*")) {
711 free(s->bind_to_device);
712 s->bind_to_device = n;
717 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
718 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
720 int config_parse_exec_io_class(const char *unit,
721 const char *filename,
724 unsigned section_line,
731 ExecContext *c = data;
739 x = ioprio_class_from_string(rvalue);
741 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
742 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
746 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
747 c->ioprio_set = true;
752 int config_parse_exec_io_priority(const char *unit,
753 const char *filename,
756 unsigned section_line,
763 ExecContext *c = data;
771 r = safe_atoi(rvalue, &i);
772 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
773 log_syntax(unit, LOG_ERR, filename, line, -r,
774 "Failed to parse IO priority, ignoring: %s", rvalue);
778 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
779 c->ioprio_set = true;
784 int config_parse_exec_cpu_sched_policy(const char *unit,
785 const char *filename,
788 unsigned section_line,
796 ExecContext *c = data;
804 x = sched_policy_from_string(rvalue);
806 log_syntax(unit, LOG_ERR, filename, line, -x,
807 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
811 c->cpu_sched_policy = x;
812 /* Moving to or from real-time policy? We need to adjust the priority */
813 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
814 c->cpu_sched_set = true;
819 int config_parse_exec_cpu_sched_prio(const char *unit,
820 const char *filename,
823 unsigned section_line,
830 ExecContext *c = data;
838 r = safe_atoi(rvalue, &i);
840 log_syntax(unit, LOG_ERR, filename, line, -r,
841 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
845 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
846 min = sched_get_priority_min(c->cpu_sched_policy);
847 max = sched_get_priority_max(c->cpu_sched_policy);
849 if (i < min || i > max) {
850 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
851 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
855 c->cpu_sched_priority = i;
856 c->cpu_sched_set = true;
861 int config_parse_exec_cpu_affinity(const char *unit,
862 const char *filename,
865 unsigned section_line,
872 ExecContext *c = data;
873 const char *word, *state;
881 if (isempty(rvalue)) {
882 /* An empty assignment resets the CPU list */
889 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
890 _cleanup_free_ char *t = NULL;
894 t = strndup(word, l);
898 r = safe_atou(t, &cpu);
901 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
906 if (r < 0 || cpu >= c->cpuset_ncpus) {
907 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
908 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
912 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
915 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
916 "Trailing garbage, ignoring.");
921 int config_parse_exec_capabilities(const char *unit,
922 const char *filename,
925 unsigned section_line,
932 ExecContext *c = data;
940 cap = cap_from_text(rvalue);
942 log_syntax(unit, LOG_ERR, filename, line, errno,
943 "Failed to parse capabilities, ignoring: %s", rvalue);
948 cap_free(c->capabilities);
949 c->capabilities = cap;
954 int config_parse_exec_secure_bits(const char *unit,
955 const char *filename,
958 unsigned section_line,
965 ExecContext *c = data;
967 const char *word, *state;
974 if (isempty(rvalue)) {
975 /* An empty assignment resets the field */
980 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
981 if (first_word(word, "keep-caps"))
982 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
983 else if (first_word(word, "keep-caps-locked"))
984 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
985 else if (first_word(word, "no-setuid-fixup"))
986 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
987 else if (first_word(word, "no-setuid-fixup-locked"))
988 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
989 else if (first_word(word, "noroot"))
990 c->secure_bits |= 1<<SECURE_NOROOT;
991 else if (first_word(word, "noroot-locked"))
992 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
994 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
995 "Failed to parse secure bits, ignoring: %s", rvalue);
1000 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1001 "Invalid syntax, garbage at the end, ignoring.");
1006 int config_parse_bounding_set(const char *unit,
1007 const char *filename,
1009 const char *section,
1010 unsigned section_line,
1017 uint64_t *capability_bounding_set_drop = data;
1018 const char *word, *state;
1020 bool invert = false;
1028 if (rvalue[0] == '~') {
1033 /* Note that we store this inverted internally, since the
1034 * kernel wants it like this. But we actually expose it
1035 * non-inverted everywhere to have a fully normalized
1038 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1039 _cleanup_free_ char *t = NULL;
1042 t = strndup(word, l);
1046 cap = capability_from_name(t);
1048 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
1052 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1054 if (!isempty(state))
1055 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1056 "Trailing garbage, ignoring.");
1059 *capability_bounding_set_drop |= sum;
1061 *capability_bounding_set_drop |= ~sum;
1066 int config_parse_limit(const char *unit,
1067 const char *filename,
1069 const char *section,
1070 unsigned section_line,
1077 struct rlimit **rl = data;
1078 unsigned long long u;
1087 if (streq(rvalue, "infinity"))
1088 u = (unsigned long long) RLIM_INFINITY;
1092 r = safe_atollu(rvalue, &u);
1094 log_syntax(unit, LOG_ERR, filename, line, -r,
1095 "Failed to parse resource value, ignoring: %s", rvalue);
1101 *rl = new(struct rlimit, 1);
1106 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1110 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1112 int config_parse_kill_signal(const char *unit,
1113 const char *filename,
1115 const char *section,
1116 unsigned section_line,
1131 r = signal_from_string_try_harder(rvalue);
1133 log_syntax(unit, LOG_ERR, filename, line, -r,
1134 "Failed to parse kill signal, ignoring: %s", rvalue);
1142 int config_parse_exec_mount_flags(const char *unit,
1143 const char *filename,
1145 const char *section,
1146 unsigned section_line,
1153 ExecContext *c = data;
1154 const char *word, *state;
1156 unsigned long flags = 0;
1163 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1164 _cleanup_free_ char *t;
1166 t = strndup(word, l);
1170 if (streq(t, "shared"))
1172 else if (streq(t, "slave"))
1174 else if (streq(word, "private"))
1177 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1178 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1182 if (!isempty(state))
1183 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1184 "Trailing garbage, ignoring.");
1186 c->mount_flags = flags;
1190 int config_parse_exec_selinux_context(
1192 const char *filename,
1194 const char *section,
1195 unsigned section_line,
1202 ExecContext *c = data;
1213 if (isempty(rvalue)) {
1214 free(c->selinux_context);
1215 c->selinux_context = NULL;
1216 c->selinux_context_ignore = false;
1220 if (rvalue[0] == '-') {
1226 r = unit_name_printf(u, rvalue, &k);
1228 log_syntax(unit, LOG_ERR, filename, line, -r,
1229 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1233 free(c->selinux_context);
1234 c->selinux_context = k;
1235 c->selinux_context_ignore = ignore;
1240 int config_parse_exec_apparmor_profile(
1242 const char *filename,
1244 const char *section,
1245 unsigned section_line,
1252 ExecContext *c = data;
1263 if (isempty(rvalue)) {
1264 free(c->apparmor_profile);
1265 c->apparmor_profile = NULL;
1266 c->apparmor_profile_ignore = false;
1270 if (rvalue[0] == '-') {
1276 r = unit_name_printf(u, rvalue, &k);
1278 log_syntax(unit, LOG_ERR, filename, line, -r,
1279 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1283 free(c->apparmor_profile);
1284 c->apparmor_profile = k;
1285 c->apparmor_profile_ignore = ignore;
1290 int config_parse_exec_smack_process_label(
1292 const char *filename,
1294 const char *section,
1295 unsigned section_line,
1302 ExecContext *c = data;
1313 if (isempty(rvalue)) {
1314 free(c->smack_process_label);
1315 c->smack_process_label = NULL;
1316 c->smack_process_label_ignore = false;
1320 if (rvalue[0] == '-') {
1326 r = unit_name_printf(u, rvalue, &k);
1328 log_syntax(unit, LOG_ERR, filename, line, -r,
1329 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1333 free(c->smack_process_label);
1334 c->smack_process_label = k;
1335 c->smack_process_label_ignore = ignore;
1340 int config_parse_timer(const char *unit,
1341 const char *filename,
1343 const char *section,
1344 unsigned section_line,
1355 CalendarSpec *c = NULL;
1362 if (isempty(rvalue)) {
1363 /* Empty assignment resets list */
1364 timer_free_values(t);
1368 b = timer_base_from_string(lvalue);
1370 log_syntax(unit, LOG_ERR, filename, line, -b,
1371 "Failed to parse timer base, ignoring: %s", lvalue);
1375 if (b == TIMER_CALENDAR) {
1376 if (calendar_spec_from_string(rvalue, &c) < 0) {
1377 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1378 "Failed to parse calendar specification, ignoring: %s",
1383 if (parse_sec(rvalue, &u) < 0) {
1384 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1385 "Failed to parse timer value, ignoring: %s",
1391 v = new0(TimerValue, 1);
1393 calendar_spec_free(c);
1399 v->calendar_spec = c;
1401 LIST_PREPEND(value, t->values, v);
1406 int config_parse_trigger_unit(
1408 const char *filename,
1410 const char *section,
1411 unsigned section_line,
1418 _cleanup_free_ char *p = NULL;
1428 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1429 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1430 "Multiple units to trigger specified, ignoring: %s", rvalue);
1434 r = unit_name_printf(u, rvalue, &p);
1436 log_syntax(unit, LOG_ERR, filename, line, -r,
1437 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1439 type = unit_name_to_type(p ?: rvalue);
1441 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1442 "Unit type not valid, ignoring: %s", rvalue);
1446 if (type == u->type) {
1447 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1448 "Trigger cannot be of same type, ignoring: %s", rvalue);
1452 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1454 log_syntax(unit, LOG_ERR, filename, line, -r,
1455 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1462 int config_parse_path_spec(const char *unit,
1463 const char *filename,
1465 const char *section,
1466 unsigned section_line,
1476 _cleanup_free_ char *k = NULL;
1484 if (isempty(rvalue)) {
1485 /* Empty assignment clears list */
1490 b = path_type_from_string(lvalue);
1492 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1493 "Failed to parse path type, ignoring: %s", lvalue);
1497 r = unit_full_printf(UNIT(p), rvalue, &k);
1503 log_syntax(unit, LOG_ERR, filename, line, -r,
1504 "Failed to resolve unit specifiers on %s. Ignoring.",
1508 if (!path_is_absolute(k)) {
1509 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1510 "Path is not absolute, ignoring: %s", k);
1514 s = new0(PathSpec, 1);
1519 s->path = path_kill_slashes(k);
1524 LIST_PREPEND(spec, p->specs, s);
1529 int config_parse_socket_service(
1531 const char *filename,
1533 const char *section,
1534 unsigned section_line,
1541 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1545 _cleanup_free_ char *p = NULL;
1552 r = unit_name_printf(UNIT(s), rvalue, &p);
1554 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1558 if (!endswith(p, ".service")) {
1559 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1563 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1565 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1569 unit_ref_set(&s->service, x);
1574 int config_parse_service_sockets(
1576 const char *filename,
1578 const char *section,
1579 unsigned section_line,
1587 const char *word, *state;
1596 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1597 _cleanup_free_ char *t = NULL, *k = NULL;
1599 t = strndup(word, l);
1603 r = unit_name_printf(UNIT(s), t, &k);
1605 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1609 if (!endswith(k, ".socket")) {
1610 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type socket, ignoring: %s", k);
1614 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1616 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1618 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1620 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1622 if (!isempty(state))
1623 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
1628 int config_parse_bus_name(
1630 const char *filename,
1632 const char *section,
1633 unsigned section_line,
1640 _cleanup_free_ char *k = NULL;
1649 r = unit_full_printf(u, rvalue, &k);
1651 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
1655 if (!service_name_is_valid(k)) {
1656 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bus name %s, ignoring.", k);
1660 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
1663 int config_parse_service_timeout(const char *unit,
1664 const char *filename,
1666 const char *section,
1667 unsigned section_line,
1674 Service *s = userdata;
1682 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1683 rvalue, data, userdata);
1687 if (streq(lvalue, "TimeoutSec")) {
1688 s->start_timeout_defined = true;
1689 s->timeout_stop_usec = s->timeout_start_usec;
1690 } else if (streq(lvalue, "TimeoutStartSec"))
1691 s->start_timeout_defined = true;
1696 int config_parse_busname_service(
1698 const char *filename,
1700 const char *section,
1701 unsigned section_line,
1708 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1712 _cleanup_free_ char *p = NULL;
1719 r = unit_name_printf(UNIT(n), rvalue, &p);
1721 log_syntax(unit, LOG_ERR, filename, line, -r,
1722 "Failed to resolve specifiers, ignoring: %s", rvalue);
1726 if (!endswith(p, ".service")) {
1727 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1728 "Unit must be of type service, ignoring: %s", rvalue);
1732 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1734 log_syntax(unit, LOG_ERR, filename, line, -r,
1735 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1739 unit_ref_set(&n->service, x);
1744 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1746 int config_parse_bus_policy(
1748 const char *filename,
1750 const char *section,
1751 unsigned section_line,
1758 _cleanup_free_ BusNamePolicy *p = NULL;
1759 _cleanup_free_ char *id_str = NULL;
1760 BusName *busname = data;
1768 p = new0(BusNamePolicy, 1);
1772 if (streq(lvalue, "AllowUser"))
1773 p->type = BUSNAME_POLICY_TYPE_USER;
1774 else if (streq(lvalue, "AllowGroup"))
1775 p->type = BUSNAME_POLICY_TYPE_GROUP;
1777 assert_not_reached("Unknown lvalue");
1779 id_str = strdup(rvalue);
1783 access_str = strpbrk(id_str, WHITESPACE);
1785 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1786 "Invalid busname policy value '%s'", rvalue);
1792 access_str += strspn(access_str, WHITESPACE);
1794 p->access = bus_policy_access_from_string(access_str);
1795 if (p->access < 0) {
1796 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1797 "Invalid busname policy access type '%s'", access_str);
1804 LIST_PREPEND(policy, busname->policy, p);
1810 int config_parse_bus_endpoint_policy(
1812 const char *filename,
1814 const char *section,
1815 unsigned section_line,
1822 _cleanup_free_ char *name = NULL;
1823 BusPolicyAccess access;
1824 ExecContext *c = data;
1833 name = strdup(rvalue);
1837 access_str = strpbrk(name, WHITESPACE);
1839 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1840 "Invalid endpoint policy value '%s'", rvalue);
1846 access_str += strspn(access_str, WHITESPACE);
1848 access = bus_policy_access_from_string(access_str);
1849 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1850 access >= _BUS_POLICY_ACCESS_MAX) {
1851 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1852 "Invalid endpoint policy access type '%s'", access_str);
1856 if (!c->bus_endpoint) {
1857 r = bus_endpoint_new(&c->bus_endpoint);
1863 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1866 int config_parse_unit_env_file(const char *unit,
1867 const char *filename,
1869 const char *section,
1870 unsigned section_line,
1879 _cleanup_free_ char *n = NULL;
1888 if (isempty(rvalue)) {
1889 /* Empty assignment frees the list */
1895 r = unit_full_printf(u, rvalue, &n);
1897 log_syntax(unit, LOG_ERR, filename, line, -r,
1898 "Failed to resolve specifiers, ignoring: %s", rvalue);
1901 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1902 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1903 "Path '%s' is not absolute, ignoring.", s);
1907 r = strv_extend(env, s);
1914 int config_parse_environ(const char *unit,
1915 const char *filename,
1917 const char *section,
1918 unsigned section_line,
1927 const char *word, *state;
1929 _cleanup_free_ char *k = NULL;
1937 if (isempty(rvalue)) {
1938 /* Empty assignment resets the list */
1945 r = unit_full_printf(u, rvalue, &k);
1947 log_syntax(unit, LOG_ERR, filename, line, -r,
1948 "Failed to resolve specifiers, ignoring: %s", rvalue);
1956 FOREACH_WORD_QUOTED(word, l, k, state) {
1957 _cleanup_free_ char *n;
1960 n = cunescape_length(word, l);
1964 if (!env_assignment_is_valid(n)) {
1965 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1966 "Invalid environment assignment, ignoring: %s", rvalue);
1970 x = strv_env_set(*env, n);
1977 if (!isempty(state))
1978 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1979 "Trailing garbage, ignoring.");
1984 int config_parse_ip_tos(const char *unit,
1985 const char *filename,
1987 const char *section,
1988 unsigned section_line,
1995 int *ip_tos = data, x;
2002 x = ip_tos_from_string(rvalue);
2004 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2005 "Failed to parse IP TOS value, ignoring: %s", rvalue);
2013 int config_parse_unit_condition_path(
2015 const char *filename,
2017 const char *section,
2018 unsigned section_line,
2025 _cleanup_free_ char *p = NULL;
2026 Condition **list = data, *c;
2027 ConditionType t = ltype;
2028 bool trigger, negate;
2037 if (isempty(rvalue)) {
2038 /* Empty assignment resets the list */
2039 *list = condition_free_list(*list);
2043 trigger = rvalue[0] == '|';
2047 negate = rvalue[0] == '!';
2051 r = unit_full_printf(u, rvalue, &p);
2053 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2057 if (!path_is_absolute(p)) {
2058 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2062 c = condition_new(t, p, trigger, negate);
2066 LIST_PREPEND(conditions, *list, c);
2070 int config_parse_unit_condition_string(
2072 const char *filename,
2074 const char *section,
2075 unsigned section_line,
2082 _cleanup_free_ char *s = NULL;
2083 Condition **list = data, *c;
2084 ConditionType t = ltype;
2085 bool trigger, negate;
2094 if (isempty(rvalue)) {
2095 /* Empty assignment resets the list */
2096 *list = condition_free_list(*list);
2100 trigger = rvalue[0] == '|';
2104 negate = rvalue[0] == '!';
2108 r = unit_full_printf(u, rvalue, &s);
2110 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2114 c = condition_new(t, s, trigger, negate);
2118 LIST_PREPEND(conditions, *list, c);
2122 int config_parse_unit_condition_null(
2124 const char *filename,
2126 const char *section,
2127 unsigned section_line,
2134 Condition **list = data, *c;
2135 bool trigger, negate;
2143 if (isempty(rvalue)) {
2144 /* Empty assignment resets the list */
2145 *list = condition_free_list(*list);
2149 trigger = rvalue[0] == '|';
2153 negate = rvalue[0] == '!';
2157 b = parse_boolean(rvalue);
2159 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2166 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2170 LIST_PREPEND(conditions, *list, c);
2174 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2175 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2177 int config_parse_unit_requires_mounts_for(
2179 const char *filename,
2181 const char *section,
2182 unsigned section_line,
2190 const char *word, *state;
2198 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2200 _cleanup_free_ char *n;
2202 n = strndup(word, l);
2206 if (!utf8_is_valid(n)) {
2207 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2211 r = unit_require_mounts_for(u, n);
2213 log_syntax(unit, LOG_ERR, filename, line, -r,
2214 "Failed to add required mount for, ignoring: %s", rvalue);
2218 if (!isempty(state))
2219 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2220 "Trailing garbage, ignoring.");
2225 int config_parse_documentation(const char *unit,
2226 const char *filename,
2228 const char *section,
2229 unsigned section_line,
2245 if (isempty(rvalue)) {
2246 /* Empty assignment resets the list */
2247 strv_free(u->documentation);
2248 u->documentation = NULL;
2252 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2253 rvalue, data, userdata);
2257 for (a = b = u->documentation; a && *a; a++) {
2259 if (documentation_url_is_valid(*a))
2262 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2263 "Invalid URL, ignoring: %s", *a);
2274 int config_parse_syscall_filter(
2276 const char *filename,
2278 const char *section,
2279 unsigned section_line,
2286 static const char default_syscalls[] =
2293 ExecContext *c = data;
2295 bool invert = false;
2296 const char *word, *state;
2305 if (isempty(rvalue)) {
2306 /* Empty assignment resets the list */
2307 set_free(c->syscall_filter);
2308 c->syscall_filter = NULL;
2309 c->syscall_whitelist = false;
2313 if (rvalue[0] == '~') {
2318 if (!c->syscall_filter) {
2319 c->syscall_filter = set_new(NULL);
2320 if (!c->syscall_filter)
2324 /* Allow everything but the ones listed */
2325 c->syscall_whitelist = false;
2329 /* Allow nothing but the ones listed */
2330 c->syscall_whitelist = true;
2332 /* Accept default syscalls if we are on a whitelist */
2333 NULSTR_FOREACH(i, default_syscalls) {
2336 id = seccomp_syscall_resolve_name(i);
2340 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2349 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2350 _cleanup_free_ char *t = NULL;
2353 t = strndup(word, l);
2357 id = seccomp_syscall_resolve_name(t);
2359 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2360 "Failed to parse system call, ignoring: %s", t);
2364 /* If we previously wanted to forbid a syscall and now
2365 * we want to allow it, then remove it from the list
2367 if (!invert == c->syscall_whitelist) {
2368 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2374 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2376 if (!isempty(state))
2377 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2378 "Trailing garbage, ignoring.");
2380 /* Turn on NNP, but only if it wasn't configured explicitly
2381 * before, and only if we are in user mode. */
2382 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2383 c->no_new_privileges = true;
2388 int config_parse_syscall_archs(
2390 const char *filename,
2392 const char *section,
2393 unsigned section_line,
2401 const char *word, *state;
2405 if (isempty(rvalue)) {
2411 r = set_ensure_allocated(archs, NULL);
2415 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2416 _cleanup_free_ char *t = NULL;
2419 t = strndup(word, l);
2423 r = seccomp_arch_from_string(t, &a);
2425 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2426 "Failed to parse system call architecture, ignoring: %s", t);
2430 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2436 if (!isempty(state))
2437 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2438 "Trailing garbage, ignoring.");
2443 int config_parse_syscall_errno(
2445 const char *filename,
2447 const char *section,
2448 unsigned section_line,
2455 ExecContext *c = data;
2462 if (isempty(rvalue)) {
2463 /* Empty assignment resets to KILL */
2464 c->syscall_errno = 0;
2468 e = errno_from_name(rvalue);
2470 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2471 "Failed to parse error number, ignoring: %s", rvalue);
2475 c->syscall_errno = e;
2479 int config_parse_address_families(
2481 const char *filename,
2483 const char *section,
2484 unsigned section_line,
2491 ExecContext *c = data;
2492 bool invert = false;
2493 const char *word, *state;
2501 if (isempty(rvalue)) {
2502 /* Empty assignment resets the list */
2503 set_free(c->address_families);
2504 c->address_families = NULL;
2505 c->address_families_whitelist = false;
2509 if (rvalue[0] == '~') {
2514 if (!c->address_families) {
2515 c->address_families = set_new(NULL);
2516 if (!c->address_families)
2519 c->address_families_whitelist = !invert;
2522 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2523 _cleanup_free_ char *t = NULL;
2526 t = strndup(word, l);
2530 af = af_from_name(t);
2532 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2533 "Failed to parse address family, ignoring: %s", t);
2537 /* If we previously wanted to forbid an address family and now
2538 * we want to allow it, then remove it from the list
2540 if (!invert == c->address_families_whitelist) {
2541 r = set_put(c->address_families, INT_TO_PTR(af));
2547 set_remove(c->address_families, INT_TO_PTR(af));
2549 if (!isempty(state))
2550 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2551 "Trailing garbage, ignoring.");
2557 int config_parse_unit_slice(
2559 const char *filename,
2561 const char *section,
2562 unsigned section_line,
2569 _cleanup_free_ char *k = NULL;
2570 Unit *u = userdata, *slice;
2578 r = unit_name_printf(u, rvalue, &k);
2580 log_syntax(unit, LOG_ERR, filename, line, -r,
2581 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2588 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2590 log_syntax(unit, LOG_ERR, filename, line, -r,
2591 "Failed to load slice unit %s. Ignoring.", k);
2595 if (slice->type != UNIT_SLICE) {
2596 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2597 "Slice unit %s is not a slice. Ignoring.", k);
2601 unit_ref_set(&u->slice, slice);
2605 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2607 int config_parse_cpu_shares(
2609 const char *filename,
2611 const char *section,
2612 unsigned section_line,
2619 unsigned long *shares = data, lu;
2626 if (isempty(rvalue)) {
2627 *shares = (unsigned long) -1;
2631 r = safe_atolu(rvalue, &lu);
2632 if (r < 0 || lu <= 0) {
2633 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2634 "CPU shares '%s' invalid. Ignoring.", rvalue);
2642 int config_parse_cpu_quota(
2644 const char *filename,
2646 const char *section,
2647 unsigned section_line,
2654 CGroupContext *c = data;
2661 if (isempty(rvalue)) {
2662 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2666 if (!endswith(rvalue, "%")) {
2668 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2669 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2673 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2674 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2675 "CPU quota '%s' invalid. Ignoring.", rvalue);
2679 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2684 int config_parse_memory_limit(
2686 const char *filename,
2688 const char *section,
2689 unsigned section_line,
2696 CGroupContext *c = data;
2700 if (isempty(rvalue)) {
2701 c->memory_limit = (uint64_t) -1;
2705 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2707 r = parse_size(rvalue, 1024, &bytes);
2709 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2710 "Memory limit '%s' invalid. Ignoring.", rvalue);
2714 c->memory_limit = (uint64_t) bytes;
2718 int config_parse_device_allow(
2720 const char *filename,
2722 const char *section,
2723 unsigned section_line,
2730 _cleanup_free_ char *path = NULL;
2731 CGroupContext *c = data;
2732 CGroupDeviceAllow *a;
2736 if (isempty(rvalue)) {
2737 while (c->device_allow)
2738 cgroup_context_free_device_allow(c, c->device_allow);
2743 n = strcspn(rvalue, WHITESPACE);
2744 path = strndup(rvalue, n);
2748 if (!startswith(path, "/dev/") &&
2749 !startswith(path, "block-") &&
2750 !startswith(path, "char-")) {
2751 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2752 "Invalid device node path '%s'. Ignoring.", path);
2756 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2760 if (!in_charset(m, "rwm")) {
2761 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2762 "Invalid device rights '%s'. Ignoring.", m);
2766 a = new0(CGroupDeviceAllow, 1);
2772 a->r = !!strchr(m, 'r');
2773 a->w = !!strchr(m, 'w');
2774 a->m = !!strchr(m, 'm');
2776 LIST_PREPEND(device_allow, c->device_allow, a);
2780 int config_parse_blockio_weight(
2782 const char *filename,
2784 const char *section,
2785 unsigned section_line,
2792 unsigned long *weight = data, lu;
2799 if (isempty(rvalue)) {
2800 *weight = (unsigned long) -1;
2804 r = safe_atolu(rvalue, &lu);
2805 if (r < 0 || lu < 10 || lu > 1000) {
2806 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2807 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2815 int config_parse_blockio_device_weight(
2817 const char *filename,
2819 const char *section,
2820 unsigned section_line,
2827 _cleanup_free_ char *path = NULL;
2828 CGroupBlockIODeviceWeight *w;
2829 CGroupContext *c = data;
2839 if (isempty(rvalue)) {
2840 while (c->blockio_device_weights)
2841 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2846 n = strcspn(rvalue, WHITESPACE);
2847 weight = rvalue + n;
2849 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2850 "Expected block device and device weight. Ignoring.");
2854 path = strndup(rvalue, n);
2858 if (!path_startswith(path, "/dev")) {
2859 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2860 "Invalid device node path '%s'. Ignoring.", path);
2864 weight += strspn(weight, WHITESPACE);
2865 r = safe_atolu(weight, &lu);
2866 if (r < 0 || lu < 10 || lu > 1000) {
2867 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2868 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2872 w = new0(CGroupBlockIODeviceWeight, 1);
2881 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2885 int config_parse_blockio_bandwidth(
2887 const char *filename,
2889 const char *section,
2890 unsigned section_line,
2897 _cleanup_free_ char *path = NULL;
2898 CGroupBlockIODeviceBandwidth *b;
2899 CGroupContext *c = data;
2900 const char *bandwidth;
2910 read = streq("BlockIOReadBandwidth", lvalue);
2912 if (isempty(rvalue)) {
2913 CGroupBlockIODeviceBandwidth *next;
2915 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2916 if (b->read == read)
2917 cgroup_context_free_blockio_device_bandwidth(c, b);
2922 n = strcspn(rvalue, WHITESPACE);
2923 bandwidth = rvalue + n;
2924 bandwidth += strspn(bandwidth, WHITESPACE);
2927 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2928 "Expected space separated pair of device node and bandwidth. Ignoring.");
2932 path = strndup(rvalue, n);
2936 if (!path_startswith(path, "/dev")) {
2937 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2938 "Invalid device node path '%s'. Ignoring.", path);
2942 r = parse_size(bandwidth, 1000, &bytes);
2943 if (r < 0 || bytes <= 0) {
2944 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2945 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2949 b = new0(CGroupBlockIODeviceBandwidth, 1);
2955 b->bandwidth = (uint64_t) bytes;
2958 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2963 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2965 int config_parse_job_mode_isolate(
2967 const char *filename,
2969 const char *section,
2970 unsigned section_line,
2984 r = parse_boolean(rvalue);
2986 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2987 "Failed to parse boolean, ignoring: %s", rvalue);
2991 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2995 int config_parse_personality(
2997 const char *filename,
2999 const char *section,
3000 unsigned section_line,
3007 unsigned long *personality = data, p;
3012 assert(personality);
3014 p = personality_from_string(rvalue);
3015 if (p == 0xffffffffUL) {
3016 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3017 "Failed to parse personality, ignoring: %s", rvalue);
3025 int config_parse_runtime_directory(
3027 const char *filename,
3029 const char *section,
3030 unsigned section_line,
3038 const char *word, *state;
3047 if (isempty(rvalue)) {
3048 /* Empty assignment resets the list */
3054 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3055 _cleanup_free_ char *n;
3057 n = strndup(word, l);
3061 if (!filename_is_valid(n)) {
3062 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3063 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3067 r = strv_push(rt, n);
3073 if (!isempty(state))
3074 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3075 "Trailing garbage, ignoring.");
3080 int config_parse_set_status(
3082 const char *filename,
3084 const char *section,
3085 unsigned section_line,
3093 const char *word, *state;
3095 ExitStatusSet *status_set = data;
3102 /* Empty assignment resets the list */
3103 if (isempty(rvalue)) {
3104 exit_status_set_free(status_set);
3108 FOREACH_WORD(word, l, rvalue, state) {
3109 _cleanup_free_ char *temp;
3113 temp = strndup(word, l);
3117 r = safe_atoi(temp, &val);
3119 val = signal_from_string_try_harder(temp);
3122 log_syntax(unit, LOG_ERR, filename, line, -val,
3123 "Failed to parse value, ignoring: %s", word);
3126 set = &status_set->signal;
3128 if (val < 0 || val > 255) {
3129 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3130 "Value %d is outside range 0-255, ignoring", val);
3133 set = &status_set->status;
3136 r = set_ensure_allocated(set, NULL);
3140 r = set_put(*set, INT_TO_PTR(val));
3142 log_syntax(unit, LOG_ERR, filename, line, -r,
3143 "Unable to store: %s", word);
3147 if (!isempty(state))
3148 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3149 "Trailing garbage, ignoring.");
3154 int config_parse_namespace_path_strv(
3156 const char *filename,
3158 const char *section,
3159 unsigned section_line,
3167 const char *word, *state;
3176 if (isempty(rvalue)) {
3177 /* Empty assignment resets the list */
3183 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3184 _cleanup_free_ char *n;
3187 n = strndup(word, l);
3191 if (!utf8_is_valid(n)) {
3192 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3196 offset = n[0] == '-';
3197 if (!path_is_absolute(n + offset)) {
3198 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3199 "Not an absolute path, ignoring: %s", rvalue);
3203 path_kill_slashes(n);
3205 r = strv_push(sv, n);
3211 if (!isempty(state))
3212 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3213 "Trailing garbage, ignoring.");
3218 int config_parse_no_new_privileges(
3220 const char *filename,
3222 const char *section,
3223 unsigned section_line,
3230 ExecContext *c = data;
3238 k = parse_boolean(rvalue);
3240 log_syntax(unit, LOG_ERR, filename, line, -k,
3241 "Failed to parse boolean value, ignoring: %s", rvalue);
3245 c->no_new_privileges = !!k;
3246 c->no_new_privileges_set = true;
3251 int config_parse_protect_home(
3253 const char *filename,
3255 const char *section,
3256 unsigned section_line,
3263 ExecContext *c = data;
3271 /* Our enum shall be a superset of booleans, hence first try
3272 * to parse as as boolean, and then as enum */
3274 k = parse_boolean(rvalue);
3276 c->protect_home = PROTECT_HOME_YES;
3278 c->protect_home = PROTECT_HOME_NO;
3282 h = protect_home_from_string(rvalue);
3284 log_syntax(unit, LOG_ERR, filename, line, -h,
3285 "Failed to parse protect home value, ignoring: %s", rvalue);
3289 c->protect_home = h;
3295 int config_parse_protect_system(
3297 const char *filename,
3299 const char *section,
3300 unsigned section_line,
3307 ExecContext *c = data;
3315 /* Our enum shall be a superset of booleans, hence first try
3316 * to parse as as boolean, and then as enum */
3318 k = parse_boolean(rvalue);
3320 c->protect_system = PROTECT_SYSTEM_YES;
3322 c->protect_system = PROTECT_SYSTEM_NO;
3326 s = protect_system_from_string(rvalue);
3328 log_syntax(unit, LOG_ERR, filename, line, -s,
3329 "Failed to parse protect system value, ignoring: %s", rvalue);
3333 c->protect_system = s;
3339 #define FOLLOW_MAX 8
3341 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3352 /* This will update the filename pointer if the loaded file is
3353 * reached by a symlink. The old string will be freed. */
3356 char *target, *name;
3358 if (c++ >= FOLLOW_MAX)
3361 path_kill_slashes(*filename);
3363 /* Add the file name we are currently looking at to
3364 * the names of this unit, but only if it is a valid
3366 name = basename(*filename);
3368 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3370 id = set_get(names, name);
3376 r = set_consume(names, id);
3382 /* Try to open the file name, but don't if its a symlink */
3383 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3390 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3391 r = readlink_and_make_absolute(*filename, &target);
3399 f = fdopen(fd, "re");
3410 static int merge_by_names(Unit **u, Set *names, const char *id) {
3418 /* Let's try to add in all symlink names we found */
3419 while ((k = set_steal_first(names))) {
3421 /* First try to merge in the other name into our
3423 r = unit_merge_by_name(*u, k);
3427 /* Hmm, we couldn't merge the other unit into
3428 * ours? Then let's try it the other way
3431 other = manager_get_unit((*u)->manager, k);
3435 r = unit_merge(other, *u);
3438 return merge_by_names(u, names, NULL);
3446 unit_choose_id(*u, id);
3454 static int load_from_path(Unit *u, const char *path) {
3456 _cleanup_set_free_free_ Set *symlink_names = NULL;
3457 _cleanup_fclose_ FILE *f = NULL;
3458 _cleanup_free_ char *filename = NULL;
3466 symlink_names = set_new(&string_hash_ops);
3470 if (path_is_absolute(path)) {
3472 filename = strdup(path);
3476 r = open_follow(&filename, &f, symlink_names, &id);
3488 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3490 /* Instead of opening the path right away, we manually
3491 * follow all symlinks and add their name to our unit
3492 * name set while doing so */
3493 filename = path_make_absolute(path, *p);
3497 if (u->manager->unit_path_cache &&
3498 !set_get(u->manager->unit_path_cache, filename))
3501 r = open_follow(&filename, &f, symlink_names, &id);
3510 /* Empty the symlink names for the next run */
3511 set_clear_free(symlink_names);
3520 /* Hmm, no suitable file found? */
3524 r = merge_by_names(&merged, symlink_names, id);
3529 u->load_state = UNIT_MERGED;
3533 if (fstat(fileno(f), &st) < 0)
3536 if (null_or_empty(&st))
3537 u->load_state = UNIT_MASKED;
3539 u->load_state = UNIT_LOADED;
3541 /* Now, parse the file contents */
3542 r = config_parse(u->id, filename, f,
3543 UNIT_VTABLE(u)->sections,
3544 config_item_perf_lookup, load_fragment_gperf_lookup,
3545 false, true, false, u);
3550 free(u->fragment_path);
3551 u->fragment_path = filename;
3554 u->fragment_mtime = timespec_load(&st.st_mtim);
3556 if (u->source_path) {
3557 if (stat(u->source_path, &st) >= 0)
3558 u->source_mtime = timespec_load(&st.st_mtim);
3560 u->source_mtime = 0;
3566 int unit_load_fragment(Unit *u) {
3572 assert(u->load_state == UNIT_STUB);
3575 /* First, try to find the unit under its id. We always look
3576 * for unit files in the default directories, to make it easy
3577 * to override things by placing things in /etc/systemd/system */
3578 r = load_from_path(u, u->id);
3582 /* Try to find an alias we can load this with */
3583 if (u->load_state == UNIT_STUB) {
3584 SET_FOREACH(t, u->names, i) {
3589 r = load_from_path(u, t);
3593 if (u->load_state != UNIT_STUB)
3598 /* And now, try looking for it under the suggested (originally linked) path */
3599 if (u->load_state == UNIT_STUB && u->fragment_path) {
3601 r = load_from_path(u, u->fragment_path);
3605 if (u->load_state == UNIT_STUB) {
3606 /* Hmm, this didn't work? Then let's get rid
3607 * of the fragment path stored for us, so that
3608 * we don't point to an invalid location. */
3609 free(u->fragment_path);
3610 u->fragment_path = NULL;
3614 /* Look for a template */
3615 if (u->load_state == UNIT_STUB && u->instance) {
3616 _cleanup_free_ char *k;
3618 k = unit_name_template(u->id);
3622 r = load_from_path(u, k);
3626 if (u->load_state == UNIT_STUB) {
3627 SET_FOREACH(t, u->names, i) {
3628 _cleanup_free_ char *z = NULL;
3633 z = unit_name_template(t);
3637 r = load_from_path(u, z);
3641 if (u->load_state != UNIT_STUB)
3650 void unit_dump_config_items(FILE *f) {
3651 static const struct {
3652 const ConfigParserCallback callback;
3655 { config_parse_warn_compat, "NOTSUPPORTED" },
3656 { config_parse_int, "INTEGER" },
3657 { config_parse_unsigned, "UNSIGNED" },
3658 { config_parse_iec_size, "SIZE" },
3659 { config_parse_iec_off, "SIZE" },
3660 { config_parse_si_size, "SIZE" },
3661 { config_parse_bool, "BOOLEAN" },
3662 { config_parse_string, "STRING" },
3663 { config_parse_path, "PATH" },
3664 { config_parse_unit_path_printf, "PATH" },
3665 { config_parse_strv, "STRING [...]" },
3666 { config_parse_exec_nice, "NICE" },
3667 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3668 { config_parse_exec_io_class, "IOCLASS" },
3669 { config_parse_exec_io_priority, "IOPRIORITY" },
3670 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3671 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3672 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3673 { config_parse_mode, "MODE" },
3674 { config_parse_unit_env_file, "FILE" },
3675 { config_parse_output, "OUTPUT" },
3676 { config_parse_input, "INPUT" },
3677 { config_parse_log_facility, "FACILITY" },
3678 { config_parse_log_level, "LEVEL" },
3679 { config_parse_exec_capabilities, "CAPABILITIES" },
3680 { config_parse_exec_secure_bits, "SECUREBITS" },
3681 { config_parse_bounding_set, "BOUNDINGSET" },
3682 { config_parse_limit, "LIMIT" },
3683 { config_parse_unit_deps, "UNIT [...]" },
3684 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3685 { config_parse_service_type, "SERVICETYPE" },
3686 { config_parse_service_restart, "SERVICERESTART" },
3687 { config_parse_kill_mode, "KILLMODE" },
3688 { config_parse_kill_signal, "SIGNAL" },
3689 { config_parse_socket_listen, "SOCKET [...]" },
3690 { config_parse_socket_bind, "SOCKETBIND" },
3691 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3692 { config_parse_sec, "SECONDS" },
3693 { config_parse_nsec, "NANOSECONDS" },
3694 { config_parse_namespace_path_strv, "PATH [...]" },
3695 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3696 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3697 { config_parse_unit_string_printf, "STRING" },
3698 { config_parse_trigger_unit, "UNIT" },
3699 { config_parse_timer, "TIMER" },
3700 { config_parse_path_spec, "PATH" },
3701 { config_parse_notify_access, "ACCESS" },
3702 { config_parse_ip_tos, "TOS" },
3703 { config_parse_unit_condition_path, "CONDITION" },
3704 { config_parse_unit_condition_string, "CONDITION" },
3705 { config_parse_unit_condition_null, "CONDITION" },
3706 { config_parse_unit_slice, "SLICE" },
3707 { config_parse_documentation, "URL" },
3708 { config_parse_service_timeout, "SECONDS" },
3709 { config_parse_failure_action, "ACTION" },
3710 { config_parse_set_status, "STATUS" },
3711 { config_parse_service_sockets, "SOCKETS" },
3712 { config_parse_environ, "ENVIRON" },
3714 { config_parse_syscall_filter, "SYSCALLS" },
3715 { config_parse_syscall_archs, "ARCHS" },
3716 { config_parse_syscall_errno, "ERRNO" },
3717 { config_parse_address_families, "FAMILIES" },
3719 { config_parse_cpu_shares, "SHARES" },
3720 { config_parse_memory_limit, "LIMIT" },
3721 { config_parse_device_allow, "DEVICE" },
3722 { config_parse_device_policy, "POLICY" },
3723 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3724 { config_parse_blockio_weight, "WEIGHT" },
3725 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3726 { config_parse_long, "LONG" },
3727 { config_parse_socket_service, "SERVICE" },
3729 { config_parse_exec_selinux_context, "LABEL" },
3731 { config_parse_job_mode, "MODE" },
3732 { config_parse_job_mode_isolate, "BOOLEAN" },
3733 { config_parse_personality, "PERSONALITY" },
3736 const char *prev = NULL;
3741 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3742 const char *rvalue = "OTHER", *lvalue;
3746 const ConfigPerfItem *p;
3748 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3750 dot = strchr(i, '.');
3751 lvalue = dot ? dot + 1 : i;
3755 if (!prev || !strneq(prev, i, prefix_len+1)) {
3759 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3762 for (j = 0; j < ELEMENTSOF(table); j++)
3763 if (p->parse == table[j].callback) {
3764 rvalue = table[j].rvalue;
3768 fprintf(f, "%s=%s\n", lvalue, rvalue);