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 #ifdef HAVE_SYSV_COMPAT
1111 int config_parse_sysv_priority(const char *unit,
1112 const char *filename,
1114 const char *section,
1115 unsigned section_line,
1122 int *priority = data;
1130 r = safe_atoi(rvalue, &i);
1131 if (r < 0 || i < 0) {
1132 log_syntax(unit, LOG_ERR, filename, line, -r,
1133 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1137 *priority = (int) i;
1142 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1144 int config_parse_kill_signal(const char *unit,
1145 const char *filename,
1147 const char *section,
1148 unsigned section_line,
1163 r = signal_from_string_try_harder(rvalue);
1165 log_syntax(unit, LOG_ERR, filename, line, -r,
1166 "Failed to parse kill signal, ignoring: %s", rvalue);
1174 int config_parse_exec_mount_flags(const char *unit,
1175 const char *filename,
1177 const char *section,
1178 unsigned section_line,
1185 ExecContext *c = data;
1186 const char *word, *state;
1188 unsigned long flags = 0;
1195 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1196 _cleanup_free_ char *t;
1198 t = strndup(word, l);
1202 if (streq(t, "shared"))
1204 else if (streq(t, "slave"))
1206 else if (streq(word, "private"))
1209 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1210 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1214 if (!isempty(state))
1215 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1216 "Trailing garbage, ignoring.");
1218 c->mount_flags = flags;
1222 int config_parse_exec_selinux_context(
1224 const char *filename,
1226 const char *section,
1227 unsigned section_line,
1234 ExecContext *c = data;
1245 if (isempty(rvalue)) {
1246 free(c->selinux_context);
1247 c->selinux_context = NULL;
1248 c->selinux_context_ignore = false;
1252 if (rvalue[0] == '-') {
1258 r = unit_name_printf(u, rvalue, &k);
1260 log_syntax(unit, LOG_ERR, filename, line, -r,
1261 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1265 free(c->selinux_context);
1266 c->selinux_context = k;
1267 c->selinux_context_ignore = ignore;
1272 int config_parse_exec_apparmor_profile(
1274 const char *filename,
1276 const char *section,
1277 unsigned section_line,
1284 ExecContext *c = data;
1295 if (isempty(rvalue)) {
1296 free(c->apparmor_profile);
1297 c->apparmor_profile = NULL;
1298 c->apparmor_profile_ignore = false;
1302 if (rvalue[0] == '-') {
1308 r = unit_name_printf(u, rvalue, &k);
1310 log_syntax(unit, LOG_ERR, filename, line, -r,
1311 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1315 free(c->apparmor_profile);
1316 c->apparmor_profile = k;
1317 c->apparmor_profile_ignore = ignore;
1322 int config_parse_exec_smack_process_label(
1324 const char *filename,
1326 const char *section,
1327 unsigned section_line,
1334 ExecContext *c = data;
1345 if (isempty(rvalue)) {
1346 free(c->smack_process_label);
1347 c->smack_process_label = NULL;
1348 c->smack_process_label_ignore = false;
1352 if (rvalue[0] == '-') {
1358 r = unit_name_printf(u, rvalue, &k);
1360 log_syntax(unit, LOG_ERR, filename, line, -r,
1361 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1365 free(c->smack_process_label);
1366 c->smack_process_label = k;
1367 c->smack_process_label_ignore = ignore;
1372 int config_parse_timer(const char *unit,
1373 const char *filename,
1375 const char *section,
1376 unsigned section_line,
1387 CalendarSpec *c = NULL;
1394 if (isempty(rvalue)) {
1395 /* Empty assignment resets list */
1396 timer_free_values(t);
1400 b = timer_base_from_string(lvalue);
1402 log_syntax(unit, LOG_ERR, filename, line, -b,
1403 "Failed to parse timer base, ignoring: %s", lvalue);
1407 if (b == TIMER_CALENDAR) {
1408 if (calendar_spec_from_string(rvalue, &c) < 0) {
1409 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1410 "Failed to parse calendar specification, ignoring: %s",
1415 if (parse_sec(rvalue, &u) < 0) {
1416 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1417 "Failed to parse timer value, ignoring: %s",
1423 v = new0(TimerValue, 1);
1425 calendar_spec_free(c);
1431 v->calendar_spec = c;
1433 LIST_PREPEND(value, t->values, v);
1438 int config_parse_trigger_unit(
1440 const char *filename,
1442 const char *section,
1443 unsigned section_line,
1450 _cleanup_free_ char *p = NULL;
1460 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1461 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1462 "Multiple units to trigger specified, ignoring: %s", rvalue);
1466 r = unit_name_printf(u, rvalue, &p);
1468 log_syntax(unit, LOG_ERR, filename, line, -r,
1469 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1471 type = unit_name_to_type(p ?: rvalue);
1473 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1474 "Unit type not valid, ignoring: %s", rvalue);
1478 if (type == u->type) {
1479 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1480 "Trigger cannot be of same type, ignoring: %s", rvalue);
1484 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1486 log_syntax(unit, LOG_ERR, filename, line, -r,
1487 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1494 int config_parse_path_spec(const char *unit,
1495 const char *filename,
1497 const char *section,
1498 unsigned section_line,
1508 _cleanup_free_ char *k = NULL;
1516 if (isempty(rvalue)) {
1517 /* Empty assignment clears list */
1522 b = path_type_from_string(lvalue);
1524 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1525 "Failed to parse path type, ignoring: %s", lvalue);
1529 r = unit_full_printf(UNIT(p), rvalue, &k);
1535 log_syntax(unit, LOG_ERR, filename, line, -r,
1536 "Failed to resolve unit specifiers on %s. Ignoring.",
1540 if (!path_is_absolute(k)) {
1541 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1542 "Path is not absolute, ignoring: %s", k);
1546 s = new0(PathSpec, 1);
1551 s->path = path_kill_slashes(k);
1556 LIST_PREPEND(spec, p->specs, s);
1561 int config_parse_socket_service(
1563 const char *filename,
1565 const char *section,
1566 unsigned section_line,
1573 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1577 _cleanup_free_ char *p = NULL;
1584 r = unit_name_printf(UNIT(s), rvalue, &p);
1586 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1590 if (!endswith(p, ".service")) {
1591 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1595 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1597 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1601 unit_ref_set(&s->service, x);
1606 int config_parse_service_sockets(
1608 const char *filename,
1610 const char *section,
1611 unsigned section_line,
1619 const char *word, *state;
1628 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1629 _cleanup_free_ char *t = NULL, *k = NULL;
1631 t = strndup(word, l);
1635 r = unit_name_printf(UNIT(s), t, &k);
1637 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1641 if (!endswith(k, ".socket")) {
1642 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type socket, ignoring: %s", k);
1646 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1648 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1650 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1652 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1654 if (!isempty(state))
1655 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
1660 int config_parse_bus_name(
1662 const char *filename,
1664 const char *section,
1665 unsigned section_line,
1672 _cleanup_free_ char *k = NULL;
1681 r = unit_full_printf(u, rvalue, &k);
1683 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
1687 if (!service_name_is_valid(k)) {
1688 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bus name %s, ignoring.", k);
1692 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
1695 int config_parse_service_timeout(const char *unit,
1696 const char *filename,
1698 const char *section,
1699 unsigned section_line,
1706 Service *s = userdata;
1714 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1715 rvalue, data, userdata);
1719 if (streq(lvalue, "TimeoutSec")) {
1720 s->start_timeout_defined = true;
1721 s->timeout_stop_usec = s->timeout_start_usec;
1722 } else if (streq(lvalue, "TimeoutStartSec"))
1723 s->start_timeout_defined = true;
1728 int config_parse_busname_service(
1730 const char *filename,
1732 const char *section,
1733 unsigned section_line,
1740 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1744 _cleanup_free_ char *p = NULL;
1751 r = unit_name_printf(UNIT(n), rvalue, &p);
1753 log_syntax(unit, LOG_ERR, filename, line, -r,
1754 "Failed to resolve specifiers, ignoring: %s", rvalue);
1758 if (!endswith(p, ".service")) {
1759 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1760 "Unit must be of type service, ignoring: %s", rvalue);
1764 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1766 log_syntax(unit, LOG_ERR, filename, line, -r,
1767 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1771 unit_ref_set(&n->service, x);
1776 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1778 int config_parse_bus_policy(
1780 const char *filename,
1782 const char *section,
1783 unsigned section_line,
1790 _cleanup_free_ BusNamePolicy *p = NULL;
1791 _cleanup_free_ char *id_str = NULL;
1792 BusName *busname = data;
1800 p = new0(BusNamePolicy, 1);
1804 if (streq(lvalue, "AllowUser"))
1805 p->type = BUSNAME_POLICY_TYPE_USER;
1806 else if (streq(lvalue, "AllowGroup"))
1807 p->type = BUSNAME_POLICY_TYPE_GROUP;
1809 assert_not_reached("Unknown lvalue");
1811 id_str = strdup(rvalue);
1815 access_str = strpbrk(id_str, WHITESPACE);
1817 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1818 "Invalid busname policy value '%s'", rvalue);
1824 access_str += strspn(access_str, WHITESPACE);
1826 p->access = bus_policy_access_from_string(access_str);
1827 if (p->access < 0) {
1828 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1829 "Invalid busname policy access type '%s'", access_str);
1836 LIST_PREPEND(policy, busname->policy, p);
1842 int config_parse_bus_endpoint_policy(
1844 const char *filename,
1846 const char *section,
1847 unsigned section_line,
1854 _cleanup_free_ char *name = NULL;
1855 BusPolicyAccess access;
1856 ExecContext *c = data;
1865 name = strdup(rvalue);
1869 access_str = strpbrk(name, WHITESPACE);
1871 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1872 "Invalid endpoint policy value '%s'", rvalue);
1878 access_str += strspn(access_str, WHITESPACE);
1880 access = bus_policy_access_from_string(access_str);
1881 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1882 access >= _BUS_POLICY_ACCESS_MAX) {
1883 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1884 "Invalid endpoint policy access type '%s'", access_str);
1888 if (!c->bus_endpoint) {
1889 r = bus_endpoint_new(&c->bus_endpoint);
1895 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1898 int config_parse_unit_env_file(const char *unit,
1899 const char *filename,
1901 const char *section,
1902 unsigned section_line,
1911 _cleanup_free_ char *n = NULL;
1920 if (isempty(rvalue)) {
1921 /* Empty assignment frees the list */
1927 r = unit_full_printf(u, rvalue, &n);
1929 log_syntax(unit, LOG_ERR, filename, line, -r,
1930 "Failed to resolve specifiers, ignoring: %s", rvalue);
1933 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1934 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1935 "Path '%s' is not absolute, ignoring.", s);
1939 r = strv_extend(env, s);
1946 int config_parse_environ(const char *unit,
1947 const char *filename,
1949 const char *section,
1950 unsigned section_line,
1959 const char *word, *state;
1961 _cleanup_free_ char *k = NULL;
1969 if (isempty(rvalue)) {
1970 /* Empty assignment resets the list */
1977 r = unit_full_printf(u, rvalue, &k);
1979 log_syntax(unit, LOG_ERR, filename, line, -r,
1980 "Failed to resolve specifiers, ignoring: %s", rvalue);
1988 FOREACH_WORD_QUOTED(word, l, k, state) {
1989 _cleanup_free_ char *n;
1992 n = cunescape_length(word, l);
1996 if (!env_assignment_is_valid(n)) {
1997 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1998 "Invalid environment assignment, ignoring: %s", rvalue);
2002 x = strv_env_set(*env, n);
2009 if (!isempty(state))
2010 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2011 "Trailing garbage, ignoring.");
2016 int config_parse_ip_tos(const char *unit,
2017 const char *filename,
2019 const char *section,
2020 unsigned section_line,
2027 int *ip_tos = data, x;
2034 x = ip_tos_from_string(rvalue);
2036 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2037 "Failed to parse IP TOS value, ignoring: %s", rvalue);
2045 int config_parse_unit_condition_path(
2047 const char *filename,
2049 const char *section,
2050 unsigned section_line,
2057 _cleanup_free_ char *p = NULL;
2058 Condition **list = data, *c;
2059 ConditionType t = ltype;
2060 bool trigger, negate;
2069 if (isempty(rvalue)) {
2070 /* Empty assignment resets the list */
2071 *list = condition_free_list(*list);
2075 trigger = rvalue[0] == '|';
2079 negate = rvalue[0] == '!';
2083 r = unit_full_printf(u, rvalue, &p);
2085 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2089 if (!path_is_absolute(p)) {
2090 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2094 c = condition_new(t, p, trigger, negate);
2098 LIST_PREPEND(conditions, *list, c);
2102 int config_parse_unit_condition_string(
2104 const char *filename,
2106 const char *section,
2107 unsigned section_line,
2114 _cleanup_free_ char *s = NULL;
2115 Condition **list = data, *c;
2116 ConditionType t = ltype;
2117 bool trigger, negate;
2126 if (isempty(rvalue)) {
2127 /* Empty assignment resets the list */
2128 *list = condition_free_list(*list);
2132 trigger = rvalue[0] == '|';
2136 negate = rvalue[0] == '!';
2140 r = unit_full_printf(u, rvalue, &s);
2142 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2146 c = condition_new(t, s, trigger, negate);
2150 LIST_PREPEND(conditions, *list, c);
2154 int config_parse_unit_condition_null(
2156 const char *filename,
2158 const char *section,
2159 unsigned section_line,
2166 Condition **list = data, *c;
2167 bool trigger, negate;
2175 if (isempty(rvalue)) {
2176 /* Empty assignment resets the list */
2177 *list = condition_free_list(*list);
2181 trigger = rvalue[0] == '|';
2185 negate = rvalue[0] == '!';
2189 b = parse_boolean(rvalue);
2191 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2198 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2202 LIST_PREPEND(conditions, *list, c);
2206 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2207 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2209 int config_parse_unit_requires_mounts_for(
2211 const char *filename,
2213 const char *section,
2214 unsigned section_line,
2222 const char *word, *state;
2230 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2232 _cleanup_free_ char *n;
2234 n = strndup(word, l);
2238 if (!utf8_is_valid(n)) {
2239 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2243 r = unit_require_mounts_for(u, n);
2245 log_syntax(unit, LOG_ERR, filename, line, -r,
2246 "Failed to add required mount for, ignoring: %s", rvalue);
2250 if (!isempty(state))
2251 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2252 "Trailing garbage, ignoring.");
2257 int config_parse_documentation(const char *unit,
2258 const char *filename,
2260 const char *section,
2261 unsigned section_line,
2277 if (isempty(rvalue)) {
2278 /* Empty assignment resets the list */
2279 strv_free(u->documentation);
2280 u->documentation = NULL;
2284 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2285 rvalue, data, userdata);
2289 for (a = b = u->documentation; a && *a; a++) {
2291 if (documentation_url_is_valid(*a))
2294 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2295 "Invalid URL, ignoring: %s", *a);
2306 int config_parse_syscall_filter(
2308 const char *filename,
2310 const char *section,
2311 unsigned section_line,
2318 static const char default_syscalls[] =
2325 ExecContext *c = data;
2327 bool invert = false;
2328 const char *word, *state;
2337 if (isempty(rvalue)) {
2338 /* Empty assignment resets the list */
2339 set_free(c->syscall_filter);
2340 c->syscall_filter = NULL;
2341 c->syscall_whitelist = false;
2345 if (rvalue[0] == '~') {
2350 if (!c->syscall_filter) {
2351 c->syscall_filter = set_new(NULL);
2352 if (!c->syscall_filter)
2356 /* Allow everything but the ones listed */
2357 c->syscall_whitelist = false;
2361 /* Allow nothing but the ones listed */
2362 c->syscall_whitelist = true;
2364 /* Accept default syscalls if we are on a whitelist */
2365 NULSTR_FOREACH(i, default_syscalls) {
2368 id = seccomp_syscall_resolve_name(i);
2372 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2381 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2382 _cleanup_free_ char *t = NULL;
2385 t = strndup(word, l);
2389 id = seccomp_syscall_resolve_name(t);
2391 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2392 "Failed to parse system call, ignoring: %s", t);
2396 /* If we previously wanted to forbid a syscall and now
2397 * we want to allow it, then remove it from the list
2399 if (!invert == c->syscall_whitelist) {
2400 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2406 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2408 if (!isempty(state))
2409 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2410 "Trailing garbage, ignoring.");
2412 /* Turn on NNP, but only if it wasn't configured explicitly
2413 * before, and only if we are in user mode. */
2414 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2415 c->no_new_privileges = true;
2420 int config_parse_syscall_archs(
2422 const char *filename,
2424 const char *section,
2425 unsigned section_line,
2433 const char *word, *state;
2437 if (isempty(rvalue)) {
2443 r = set_ensure_allocated(archs, NULL);
2447 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2448 _cleanup_free_ char *t = NULL;
2451 t = strndup(word, l);
2455 r = seccomp_arch_from_string(t, &a);
2457 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2458 "Failed to parse system call architecture, ignoring: %s", t);
2462 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2468 if (!isempty(state))
2469 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2470 "Trailing garbage, ignoring.");
2475 int config_parse_syscall_errno(
2477 const char *filename,
2479 const char *section,
2480 unsigned section_line,
2487 ExecContext *c = data;
2494 if (isempty(rvalue)) {
2495 /* Empty assignment resets to KILL */
2496 c->syscall_errno = 0;
2500 e = errno_from_name(rvalue);
2502 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2503 "Failed to parse error number, ignoring: %s", rvalue);
2507 c->syscall_errno = e;
2511 int config_parse_address_families(
2513 const char *filename,
2515 const char *section,
2516 unsigned section_line,
2523 ExecContext *c = data;
2524 bool invert = false;
2525 const char *word, *state;
2533 if (isempty(rvalue)) {
2534 /* Empty assignment resets the list */
2535 set_free(c->address_families);
2536 c->address_families = NULL;
2537 c->address_families_whitelist = false;
2541 if (rvalue[0] == '~') {
2546 if (!c->address_families) {
2547 c->address_families = set_new(NULL);
2548 if (!c->address_families)
2551 c->address_families_whitelist = !invert;
2554 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2555 _cleanup_free_ char *t = NULL;
2558 t = strndup(word, l);
2562 af = af_from_name(t);
2564 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2565 "Failed to parse address family, ignoring: %s", t);
2569 /* If we previously wanted to forbid an address family and now
2570 * we want to allow it, then remove it from the list
2572 if (!invert == c->address_families_whitelist) {
2573 r = set_put(c->address_families, INT_TO_PTR(af));
2579 set_remove(c->address_families, INT_TO_PTR(af));
2581 if (!isempty(state))
2582 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2583 "Trailing garbage, ignoring.");
2589 int config_parse_unit_slice(
2591 const char *filename,
2593 const char *section,
2594 unsigned section_line,
2601 _cleanup_free_ char *k = NULL;
2602 Unit *u = userdata, *slice;
2610 r = unit_name_printf(u, rvalue, &k);
2612 log_syntax(unit, LOG_ERR, filename, line, -r,
2613 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2620 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2622 log_syntax(unit, LOG_ERR, filename, line, -r,
2623 "Failed to load slice unit %s. Ignoring.", k);
2627 if (slice->type != UNIT_SLICE) {
2628 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2629 "Slice unit %s is not a slice. Ignoring.", k);
2633 unit_ref_set(&u->slice, slice);
2637 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2639 int config_parse_cpu_shares(
2641 const char *filename,
2643 const char *section,
2644 unsigned section_line,
2651 unsigned long *shares = data, lu;
2658 if (isempty(rvalue)) {
2659 *shares = (unsigned long) -1;
2663 r = safe_atolu(rvalue, &lu);
2664 if (r < 0 || lu <= 0) {
2665 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2666 "CPU shares '%s' invalid. Ignoring.", rvalue);
2674 int config_parse_cpu_quota(
2676 const char *filename,
2678 const char *section,
2679 unsigned section_line,
2686 CGroupContext *c = data;
2693 if (isempty(rvalue)) {
2694 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2698 if (!endswith(rvalue, "%")) {
2700 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2701 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2705 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2706 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2707 "CPU quota '%s' invalid. Ignoring.", rvalue);
2711 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2716 int config_parse_memory_limit(
2718 const char *filename,
2720 const char *section,
2721 unsigned section_line,
2728 CGroupContext *c = data;
2732 if (isempty(rvalue)) {
2733 c->memory_limit = (uint64_t) -1;
2737 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2739 r = parse_size(rvalue, 1024, &bytes);
2741 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2742 "Memory limit '%s' invalid. Ignoring.", rvalue);
2746 c->memory_limit = (uint64_t) bytes;
2750 int config_parse_device_allow(
2752 const char *filename,
2754 const char *section,
2755 unsigned section_line,
2762 _cleanup_free_ char *path = NULL;
2763 CGroupContext *c = data;
2764 CGroupDeviceAllow *a;
2768 if (isempty(rvalue)) {
2769 while (c->device_allow)
2770 cgroup_context_free_device_allow(c, c->device_allow);
2775 n = strcspn(rvalue, WHITESPACE);
2776 path = strndup(rvalue, n);
2780 if (!startswith(path, "/dev/") &&
2781 !startswith(path, "block-") &&
2782 !startswith(path, "char-")) {
2783 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2784 "Invalid device node path '%s'. Ignoring.", path);
2788 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2792 if (!in_charset(m, "rwm")) {
2793 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2794 "Invalid device rights '%s'. Ignoring.", m);
2798 a = new0(CGroupDeviceAllow, 1);
2804 a->r = !!strchr(m, 'r');
2805 a->w = !!strchr(m, 'w');
2806 a->m = !!strchr(m, 'm');
2808 LIST_PREPEND(device_allow, c->device_allow, a);
2812 int config_parse_blockio_weight(
2814 const char *filename,
2816 const char *section,
2817 unsigned section_line,
2824 unsigned long *weight = data, lu;
2831 if (isempty(rvalue)) {
2832 *weight = (unsigned long) -1;
2836 r = safe_atolu(rvalue, &lu);
2837 if (r < 0 || lu < 10 || lu > 1000) {
2838 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2839 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2847 int config_parse_blockio_device_weight(
2849 const char *filename,
2851 const char *section,
2852 unsigned section_line,
2859 _cleanup_free_ char *path = NULL;
2860 CGroupBlockIODeviceWeight *w;
2861 CGroupContext *c = data;
2871 if (isempty(rvalue)) {
2872 while (c->blockio_device_weights)
2873 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2878 n = strcspn(rvalue, WHITESPACE);
2879 weight = rvalue + n;
2881 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2882 "Expected block device and device weight. Ignoring.");
2886 path = strndup(rvalue, n);
2890 if (!path_startswith(path, "/dev")) {
2891 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2892 "Invalid device node path '%s'. Ignoring.", path);
2896 weight += strspn(weight, WHITESPACE);
2897 r = safe_atolu(weight, &lu);
2898 if (r < 0 || lu < 10 || lu > 1000) {
2899 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2900 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2904 w = new0(CGroupBlockIODeviceWeight, 1);
2913 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2917 int config_parse_blockio_bandwidth(
2919 const char *filename,
2921 const char *section,
2922 unsigned section_line,
2929 _cleanup_free_ char *path = NULL;
2930 CGroupBlockIODeviceBandwidth *b;
2931 CGroupContext *c = data;
2932 const char *bandwidth;
2942 read = streq("BlockIOReadBandwidth", lvalue);
2944 if (isempty(rvalue)) {
2945 CGroupBlockIODeviceBandwidth *next;
2947 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2948 if (b->read == read)
2949 cgroup_context_free_blockio_device_bandwidth(c, b);
2954 n = strcspn(rvalue, WHITESPACE);
2955 bandwidth = rvalue + n;
2956 bandwidth += strspn(bandwidth, WHITESPACE);
2959 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2960 "Expected space separated pair of device node and bandwidth. Ignoring.");
2964 path = strndup(rvalue, n);
2968 if (!path_startswith(path, "/dev")) {
2969 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2970 "Invalid device node path '%s'. Ignoring.", path);
2974 r = parse_size(bandwidth, 1000, &bytes);
2975 if (r < 0 || bytes <= 0) {
2976 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2977 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2981 b = new0(CGroupBlockIODeviceBandwidth, 1);
2987 b->bandwidth = (uint64_t) bytes;
2990 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2995 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2997 int config_parse_job_mode_isolate(
2999 const char *filename,
3001 const char *section,
3002 unsigned section_line,
3016 r = parse_boolean(rvalue);
3018 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3019 "Failed to parse boolean, ignoring: %s", rvalue);
3023 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3027 int config_parse_personality(
3029 const char *filename,
3031 const char *section,
3032 unsigned section_line,
3039 unsigned long *personality = data, p;
3044 assert(personality);
3046 p = personality_from_string(rvalue);
3047 if (p == 0xffffffffUL) {
3048 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3049 "Failed to parse personality, ignoring: %s", rvalue);
3057 int config_parse_runtime_directory(
3059 const char *filename,
3061 const char *section,
3062 unsigned section_line,
3070 const char *word, *state;
3079 if (isempty(rvalue)) {
3080 /* Empty assignment resets the list */
3086 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3087 _cleanup_free_ char *n;
3089 n = strndup(word, l);
3093 if (!filename_is_valid(n)) {
3094 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3095 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3099 r = strv_push(rt, n);
3105 if (!isempty(state))
3106 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3107 "Trailing garbage, ignoring.");
3112 int config_parse_set_status(
3114 const char *filename,
3116 const char *section,
3117 unsigned section_line,
3125 const char *word, *state;
3127 ExitStatusSet *status_set = data;
3134 /* Empty assignment resets the list */
3135 if (isempty(rvalue)) {
3136 exit_status_set_free(status_set);
3140 FOREACH_WORD(word, l, rvalue, state) {
3141 _cleanup_free_ char *temp;
3145 temp = strndup(word, l);
3149 r = safe_atoi(temp, &val);
3151 val = signal_from_string_try_harder(temp);
3154 log_syntax(unit, LOG_ERR, filename, line, -val,
3155 "Failed to parse value, ignoring: %s", word);
3158 set = &status_set->signal;
3160 if (val < 0 || val > 255) {
3161 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3162 "Value %d is outside range 0-255, ignoring", val);
3165 set = &status_set->status;
3168 r = set_ensure_allocated(set, NULL);
3172 r = set_put(*set, INT_TO_PTR(val));
3174 log_syntax(unit, LOG_ERR, filename, line, -r,
3175 "Unable to store: %s", word);
3179 if (!isempty(state))
3180 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3181 "Trailing garbage, ignoring.");
3186 int config_parse_namespace_path_strv(
3188 const char *filename,
3190 const char *section,
3191 unsigned section_line,
3199 const char *word, *state;
3208 if (isempty(rvalue)) {
3209 /* Empty assignment resets the list */
3215 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3216 _cleanup_free_ char *n;
3219 n = strndup(word, l);
3223 if (!utf8_is_valid(n)) {
3224 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3228 offset = n[0] == '-';
3229 if (!path_is_absolute(n + offset)) {
3230 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3231 "Not an absolute path, ignoring: %s", rvalue);
3235 path_kill_slashes(n);
3237 r = strv_push(sv, n);
3243 if (!isempty(state))
3244 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3245 "Trailing garbage, ignoring.");
3250 int config_parse_no_new_privileges(
3252 const char *filename,
3254 const char *section,
3255 unsigned section_line,
3262 ExecContext *c = data;
3270 k = parse_boolean(rvalue);
3272 log_syntax(unit, LOG_ERR, filename, line, -k,
3273 "Failed to parse boolean value, ignoring: %s", rvalue);
3277 c->no_new_privileges = !!k;
3278 c->no_new_privileges_set = true;
3283 int config_parse_protect_home(
3285 const char *filename,
3287 const char *section,
3288 unsigned section_line,
3295 ExecContext *c = data;
3303 /* Our enum shall be a superset of booleans, hence first try
3304 * to parse as as boolean, and then as enum */
3306 k = parse_boolean(rvalue);
3308 c->protect_home = PROTECT_HOME_YES;
3310 c->protect_home = PROTECT_HOME_NO;
3314 h = protect_home_from_string(rvalue);
3316 log_syntax(unit, LOG_ERR, filename, line, -h,
3317 "Failed to parse protect home value, ignoring: %s", rvalue);
3321 c->protect_home = h;
3327 int config_parse_protect_system(
3329 const char *filename,
3331 const char *section,
3332 unsigned section_line,
3339 ExecContext *c = data;
3347 /* Our enum shall be a superset of booleans, hence first try
3348 * to parse as as boolean, and then as enum */
3350 k = parse_boolean(rvalue);
3352 c->protect_system = PROTECT_SYSTEM_YES;
3354 c->protect_system = PROTECT_SYSTEM_NO;
3358 s = protect_system_from_string(rvalue);
3360 log_syntax(unit, LOG_ERR, filename, line, -s,
3361 "Failed to parse protect system value, ignoring: %s", rvalue);
3365 c->protect_system = s;
3371 #define FOLLOW_MAX 8
3373 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3384 /* This will update the filename pointer if the loaded file is
3385 * reached by a symlink. The old string will be freed. */
3388 char *target, *name;
3390 if (c++ >= FOLLOW_MAX)
3393 path_kill_slashes(*filename);
3395 /* Add the file name we are currently looking at to
3396 * the names of this unit, but only if it is a valid
3398 name = basename(*filename);
3400 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3402 id = set_get(names, name);
3408 r = set_consume(names, id);
3414 /* Try to open the file name, but don't if its a symlink */
3415 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3422 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3423 r = readlink_and_make_absolute(*filename, &target);
3431 f = fdopen(fd, "re");
3442 static int merge_by_names(Unit **u, Set *names, const char *id) {
3450 /* Let's try to add in all symlink names we found */
3451 while ((k = set_steal_first(names))) {
3453 /* First try to merge in the other name into our
3455 r = unit_merge_by_name(*u, k);
3459 /* Hmm, we couldn't merge the other unit into
3460 * ours? Then let's try it the other way
3463 other = manager_get_unit((*u)->manager, k);
3467 r = unit_merge(other, *u);
3470 return merge_by_names(u, names, NULL);
3478 unit_choose_id(*u, id);
3486 static int load_from_path(Unit *u, const char *path) {
3488 _cleanup_set_free_free_ Set *symlink_names = NULL;
3489 _cleanup_fclose_ FILE *f = NULL;
3490 _cleanup_free_ char *filename = NULL;
3498 symlink_names = set_new(&string_hash_ops);
3502 if (path_is_absolute(path)) {
3504 filename = strdup(path);
3508 r = open_follow(&filename, &f, symlink_names, &id);
3520 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3522 /* Instead of opening the path right away, we manually
3523 * follow all symlinks and add their name to our unit
3524 * name set while doing so */
3525 filename = path_make_absolute(path, *p);
3529 if (u->manager->unit_path_cache &&
3530 !set_get(u->manager->unit_path_cache, filename))
3533 r = open_follow(&filename, &f, symlink_names, &id);
3542 /* Empty the symlink names for the next run */
3543 set_clear_free(symlink_names);
3552 /* Hmm, no suitable file found? */
3556 r = merge_by_names(&merged, symlink_names, id);
3561 u->load_state = UNIT_MERGED;
3565 if (fstat(fileno(f), &st) < 0)
3568 if (null_or_empty(&st))
3569 u->load_state = UNIT_MASKED;
3571 u->load_state = UNIT_LOADED;
3573 /* Now, parse the file contents */
3574 r = config_parse(u->id, filename, f,
3575 UNIT_VTABLE(u)->sections,
3576 config_item_perf_lookup, load_fragment_gperf_lookup,
3577 false, true, false, u);
3582 free(u->fragment_path);
3583 u->fragment_path = filename;
3586 u->fragment_mtime = timespec_load(&st.st_mtim);
3588 if (u->source_path) {
3589 if (stat(u->source_path, &st) >= 0)
3590 u->source_mtime = timespec_load(&st.st_mtim);
3592 u->source_mtime = 0;
3598 int unit_load_fragment(Unit *u) {
3604 assert(u->load_state == UNIT_STUB);
3607 /* First, try to find the unit under its id. We always look
3608 * for unit files in the default directories, to make it easy
3609 * to override things by placing things in /etc/systemd/system */
3610 r = load_from_path(u, u->id);
3614 /* Try to find an alias we can load this with */
3615 if (u->load_state == UNIT_STUB) {
3616 SET_FOREACH(t, u->names, i) {
3621 r = load_from_path(u, t);
3625 if (u->load_state != UNIT_STUB)
3630 /* And now, try looking for it under the suggested (originally linked) path */
3631 if (u->load_state == UNIT_STUB && u->fragment_path) {
3633 r = load_from_path(u, u->fragment_path);
3637 if (u->load_state == UNIT_STUB) {
3638 /* Hmm, this didn't work? Then let's get rid
3639 * of the fragment path stored for us, so that
3640 * we don't point to an invalid location. */
3641 free(u->fragment_path);
3642 u->fragment_path = NULL;
3646 /* Look for a template */
3647 if (u->load_state == UNIT_STUB && u->instance) {
3648 _cleanup_free_ char *k;
3650 k = unit_name_template(u->id);
3654 r = load_from_path(u, k);
3658 if (u->load_state == UNIT_STUB) {
3659 SET_FOREACH(t, u->names, i) {
3660 _cleanup_free_ char *z = NULL;
3665 z = unit_name_template(t);
3669 r = load_from_path(u, z);
3673 if (u->load_state != UNIT_STUB)
3682 void unit_dump_config_items(FILE *f) {
3683 static const struct {
3684 const ConfigParserCallback callback;
3687 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3688 { config_parse_warn_compat, "NOTSUPPORTED" },
3690 { config_parse_int, "INTEGER" },
3691 { config_parse_unsigned, "UNSIGNED" },
3692 { config_parse_iec_size, "SIZE" },
3693 { config_parse_iec_off, "SIZE" },
3694 { config_parse_si_size, "SIZE" },
3695 { config_parse_bool, "BOOLEAN" },
3696 { config_parse_string, "STRING" },
3697 { config_parse_path, "PATH" },
3698 { config_parse_unit_path_printf, "PATH" },
3699 { config_parse_strv, "STRING [...]" },
3700 { config_parse_exec_nice, "NICE" },
3701 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3702 { config_parse_exec_io_class, "IOCLASS" },
3703 { config_parse_exec_io_priority, "IOPRIORITY" },
3704 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3705 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3706 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3707 { config_parse_mode, "MODE" },
3708 { config_parse_unit_env_file, "FILE" },
3709 { config_parse_output, "OUTPUT" },
3710 { config_parse_input, "INPUT" },
3711 { config_parse_log_facility, "FACILITY" },
3712 { config_parse_log_level, "LEVEL" },
3713 { config_parse_exec_capabilities, "CAPABILITIES" },
3714 { config_parse_exec_secure_bits, "SECUREBITS" },
3715 { config_parse_bounding_set, "BOUNDINGSET" },
3716 { config_parse_limit, "LIMIT" },
3717 { config_parse_unit_deps, "UNIT [...]" },
3718 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3719 { config_parse_service_type, "SERVICETYPE" },
3720 { config_parse_service_restart, "SERVICERESTART" },
3721 #ifdef HAVE_SYSV_COMPAT
3722 { config_parse_sysv_priority, "SYSVPRIORITY" },
3724 { config_parse_kill_mode, "KILLMODE" },
3725 { config_parse_kill_signal, "SIGNAL" },
3726 { config_parse_socket_listen, "SOCKET [...]" },
3727 { config_parse_socket_bind, "SOCKETBIND" },
3728 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3729 { config_parse_sec, "SECONDS" },
3730 { config_parse_nsec, "NANOSECONDS" },
3731 { config_parse_namespace_path_strv, "PATH [...]" },
3732 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3733 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3734 { config_parse_unit_string_printf, "STRING" },
3735 { config_parse_trigger_unit, "UNIT" },
3736 { config_parse_timer, "TIMER" },
3737 { config_parse_path_spec, "PATH" },
3738 { config_parse_notify_access, "ACCESS" },
3739 { config_parse_ip_tos, "TOS" },
3740 { config_parse_unit_condition_path, "CONDITION" },
3741 { config_parse_unit_condition_string, "CONDITION" },
3742 { config_parse_unit_condition_null, "CONDITION" },
3743 { config_parse_unit_slice, "SLICE" },
3744 { config_parse_documentation, "URL" },
3745 { config_parse_service_timeout, "SECONDS" },
3746 { config_parse_failure_action, "ACTION" },
3747 { config_parse_set_status, "STATUS" },
3748 { config_parse_service_sockets, "SOCKETS" },
3749 { config_parse_environ, "ENVIRON" },
3751 { config_parse_syscall_filter, "SYSCALLS" },
3752 { config_parse_syscall_archs, "ARCHS" },
3753 { config_parse_syscall_errno, "ERRNO" },
3754 { config_parse_address_families, "FAMILIES" },
3756 { config_parse_cpu_shares, "SHARES" },
3757 { config_parse_memory_limit, "LIMIT" },
3758 { config_parse_device_allow, "DEVICE" },
3759 { config_parse_device_policy, "POLICY" },
3760 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3761 { config_parse_blockio_weight, "WEIGHT" },
3762 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3763 { config_parse_long, "LONG" },
3764 { config_parse_socket_service, "SERVICE" },
3766 { config_parse_exec_selinux_context, "LABEL" },
3768 { config_parse_job_mode, "MODE" },
3769 { config_parse_job_mode_isolate, "BOOLEAN" },
3770 { config_parse_personality, "PERSONALITY" },
3773 const char *prev = NULL;
3778 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3779 const char *rvalue = "OTHER", *lvalue;
3783 const ConfigPerfItem *p;
3785 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3787 dot = strchr(i, '.');
3788 lvalue = dot ? dot + 1 : i;
3792 if (!prev || !strneq(prev, i, prefix_len+1)) {
3796 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3799 for (j = 0; j < ELEMENTSOF(table); j++)
3800 if (p->parse == table[j].callback) {
3801 rvalue = table[j].rvalue;
3805 fprintf(f, "%s=%s\n", lvalue, rvalue);