1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
7 Copyright 2012 Holger Hans Peter Freyther
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <linux/oom.h>
30 #include <sys/prctl.h>
31 #include <sys/mount.h>
35 #include <sys/resource.h>
36 #include <sys/types.h>
43 #include "sd-messages.h"
46 #include "conf-parser.h"
47 #include "load-fragment.h"
50 #include "securebits.h"
52 #include "unit-name.h"
53 #include "unit-printf.h"
55 #include "path-util.h"
59 #include "bus-error.h"
60 #include "errno-list.h"
65 #include "seccomp-util.h"
68 int config_parse_warn_compat(
73 unsigned section_line,
79 Disabled reason = ltype;
82 case DISABLED_CONFIGURATION:
83 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
84 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
87 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
88 "Support for option %s= has been removed and it is ignored", lvalue);
90 case DISABLED_EXPERIMENTAL:
91 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
92 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
99 int config_parse_unit_deps(const char *unit,
100 const char *filename,
103 unsigned section_line,
110 UnitDependency d = ltype;
112 const char *word, *state;
119 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
120 _cleanup_free_ char *t = NULL, *k = NULL;
123 t = strndup(word, l);
127 r = unit_name_printf(u, t, &k);
129 log_syntax(unit, LOG_ERR, filename, line, -r,
130 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
134 r = unit_add_dependency_by_name(u, d, k, NULL, true);
136 log_syntax(unit, LOG_ERR, filename, line, -r,
137 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
140 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
145 int config_parse_unit_string_printf(const char *unit,
146 const char *filename,
149 unsigned section_line,
157 _cleanup_free_ char *k = NULL;
165 r = unit_full_printf(u, rvalue, &k);
167 log_syntax(unit, LOG_ERR, filename, line, -r,
168 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
170 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
171 k ? k : rvalue, data, userdata);
174 int config_parse_unit_strv_printf(const char *unit,
175 const char *filename,
178 unsigned section_line,
186 _cleanup_free_ char *k = NULL;
194 r = unit_full_printf(u, rvalue, &k);
196 log_syntax(unit, LOG_ERR, filename, line, -r,
197 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
199 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
200 k ? k : rvalue, data, userdata);
203 int config_parse_unit_path_printf(const char *unit,
204 const char *filename,
207 unsigned section_line,
214 _cleanup_free_ char *k = NULL;
223 r = unit_full_printf(u, rvalue, &k);
225 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
229 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
232 int config_parse_unit_path_strv_printf(
234 const char *filename,
237 unsigned section_line,
245 const char *word, *state;
255 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
256 _cleanup_free_ char *k = NULL;
262 r = unit_full_printf(u, t, &k);
264 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
268 if (!utf8_is_valid(k)) {
269 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
273 if (!path_is_absolute(k)) {
274 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
278 path_kill_slashes(k);
287 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
292 int config_parse_socket_listen(const char *unit,
293 const char *filename,
296 unsigned section_line,
303 _cleanup_free_ SocketPort *p = NULL;
315 if (isempty(rvalue)) {
316 /* An empty assignment removes all ports */
317 socket_free_ports(s);
321 p = new0(SocketPort, 1);
325 if (ltype != SOCKET_SOCKET) {
328 r = unit_full_printf(UNIT(s), rvalue, &p->path);
330 p->path = strdup(rvalue);
334 log_syntax(unit, LOG_ERR, filename, line, -r,
335 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
338 path_kill_slashes(p->path);
340 } else if (streq(lvalue, "ListenNetlink")) {
341 _cleanup_free_ char *k = NULL;
343 p->type = SOCKET_SOCKET;
344 r = unit_full_printf(UNIT(s), rvalue, &k);
346 log_syntax(unit, LOG_ERR, filename, line, -r,
347 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
349 r = socket_address_parse_netlink(&p->address, k ?: rvalue);
351 log_syntax(unit, LOG_ERR, filename, line, -r,
352 "Failed to parse address value, ignoring: %s", rvalue);
357 _cleanup_free_ char *k = NULL;
359 p->type = SOCKET_SOCKET;
360 r = unit_full_printf(UNIT(s), rvalue, &k);
362 log_syntax(unit, LOG_ERR, filename, line, -r,
363 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
365 r = socket_address_parse(&p->address, k ? k : rvalue);
367 log_syntax(unit, LOG_ERR, filename, line, -r,
368 "Failed to parse address value, ignoring: %s", rvalue);
372 if (streq(lvalue, "ListenStream"))
373 p->address.type = SOCK_STREAM;
374 else if (streq(lvalue, "ListenDatagram"))
375 p->address.type = SOCK_DGRAM;
377 assert(streq(lvalue, "ListenSequentialPacket"));
378 p->address.type = SOCK_SEQPACKET;
381 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
382 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
383 "Address family not supported, ignoring: %s", rvalue);
392 LIST_FIND_TAIL(port, s->ports, tail);
393 LIST_INSERT_AFTER(port, s->ports, tail, p);
395 LIST_PREPEND(port, s->ports, p);
401 int config_parse_socket_bind(const char *unit,
402 const char *filename,
405 unsigned section_line,
413 SocketAddressBindIPv6Only b;
422 b = socket_address_bind_ipv6_only_from_string(rvalue);
426 r = parse_boolean(rvalue);
428 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
429 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
433 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
435 s->bind_ipv6_only = b;
440 int config_parse_exec_nice(const char *unit,
441 const char *filename,
444 unsigned section_line,
451 ExecContext *c = data;
459 r = safe_atoi(rvalue, &priority);
461 log_syntax(unit, LOG_ERR, filename, line, -r,
462 "Failed to parse nice priority, ignoring: %s. ", rvalue);
466 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
467 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
468 "Nice priority out of range, ignoring: %s", rvalue);
478 int config_parse_exec_oom_score_adjust(const char* unit,
479 const char *filename,
482 unsigned section_line,
489 ExecContext *c = data;
497 r = safe_atoi(rvalue, &oa);
499 log_syntax(unit, LOG_ERR, filename, line, -r,
500 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
504 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
505 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
506 "OOM score adjust value out of range, ignoring: %s", rvalue);
510 c->oom_score_adjust = oa;
511 c->oom_score_adjust_set = true;
516 int config_parse_exec(const char *unit,
517 const char *filename,
520 unsigned section_line,
527 ExecCommand **e = data, *nce;
539 if (isempty(rvalue)) {
540 /* An empty assignment resets the list */
541 exec_command_free_list(*e);
546 /* We accept an absolute path as first argument, or
547 * alternatively an absolute prefixed with @ to allow
548 * overriding of argv[0]. */
551 const char *word, *state;
553 bool honour_argv0 = false, ignore = false;
559 rvalue += strspn(rvalue, WHITESPACE);
564 for (i = 0; i < 2; i++) {
565 if (rvalue[0] == '-' && !ignore) {
570 if (rvalue[0] == '@' && !honour_argv0) {
576 if (*rvalue != '/') {
577 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
578 "Executable path is not absolute, ignoring: %s", rvalue);
583 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
584 if (strneq(word, ";", MAX(l, 1U)))
589 if (!isempty(state)) {
590 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
591 "Trailing garbage, ignoring.");
596 n = new(char*, k + !honour_argv0);
601 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
602 if (strneq(word, ";", MAX(l, 1U)))
604 else if (strneq(word, "\\;", MAX(l, 1U)))
607 if (honour_argv0 && word == rvalue) {
610 path = strndup(word, l);
616 if (!utf8_is_valid(path)) {
617 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
625 c = n[k++] = cunescape_length(word, l);
631 if (!utf8_is_valid(c)) {
632 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
642 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
643 "Invalid command line, ignoring: %s", rvalue);
656 assert(path_is_absolute(path));
658 nce = new0(ExecCommand, 1);
666 nce->ignore = ignore;
668 path_kill_slashes(nce->path);
670 exec_command_append_list(e, nce);
686 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
687 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
689 int config_parse_socket_bindtodevice(const char* unit,
690 const char *filename,
693 unsigned section_line,
708 if (rvalue[0] && !streq(rvalue, "*")) {
715 free(s->bind_to_device);
716 s->bind_to_device = n;
721 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
722 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
724 int config_parse_exec_io_class(const char *unit,
725 const char *filename,
728 unsigned section_line,
735 ExecContext *c = data;
743 x = ioprio_class_from_string(rvalue);
745 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
746 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
750 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
751 c->ioprio_set = true;
756 int config_parse_exec_io_priority(const char *unit,
757 const char *filename,
760 unsigned section_line,
767 ExecContext *c = data;
775 r = safe_atoi(rvalue, &i);
776 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
777 log_syntax(unit, LOG_ERR, filename, line, -r,
778 "Failed to parse IO priority, ignoring: %s", rvalue);
782 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
783 c->ioprio_set = true;
788 int config_parse_exec_cpu_sched_policy(const char *unit,
789 const char *filename,
792 unsigned section_line,
800 ExecContext *c = data;
808 x = sched_policy_from_string(rvalue);
810 log_syntax(unit, LOG_ERR, filename, line, -x,
811 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
815 c->cpu_sched_policy = x;
816 /* Moving to or from real-time policy? We need to adjust the priority */
817 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
818 c->cpu_sched_set = true;
823 int config_parse_exec_cpu_sched_prio(const char *unit,
824 const char *filename,
827 unsigned section_line,
834 ExecContext *c = data;
842 r = safe_atoi(rvalue, &i);
844 log_syntax(unit, LOG_ERR, filename, line, -r,
845 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
849 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
850 min = sched_get_priority_min(c->cpu_sched_policy);
851 max = sched_get_priority_max(c->cpu_sched_policy);
853 if (i < min || i > max) {
854 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
855 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
859 c->cpu_sched_priority = i;
860 c->cpu_sched_set = true;
865 int config_parse_exec_cpu_affinity(const char *unit,
866 const char *filename,
869 unsigned section_line,
876 ExecContext *c = data;
877 const char *word, *state;
885 if (isempty(rvalue)) {
886 /* An empty assignment resets the CPU list */
893 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
894 _cleanup_free_ char *t = NULL;
898 t = strndup(word, l);
902 r = safe_atou(t, &cpu);
905 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
910 if (r < 0 || cpu >= c->cpuset_ncpus) {
911 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
912 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
916 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
919 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
920 "Trailing garbage, ignoring.");
925 int config_parse_exec_capabilities(const char *unit,
926 const char *filename,
929 unsigned section_line,
936 ExecContext *c = data;
944 cap = cap_from_text(rvalue);
946 log_syntax(unit, LOG_ERR, filename, line, errno,
947 "Failed to parse capabilities, ignoring: %s", rvalue);
952 cap_free(c->capabilities);
953 c->capabilities = cap;
958 int config_parse_exec_secure_bits(const char *unit,
959 const char *filename,
962 unsigned section_line,
969 ExecContext *c = data;
971 const char *word, *state;
978 if (isempty(rvalue)) {
979 /* An empty assignment resets the field */
984 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
985 if (first_word(word, "keep-caps"))
986 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
987 else if (first_word(word, "keep-caps-locked"))
988 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
989 else if (first_word(word, "no-setuid-fixup"))
990 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
991 else if (first_word(word, "no-setuid-fixup-locked"))
992 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
993 else if (first_word(word, "noroot"))
994 c->secure_bits |= 1<<SECURE_NOROOT;
995 else if (first_word(word, "noroot-locked"))
996 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
998 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
999 "Failed to parse secure bits, ignoring: %s", rvalue);
1003 if (!isempty(state))
1004 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1005 "Invalid syntax, garbage at the end, ignoring.");
1010 int config_parse_bounding_set(const char *unit,
1011 const char *filename,
1013 const char *section,
1014 unsigned section_line,
1021 uint64_t *capability_bounding_set_drop = data;
1022 const char *word, *state;
1024 bool invert = false;
1032 if (rvalue[0] == '~') {
1037 /* Note that we store this inverted internally, since the
1038 * kernel wants it like this. But we actually expose it
1039 * non-inverted everywhere to have a fully normalized
1042 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1043 _cleanup_free_ char *t = NULL;
1046 t = strndup(word, l);
1050 cap = capability_from_name(t);
1052 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
1056 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1058 if (!isempty(state))
1059 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1060 "Trailing garbage, ignoring.");
1063 *capability_bounding_set_drop |= sum;
1065 *capability_bounding_set_drop |= ~sum;
1070 int config_parse_limit(const char *unit,
1071 const char *filename,
1073 const char *section,
1074 unsigned section_line,
1081 struct rlimit **rl = data;
1082 unsigned long long u;
1091 if (streq(rvalue, "infinity"))
1092 u = (unsigned long long) RLIM_INFINITY;
1096 r = safe_atollu(rvalue, &u);
1098 log_syntax(unit, LOG_ERR, filename, line, -r,
1099 "Failed to parse resource value, ignoring: %s", rvalue);
1105 *rl = new(struct rlimit, 1);
1110 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1114 #ifdef HAVE_SYSV_COMPAT
1115 int config_parse_sysv_priority(const char *unit,
1116 const char *filename,
1118 const char *section,
1119 unsigned section_line,
1126 int *priority = data;
1134 r = safe_atoi(rvalue, &i);
1135 if (r < 0 || i < 0) {
1136 log_syntax(unit, LOG_ERR, filename, line, -r,
1137 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1141 *priority = (int) i;
1146 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1148 int config_parse_kill_signal(const char *unit,
1149 const char *filename,
1151 const char *section,
1152 unsigned section_line,
1167 r = signal_from_string_try_harder(rvalue);
1169 log_syntax(unit, LOG_ERR, filename, line, -r,
1170 "Failed to parse kill signal, ignoring: %s", rvalue);
1178 int config_parse_exec_mount_flags(const char *unit,
1179 const char *filename,
1181 const char *section,
1182 unsigned section_line,
1189 ExecContext *c = data;
1190 const char *word, *state;
1192 unsigned long flags = 0;
1199 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1200 _cleanup_free_ char *t;
1202 t = strndup(word, l);
1206 if (streq(t, "shared"))
1208 else if (streq(t, "slave"))
1210 else if (streq(word, "private"))
1213 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1214 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1218 if (!isempty(state))
1219 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1220 "Trailing garbage, ignoring.");
1222 c->mount_flags = flags;
1226 int config_parse_exec_selinux_context(
1228 const char *filename,
1230 const char *section,
1231 unsigned section_line,
1238 ExecContext *c = data;
1249 if (isempty(rvalue)) {
1250 free(c->selinux_context);
1251 c->selinux_context = NULL;
1252 c->selinux_context_ignore = false;
1256 if (rvalue[0] == '-') {
1262 r = unit_name_printf(u, rvalue, &k);
1264 log_syntax(unit, LOG_ERR, filename, line, -r,
1265 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1269 free(c->selinux_context);
1270 c->selinux_context = k;
1271 c->selinux_context_ignore = ignore;
1276 int config_parse_exec_apparmor_profile(
1278 const char *filename,
1280 const char *section,
1281 unsigned section_line,
1288 ExecContext *c = data;
1299 if (isempty(rvalue)) {
1300 free(c->apparmor_profile);
1301 c->apparmor_profile = NULL;
1302 c->apparmor_profile_ignore = false;
1306 if (rvalue[0] == '-') {
1312 r = unit_name_printf(u, rvalue, &k);
1314 log_syntax(unit, LOG_ERR, filename, line, -r,
1315 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1319 free(c->apparmor_profile);
1320 c->apparmor_profile = k;
1321 c->apparmor_profile_ignore = ignore;
1326 int config_parse_exec_smack_process_label(
1328 const char *filename,
1330 const char *section,
1331 unsigned section_line,
1338 ExecContext *c = data;
1349 if (isempty(rvalue)) {
1350 free(c->smack_process_label);
1351 c->smack_process_label = NULL;
1352 c->smack_process_label_ignore = false;
1356 if (rvalue[0] == '-') {
1362 r = unit_name_printf(u, rvalue, &k);
1364 log_syntax(unit, LOG_ERR, filename, line, -r,
1365 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1369 free(c->smack_process_label);
1370 c->smack_process_label = k;
1371 c->smack_process_label_ignore = ignore;
1376 int config_parse_timer(const char *unit,
1377 const char *filename,
1379 const char *section,
1380 unsigned section_line,
1391 CalendarSpec *c = NULL;
1398 if (isempty(rvalue)) {
1399 /* Empty assignment resets list */
1400 timer_free_values(t);
1404 b = timer_base_from_string(lvalue);
1406 log_syntax(unit, LOG_ERR, filename, line, -b,
1407 "Failed to parse timer base, ignoring: %s", lvalue);
1411 if (b == TIMER_CALENDAR) {
1412 if (calendar_spec_from_string(rvalue, &c) < 0) {
1413 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1414 "Failed to parse calendar specification, ignoring: %s",
1419 if (parse_sec(rvalue, &u) < 0) {
1420 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1421 "Failed to parse timer value, ignoring: %s",
1427 v = new0(TimerValue, 1);
1429 calendar_spec_free(c);
1435 v->calendar_spec = c;
1437 LIST_PREPEND(value, t->values, v);
1442 int config_parse_trigger_unit(
1444 const char *filename,
1446 const char *section,
1447 unsigned section_line,
1454 _cleanup_free_ char *p = NULL;
1464 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1465 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1466 "Multiple units to trigger specified, ignoring: %s", rvalue);
1470 r = unit_name_printf(u, rvalue, &p);
1472 log_syntax(unit, LOG_ERR, filename, line, -r,
1473 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1475 type = unit_name_to_type(p ?: rvalue);
1477 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1478 "Unit type not valid, ignoring: %s", rvalue);
1482 if (type == u->type) {
1483 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1484 "Trigger cannot be of same type, ignoring: %s", rvalue);
1488 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1490 log_syntax(unit, LOG_ERR, filename, line, -r,
1491 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1498 int config_parse_path_spec(const char *unit,
1499 const char *filename,
1501 const char *section,
1502 unsigned section_line,
1512 _cleanup_free_ char *k = NULL;
1520 if (isempty(rvalue)) {
1521 /* Empty assignment clears list */
1526 b = path_type_from_string(lvalue);
1528 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1529 "Failed to parse path type, ignoring: %s", lvalue);
1533 r = unit_full_printf(UNIT(p), rvalue, &k);
1539 log_syntax(unit, LOG_ERR, filename, line, -r,
1540 "Failed to resolve unit specifiers on %s. Ignoring.",
1544 if (!path_is_absolute(k)) {
1545 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1546 "Path is not absolute, ignoring: %s", k);
1550 s = new0(PathSpec, 1);
1555 s->path = path_kill_slashes(k);
1560 LIST_PREPEND(spec, p->specs, s);
1565 int config_parse_socket_service(const char *unit,
1566 const char *filename,
1568 const char *section,
1569 unsigned section_line,
1576 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1580 _cleanup_free_ char *p = NULL;
1587 r = unit_name_printf(UNIT(s), rvalue, &p);
1589 log_syntax(unit, LOG_ERR, filename, line, -r,
1590 "Failed to resolve specifiers, ignoring: %s", rvalue);
1594 if (!endswith(p, ".service")) {
1595 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1596 "Unit must be of type service, ignoring: %s", rvalue);
1600 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1602 log_syntax(unit, LOG_ERR, filename, line, -r,
1603 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1607 unit_ref_set(&s->service, x);
1612 int config_parse_service_sockets(const char *unit,
1613 const char *filename,
1615 const char *section,
1616 unsigned section_line,
1625 const char *word, *state;
1633 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1634 _cleanup_free_ char *t = NULL, *k = NULL;
1636 t = strndup(word, l);
1640 r = unit_name_printf(UNIT(s), t, &k);
1642 log_syntax(unit, LOG_ERR, filename, line, -r,
1643 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1645 if (!endswith(k ?: t, ".socket")) {
1646 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1647 "Unit must be of type socket, ignoring: %s", k ?: t);
1651 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1653 log_syntax(unit, LOG_ERR, filename, line, -r,
1654 "Failed to add dependency on %s, ignoring: %s",
1655 k ?: t, strerror(-r));
1657 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1661 if (!isempty(state))
1662 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1663 "Trailing garbage, ignoring.");
1668 int config_parse_service_timeout(const char *unit,
1669 const char *filename,
1671 const char *section,
1672 unsigned section_line,
1679 Service *s = userdata;
1687 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1688 rvalue, data, userdata);
1692 if (streq(lvalue, "TimeoutSec")) {
1693 s->start_timeout_defined = true;
1694 s->timeout_stop_usec = s->timeout_start_usec;
1695 } else if (streq(lvalue, "TimeoutStartSec"))
1696 s->start_timeout_defined = true;
1701 int config_parse_busname_service(
1703 const char *filename,
1705 const char *section,
1706 unsigned section_line,
1713 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1717 _cleanup_free_ char *p = NULL;
1724 r = unit_name_printf(UNIT(n), rvalue, &p);
1726 log_syntax(unit, LOG_ERR, filename, line, -r,
1727 "Failed to resolve specifiers, ignoring: %s", rvalue);
1731 if (!endswith(p, ".service")) {
1732 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1733 "Unit must be of type service, ignoring: %s", rvalue);
1737 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1739 log_syntax(unit, LOG_ERR, filename, line, -r,
1740 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1744 unit_ref_set(&n->service, x);
1749 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1751 int config_parse_bus_policy(
1753 const char *filename,
1755 const char *section,
1756 unsigned section_line,
1763 _cleanup_free_ BusNamePolicy *p = NULL;
1764 _cleanup_free_ char *id_str = NULL;
1765 BusName *busname = data;
1773 p = new0(BusNamePolicy, 1);
1777 if (streq(lvalue, "AllowUser"))
1778 p->type = BUSNAME_POLICY_TYPE_USER;
1779 else if (streq(lvalue, "AllowGroup"))
1780 p->type = BUSNAME_POLICY_TYPE_GROUP;
1782 assert_not_reached("Unknown lvalue");
1784 id_str = strdup(rvalue);
1788 access_str = strpbrk(id_str, WHITESPACE);
1790 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1791 "Invalid busname policy value '%s'", rvalue);
1797 access_str += strspn(access_str, WHITESPACE);
1799 p->access = bus_policy_access_from_string(access_str);
1800 if (p->access < 0) {
1801 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1802 "Invalid busname policy access type '%s'", access_str);
1809 LIST_PREPEND(policy, busname->policy, p);
1815 int config_parse_bus_endpoint_policy(
1817 const char *filename,
1819 const char *section,
1820 unsigned section_line,
1827 _cleanup_free_ char *name = NULL;
1828 BusPolicyAccess access;
1829 ExecContext *c = data;
1838 name = strdup(rvalue);
1842 access_str = strpbrk(name, WHITESPACE);
1844 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1845 "Invalid endpoint policy value '%s'", rvalue);
1851 access_str += strspn(access_str, WHITESPACE);
1853 access = bus_policy_access_from_string(access_str);
1854 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1855 access >= _BUS_POLICY_ACCESS_MAX) {
1856 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1857 "Invalid endpoint policy access type '%s'", access_str);
1861 if (!c->bus_endpoint) {
1862 r = bus_endpoint_new(&c->bus_endpoint);
1868 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1871 int config_parse_unit_env_file(const char *unit,
1872 const char *filename,
1874 const char *section,
1875 unsigned section_line,
1884 _cleanup_free_ char *n = NULL;
1893 if (isempty(rvalue)) {
1894 /* Empty assignment frees the list */
1900 r = unit_full_printf(u, rvalue, &n);
1902 log_syntax(unit, LOG_ERR, filename, line, -r,
1903 "Failed to resolve specifiers, ignoring: %s", rvalue);
1906 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1907 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1908 "Path '%s' is not absolute, ignoring.", s);
1912 r = strv_extend(env, s);
1919 int config_parse_environ(const char *unit,
1920 const char *filename,
1922 const char *section,
1923 unsigned section_line,
1932 const char *word, *state;
1934 _cleanup_free_ char *k = NULL;
1942 if (isempty(rvalue)) {
1943 /* Empty assignment resets the list */
1950 r = unit_full_printf(u, rvalue, &k);
1952 log_syntax(unit, LOG_ERR, filename, line, -r,
1953 "Failed to resolve specifiers, ignoring: %s", rvalue);
1961 FOREACH_WORD_QUOTED(word, l, k, state) {
1962 _cleanup_free_ char *n;
1965 n = cunescape_length(word, l);
1969 if (!env_assignment_is_valid(n)) {
1970 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1971 "Invalid environment assignment, ignoring: %s", rvalue);
1975 x = strv_env_set(*env, n);
1982 if (!isempty(state))
1983 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1984 "Trailing garbage, ignoring.");
1989 int config_parse_ip_tos(const char *unit,
1990 const char *filename,
1992 const char *section,
1993 unsigned section_line,
2000 int *ip_tos = data, x;
2007 x = ip_tos_from_string(rvalue);
2009 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2010 "Failed to parse IP TOS value, ignoring: %s", rvalue);
2018 int config_parse_unit_condition_path(
2020 const char *filename,
2022 const char *section,
2023 unsigned section_line,
2030 _cleanup_free_ char *p = NULL;
2031 Condition **list = data, *c;
2032 ConditionType t = ltype;
2033 bool trigger, negate;
2042 if (isempty(rvalue)) {
2043 /* Empty assignment resets the list */
2044 condition_free_list(*list);
2049 trigger = rvalue[0] == '|';
2053 negate = rvalue[0] == '!';
2057 r = unit_full_printf(u, rvalue, &p);
2059 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2063 if (!path_is_absolute(p)) {
2064 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2068 c = condition_new(t, p, trigger, negate);
2072 LIST_PREPEND(conditions, *list, c);
2076 int config_parse_unit_condition_string(
2078 const char *filename,
2080 const char *section,
2081 unsigned section_line,
2088 _cleanup_free_ char *s = NULL;
2089 Condition **list = data, *c;
2090 ConditionType t = ltype;
2091 bool trigger, negate;
2100 if (isempty(rvalue)) {
2101 /* Empty assignment resets the list */
2102 condition_free_list(*list);
2107 trigger = rvalue[0] == '|';
2111 negate = rvalue[0] == '!';
2115 r = unit_full_printf(u, rvalue, &s);
2117 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2121 c = condition_new(t, s, trigger, negate);
2125 LIST_PREPEND(conditions, *list, c);
2129 int config_parse_unit_condition_null(
2131 const char *filename,
2133 const char *section,
2134 unsigned section_line,
2141 Condition **list = data, *c;
2142 bool trigger, negate;
2150 if (isempty(rvalue)) {
2151 /* Empty assignment resets the list */
2152 condition_free_list(*list);
2157 trigger = rvalue[0] == '|';
2161 negate = rvalue[0] == '!';
2165 b = parse_boolean(rvalue);
2167 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2174 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2178 LIST_PREPEND(conditions, *list, c);
2182 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2183 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2185 int config_parse_unit_requires_mounts_for(
2187 const char *filename,
2189 const char *section,
2190 unsigned section_line,
2198 const char *word, *state;
2206 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2208 _cleanup_free_ char *n;
2210 n = strndup(word, l);
2214 if (!utf8_is_valid(n)) {
2215 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2219 r = unit_require_mounts_for(u, n);
2221 log_syntax(unit, LOG_ERR, filename, line, -r,
2222 "Failed to add required mount for, ignoring: %s", rvalue);
2226 if (!isempty(state))
2227 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2228 "Trailing garbage, ignoring.");
2233 int config_parse_documentation(const char *unit,
2234 const char *filename,
2236 const char *section,
2237 unsigned section_line,
2253 if (isempty(rvalue)) {
2254 /* Empty assignment resets the list */
2255 strv_free(u->documentation);
2256 u->documentation = NULL;
2260 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2261 rvalue, data, userdata);
2265 for (a = b = u->documentation; a && *a; a++) {
2267 if (is_valid_documentation_url(*a))
2270 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2271 "Invalid URL, ignoring: %s", *a);
2282 int config_parse_syscall_filter(
2284 const char *filename,
2286 const char *section,
2287 unsigned section_line,
2294 static const char default_syscalls[] =
2301 ExecContext *c = data;
2303 bool invert = false;
2304 const char *word, *state;
2313 if (isempty(rvalue)) {
2314 /* Empty assignment resets the list */
2315 set_free(c->syscall_filter);
2316 c->syscall_filter = NULL;
2317 c->syscall_whitelist = false;
2321 if (rvalue[0] == '~') {
2326 if (!c->syscall_filter) {
2327 c->syscall_filter = set_new(NULL);
2328 if (!c->syscall_filter)
2332 /* Allow everything but the ones listed */
2333 c->syscall_whitelist = false;
2337 /* Allow nothing but the ones listed */
2338 c->syscall_whitelist = true;
2340 /* Accept default syscalls if we are on a whitelist */
2341 NULSTR_FOREACH(i, default_syscalls) {
2344 id = seccomp_syscall_resolve_name(i);
2348 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2357 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2358 _cleanup_free_ char *t = NULL;
2361 t = strndup(word, l);
2365 id = seccomp_syscall_resolve_name(t);
2367 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2368 "Failed to parse system call, ignoring: %s", t);
2372 /* If we previously wanted to forbid a syscall and now
2373 * we want to allow it, then remove it from the list
2375 if (!invert == c->syscall_whitelist) {
2376 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2382 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2384 if (!isempty(state))
2385 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2386 "Trailing garbage, ignoring.");
2388 /* Turn on NNP, but only if it wasn't configured explicitly
2389 * before, and only if we are in user mode. */
2390 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2391 c->no_new_privileges = true;
2396 int config_parse_syscall_archs(
2398 const char *filename,
2400 const char *section,
2401 unsigned section_line,
2409 const char *word, *state;
2413 if (isempty(rvalue)) {
2419 r = set_ensure_allocated(archs, NULL);
2423 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2424 _cleanup_free_ char *t = NULL;
2427 t = strndup(word, l);
2431 r = seccomp_arch_from_string(t, &a);
2433 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2434 "Failed to parse system call architecture, ignoring: %s", t);
2438 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2444 if (!isempty(state))
2445 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2446 "Trailing garbage, ignoring.");
2451 int config_parse_syscall_errno(
2453 const char *filename,
2455 const char *section,
2456 unsigned section_line,
2463 ExecContext *c = data;
2470 if (isempty(rvalue)) {
2471 /* Empty assignment resets to KILL */
2472 c->syscall_errno = 0;
2476 e = errno_from_name(rvalue);
2478 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2479 "Failed to parse error number, ignoring: %s", rvalue);
2483 c->syscall_errno = e;
2487 int config_parse_address_families(
2489 const char *filename,
2491 const char *section,
2492 unsigned section_line,
2499 ExecContext *c = data;
2500 bool invert = false;
2501 const char *word, *state;
2509 if (isempty(rvalue)) {
2510 /* Empty assignment resets the list */
2511 set_free(c->address_families);
2512 c->address_families = NULL;
2513 c->address_families_whitelist = false;
2517 if (rvalue[0] == '~') {
2522 if (!c->address_families) {
2523 c->address_families = set_new(NULL);
2524 if (!c->address_families)
2527 c->address_families_whitelist = !invert;
2530 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2531 _cleanup_free_ char *t = NULL;
2534 t = strndup(word, l);
2538 af = af_from_name(t);
2540 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2541 "Failed to parse address family, ignoring: %s", t);
2545 /* If we previously wanted to forbid an address family and now
2546 * we want to allow it, then remove it from the list
2548 if (!invert == c->address_families_whitelist) {
2549 r = set_put(c->address_families, INT_TO_PTR(af));
2555 set_remove(c->address_families, INT_TO_PTR(af));
2557 if (!isempty(state))
2558 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2559 "Trailing garbage, ignoring.");
2565 int config_parse_unit_slice(
2567 const char *filename,
2569 const char *section,
2570 unsigned section_line,
2577 _cleanup_free_ char *k = NULL;
2578 Unit *u = userdata, *slice;
2586 r = unit_name_printf(u, rvalue, &k);
2588 log_syntax(unit, LOG_ERR, filename, line, -r,
2589 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2596 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2598 log_syntax(unit, LOG_ERR, filename, line, -r,
2599 "Failed to load slice unit %s. Ignoring.", k);
2603 if (slice->type != UNIT_SLICE) {
2604 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2605 "Slice unit %s is not a slice. Ignoring.", k);
2609 unit_ref_set(&u->slice, slice);
2613 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2615 int config_parse_cpu_shares(
2617 const char *filename,
2619 const char *section,
2620 unsigned section_line,
2627 unsigned long *shares = data, lu;
2634 if (isempty(rvalue)) {
2635 *shares = (unsigned long) -1;
2639 r = safe_atolu(rvalue, &lu);
2640 if (r < 0 || lu <= 0) {
2641 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2642 "CPU shares '%s' invalid. Ignoring.", rvalue);
2650 int config_parse_cpu_quota(
2652 const char *filename,
2654 const char *section,
2655 unsigned section_line,
2662 CGroupContext *c = data;
2669 if (isempty(rvalue)) {
2670 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2674 if (!endswith(rvalue, "%")) {
2676 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2677 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2681 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2682 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2683 "CPU quota '%s' invalid. Ignoring.", rvalue);
2687 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2692 int config_parse_memory_limit(
2694 const char *filename,
2696 const char *section,
2697 unsigned section_line,
2704 CGroupContext *c = data;
2708 if (isempty(rvalue)) {
2709 c->memory_limit = (uint64_t) -1;
2713 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2715 r = parse_size(rvalue, 1024, &bytes);
2717 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2718 "Memory limit '%s' invalid. Ignoring.", rvalue);
2722 c->memory_limit = (uint64_t) bytes;
2726 int config_parse_device_allow(
2728 const char *filename,
2730 const char *section,
2731 unsigned section_line,
2738 _cleanup_free_ char *path = NULL;
2739 CGroupContext *c = data;
2740 CGroupDeviceAllow *a;
2744 if (isempty(rvalue)) {
2745 while (c->device_allow)
2746 cgroup_context_free_device_allow(c, c->device_allow);
2751 n = strcspn(rvalue, WHITESPACE);
2752 path = strndup(rvalue, n);
2756 if (!startswith(path, "/dev/") &&
2757 !startswith(path, "block-") &&
2758 !startswith(path, "char-")) {
2759 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2760 "Invalid device node path '%s'. Ignoring.", path);
2764 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2768 if (!in_charset(m, "rwm")) {
2769 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2770 "Invalid device rights '%s'. Ignoring.", m);
2774 a = new0(CGroupDeviceAllow, 1);
2780 a->r = !!strchr(m, 'r');
2781 a->w = !!strchr(m, 'w');
2782 a->m = !!strchr(m, 'm');
2784 LIST_PREPEND(device_allow, c->device_allow, a);
2788 int config_parse_blockio_weight(
2790 const char *filename,
2792 const char *section,
2793 unsigned section_line,
2800 unsigned long *weight = data, lu;
2807 if (isempty(rvalue)) {
2808 *weight = (unsigned long) -1;
2812 r = safe_atolu(rvalue, &lu);
2813 if (r < 0 || lu < 10 || lu > 1000) {
2814 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2815 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2823 int config_parse_blockio_device_weight(
2825 const char *filename,
2827 const char *section,
2828 unsigned section_line,
2835 _cleanup_free_ char *path = NULL;
2836 CGroupBlockIODeviceWeight *w;
2837 CGroupContext *c = data;
2847 if (isempty(rvalue)) {
2848 while (c->blockio_device_weights)
2849 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2854 n = strcspn(rvalue, WHITESPACE);
2855 weight = rvalue + n;
2857 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2858 "Expected block device and device weight. Ignoring.");
2862 path = strndup(rvalue, n);
2866 if (!path_startswith(path, "/dev")) {
2867 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2868 "Invalid device node path '%s'. Ignoring.", path);
2872 weight += strspn(weight, WHITESPACE);
2873 r = safe_atolu(weight, &lu);
2874 if (r < 0 || lu < 10 || lu > 1000) {
2875 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2876 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2880 w = new0(CGroupBlockIODeviceWeight, 1);
2889 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2893 int config_parse_blockio_bandwidth(
2895 const char *filename,
2897 const char *section,
2898 unsigned section_line,
2905 _cleanup_free_ char *path = NULL;
2906 CGroupBlockIODeviceBandwidth *b;
2907 CGroupContext *c = data;
2908 const char *bandwidth;
2918 read = streq("BlockIOReadBandwidth", lvalue);
2920 if (isempty(rvalue)) {
2921 CGroupBlockIODeviceBandwidth *next;
2923 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2924 if (b->read == read)
2925 cgroup_context_free_blockio_device_bandwidth(c, b);
2930 n = strcspn(rvalue, WHITESPACE);
2931 bandwidth = rvalue + n;
2932 bandwidth += strspn(bandwidth, WHITESPACE);
2935 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2936 "Expected space separated pair of device node and bandwidth. Ignoring.");
2940 path = strndup(rvalue, n);
2944 if (!path_startswith(path, "/dev")) {
2945 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2946 "Invalid device node path '%s'. Ignoring.", path);
2950 r = parse_size(bandwidth, 1000, &bytes);
2951 if (r < 0 || bytes <= 0) {
2952 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2953 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2957 b = new0(CGroupBlockIODeviceBandwidth, 1);
2963 b->bandwidth = (uint64_t) bytes;
2966 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2971 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2973 int config_parse_job_mode_isolate(
2975 const char *filename,
2977 const char *section,
2978 unsigned section_line,
2992 r = parse_boolean(rvalue);
2994 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2995 "Failed to parse boolean, ignoring: %s", rvalue);
2999 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3003 int config_parse_personality(
3005 const char *filename,
3007 const char *section,
3008 unsigned section_line,
3015 unsigned long *personality = data, p;
3020 assert(personality);
3022 p = personality_from_string(rvalue);
3023 if (p == 0xffffffffUL) {
3024 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3025 "Failed to parse personality, ignoring: %s", rvalue);
3033 int config_parse_runtime_directory(
3035 const char *filename,
3037 const char *section,
3038 unsigned section_line,
3046 const char *word, *state;
3055 if (isempty(rvalue)) {
3056 /* Empty assignment resets the list */
3062 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3063 _cleanup_free_ char *n;
3065 n = strndup(word, l);
3069 if (!filename_is_valid(n)) {
3070 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3071 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3075 r = strv_push(rt, n);
3081 if (!isempty(state))
3082 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3083 "Trailing garbage, ignoring.");
3088 int config_parse_set_status(
3090 const char *filename,
3092 const char *section,
3093 unsigned section_line,
3101 const char *word, *state;
3103 ExitStatusSet *status_set = data;
3110 /* Empty assignment resets the list */
3111 if (isempty(rvalue)) {
3112 exit_status_set_free(status_set);
3116 FOREACH_WORD(word, l, rvalue, state) {
3117 _cleanup_free_ char *temp;
3120 temp = strndup(word, l);
3124 r = safe_atoi(temp, &val);
3126 val = signal_from_string_try_harder(temp);
3129 log_syntax(unit, LOG_ERR, filename, line, -val,
3130 "Failed to parse value, ignoring: %s", word);
3134 if (val < 0 || val > 255) {
3135 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3136 "Value %d is outside range 0-255, ignoring", val);
3141 r = set_ensure_allocated(&status_set->status, NULL);
3145 r = set_put(status_set->status, INT_TO_PTR(val));
3147 log_syntax(unit, LOG_ERR, filename, line, -r,
3148 "Unable to store: %s", word);
3152 if (!isempty(state))
3153 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3154 "Trailing garbage, ignoring.");
3159 int config_parse_namespace_path_strv(
3161 const char *filename,
3163 const char *section,
3164 unsigned section_line,
3172 const char *word, *state;
3181 if (isempty(rvalue)) {
3182 /* Empty assignment resets the list */
3188 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3189 _cleanup_free_ char *n;
3192 n = strndup(word, l);
3196 if (!utf8_is_valid(n)) {
3197 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3201 offset = n[0] == '-';
3202 if (!path_is_absolute(n + offset)) {
3203 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3204 "Not an absolute path, ignoring: %s", rvalue);
3208 path_kill_slashes(n);
3210 r = strv_push(sv, n);
3216 if (!isempty(state))
3217 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3218 "Trailing garbage, ignoring.");
3223 int config_parse_no_new_privileges(
3225 const char *filename,
3227 const char *section,
3228 unsigned section_line,
3235 ExecContext *c = data;
3243 k = parse_boolean(rvalue);
3245 log_syntax(unit, LOG_ERR, filename, line, -k,
3246 "Failed to parse boolean value, ignoring: %s", rvalue);
3250 c->no_new_privileges = !!k;
3251 c->no_new_privileges_set = true;
3256 int config_parse_protect_home(
3258 const char *filename,
3260 const char *section,
3261 unsigned section_line,
3268 ExecContext *c = data;
3276 /* Our enum shall be a superset of booleans, hence first try
3277 * to parse as as boolean, and then as enum */
3279 k = parse_boolean(rvalue);
3281 c->protect_home = PROTECT_HOME_YES;
3283 c->protect_home = PROTECT_HOME_NO;
3287 h = protect_home_from_string(rvalue);
3289 log_syntax(unit, LOG_ERR, filename, line, -h,
3290 "Failed to parse protect home value, ignoring: %s", rvalue);
3294 c->protect_home = h;
3300 int config_parse_protect_system(
3302 const char *filename,
3304 const char *section,
3305 unsigned section_line,
3312 ExecContext *c = data;
3320 /* Our enum shall be a superset of booleans, hence first try
3321 * to parse as as boolean, and then as enum */
3323 k = parse_boolean(rvalue);
3325 c->protect_system = PROTECT_SYSTEM_YES;
3327 c->protect_system = PROTECT_SYSTEM_NO;
3331 s = protect_system_from_string(rvalue);
3333 log_syntax(unit, LOG_ERR, filename, line, -s,
3334 "Failed to parse protect system value, ignoring: %s", rvalue);
3338 c->protect_system = s;
3344 #define FOLLOW_MAX 8
3346 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3357 /* This will update the filename pointer if the loaded file is
3358 * reached by a symlink. The old string will be freed. */
3361 char *target, *name;
3363 if (c++ >= FOLLOW_MAX)
3366 path_kill_slashes(*filename);
3368 /* Add the file name we are currently looking at to
3369 * the names of this unit, but only if it is a valid
3371 name = basename(*filename);
3373 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3375 id = set_get(names, name);
3381 r = set_consume(names, id);
3387 /* Try to open the file name, but don't if its a symlink */
3388 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3395 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3396 r = readlink_and_make_absolute(*filename, &target);
3404 f = fdopen(fd, "re");
3416 static int merge_by_names(Unit **u, Set *names, const char *id) {
3424 /* Let's try to add in all symlink names we found */
3425 while ((k = set_steal_first(names))) {
3427 /* First try to merge in the other name into our
3429 r = unit_merge_by_name(*u, k);
3433 /* Hmm, we couldn't merge the other unit into
3434 * ours? Then let's try it the other way
3437 other = manager_get_unit((*u)->manager, k);
3441 r = unit_merge(other, *u);
3444 return merge_by_names(u, names, NULL);
3452 unit_choose_id(*u, id);
3460 static int load_from_path(Unit *u, const char *path) {
3462 _cleanup_set_free_free_ Set *symlink_names = NULL;
3463 _cleanup_fclose_ FILE *f = NULL;
3464 _cleanup_free_ char *filename = NULL;
3472 symlink_names = set_new(&string_hash_ops);
3476 if (path_is_absolute(path)) {
3478 filename = strdup(path);
3482 r = open_follow(&filename, &f, symlink_names, &id);
3494 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3496 /* Instead of opening the path right away, we manually
3497 * follow all symlinks and add their name to our unit
3498 * name set while doing so */
3499 filename = path_make_absolute(path, *p);
3503 if (u->manager->unit_path_cache &&
3504 !set_get(u->manager->unit_path_cache, filename))
3507 r = open_follow(&filename, &f, symlink_names, &id);
3516 /* Empty the symlink names for the next run */
3517 set_clear_free(symlink_names);
3526 /* Hmm, no suitable file found? */
3530 r = merge_by_names(&merged, symlink_names, id);
3535 u->load_state = UNIT_MERGED;
3539 if (fstat(fileno(f), &st) < 0)
3542 if (null_or_empty(&st))
3543 u->load_state = UNIT_MASKED;
3545 u->load_state = UNIT_LOADED;
3547 /* Now, parse the file contents */
3548 r = config_parse(u->id, filename, f,
3549 UNIT_VTABLE(u)->sections,
3550 config_item_perf_lookup, load_fragment_gperf_lookup,
3551 false, true, false, u);
3556 free(u->fragment_path);
3557 u->fragment_path = filename;
3560 u->fragment_mtime = timespec_load(&st.st_mtim);
3562 if (u->source_path) {
3563 if (stat(u->source_path, &st) >= 0)
3564 u->source_mtime = timespec_load(&st.st_mtim);
3566 u->source_mtime = 0;
3572 int unit_load_fragment(Unit *u) {
3578 assert(u->load_state == UNIT_STUB);
3581 /* First, try to find the unit under its id. We always look
3582 * for unit files in the default directories, to make it easy
3583 * to override things by placing things in /etc/systemd/system */
3584 r = load_from_path(u, u->id);
3588 /* Try to find an alias we can load this with */
3589 if (u->load_state == UNIT_STUB) {
3590 SET_FOREACH(t, u->names, i) {
3595 r = load_from_path(u, t);
3599 if (u->load_state != UNIT_STUB)
3604 /* And now, try looking for it under the suggested (originally linked) path */
3605 if (u->load_state == UNIT_STUB && u->fragment_path) {
3607 r = load_from_path(u, u->fragment_path);
3611 if (u->load_state == UNIT_STUB) {
3612 /* Hmm, this didn't work? Then let's get rid
3613 * of the fragment path stored for us, so that
3614 * we don't point to an invalid location. */
3615 free(u->fragment_path);
3616 u->fragment_path = NULL;
3620 /* Look for a template */
3621 if (u->load_state == UNIT_STUB && u->instance) {
3622 _cleanup_free_ char *k;
3624 k = unit_name_template(u->id);
3628 r = load_from_path(u, k);
3632 if (u->load_state == UNIT_STUB) {
3633 SET_FOREACH(t, u->names, i) {
3634 _cleanup_free_ char *z = NULL;
3639 z = unit_name_template(t);
3643 r = load_from_path(u, z);
3647 if (u->load_state != UNIT_STUB)
3656 void unit_dump_config_items(FILE *f) {
3657 static const struct {
3658 const ConfigParserCallback callback;
3661 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3662 { config_parse_warn_compat, "NOTSUPPORTED" },
3664 { config_parse_int, "INTEGER" },
3665 { config_parse_unsigned, "UNSIGNED" },
3666 { config_parse_iec_size, "SIZE" },
3667 { config_parse_iec_off, "SIZE" },
3668 { config_parse_si_size, "SIZE" },
3669 { config_parse_bool, "BOOLEAN" },
3670 { config_parse_string, "STRING" },
3671 { config_parse_path, "PATH" },
3672 { config_parse_unit_path_printf, "PATH" },
3673 { config_parse_strv, "STRING [...]" },
3674 { config_parse_exec_nice, "NICE" },
3675 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3676 { config_parse_exec_io_class, "IOCLASS" },
3677 { config_parse_exec_io_priority, "IOPRIORITY" },
3678 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3679 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3680 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3681 { config_parse_mode, "MODE" },
3682 { config_parse_unit_env_file, "FILE" },
3683 { config_parse_output, "OUTPUT" },
3684 { config_parse_input, "INPUT" },
3685 { config_parse_log_facility, "FACILITY" },
3686 { config_parse_log_level, "LEVEL" },
3687 { config_parse_exec_capabilities, "CAPABILITIES" },
3688 { config_parse_exec_secure_bits, "SECUREBITS" },
3689 { config_parse_bounding_set, "BOUNDINGSET" },
3690 { config_parse_limit, "LIMIT" },
3691 { config_parse_unit_deps, "UNIT [...]" },
3692 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3693 { config_parse_service_type, "SERVICETYPE" },
3694 { config_parse_service_restart, "SERVICERESTART" },
3695 #ifdef HAVE_SYSV_COMPAT
3696 { config_parse_sysv_priority, "SYSVPRIORITY" },
3698 { config_parse_kill_mode, "KILLMODE" },
3699 { config_parse_kill_signal, "SIGNAL" },
3700 { config_parse_socket_listen, "SOCKET [...]" },
3701 { config_parse_socket_bind, "SOCKETBIND" },
3702 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3703 { config_parse_sec, "SECONDS" },
3704 { config_parse_nsec, "NANOSECONDS" },
3705 { config_parse_namespace_path_strv, "PATH [...]" },
3706 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3707 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3708 { config_parse_unit_string_printf, "STRING" },
3709 { config_parse_trigger_unit, "UNIT" },
3710 { config_parse_timer, "TIMER" },
3711 { config_parse_path_spec, "PATH" },
3712 { config_parse_notify_access, "ACCESS" },
3713 { config_parse_ip_tos, "TOS" },
3714 { config_parse_unit_condition_path, "CONDITION" },
3715 { config_parse_unit_condition_string, "CONDITION" },
3716 { config_parse_unit_condition_null, "CONDITION" },
3717 { config_parse_unit_slice, "SLICE" },
3718 { config_parse_documentation, "URL" },
3719 { config_parse_service_timeout, "SECONDS" },
3720 { config_parse_failure_action, "ACTION" },
3721 { config_parse_set_status, "STATUS" },
3722 { config_parse_service_sockets, "SOCKETS" },
3723 { config_parse_environ, "ENVIRON" },
3725 { config_parse_syscall_filter, "SYSCALLS" },
3726 { config_parse_syscall_archs, "ARCHS" },
3727 { config_parse_syscall_errno, "ERRNO" },
3728 { config_parse_address_families, "FAMILIES" },
3730 { config_parse_cpu_shares, "SHARES" },
3731 { config_parse_memory_limit, "LIMIT" },
3732 { config_parse_device_allow, "DEVICE" },
3733 { config_parse_device_policy, "POLICY" },
3734 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3735 { config_parse_blockio_weight, "WEIGHT" },
3736 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3737 { config_parse_long, "LONG" },
3738 { config_parse_socket_service, "SERVICE" },
3740 { config_parse_exec_selinux_context, "LABEL" },
3742 { config_parse_job_mode, "MODE" },
3743 { config_parse_job_mode_isolate, "BOOLEAN" },
3744 { config_parse_personality, "PERSONALITY" },
3747 const char *prev = NULL;
3752 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3753 const char *rvalue = "OTHER", *lvalue;
3757 const ConfigPerfItem *p;
3759 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3761 dot = strchr(i, '.');
3762 lvalue = dot ? dot + 1 : i;
3766 if (!prev || !strneq(prev, i, prefix_len+1)) {
3770 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3773 for (j = 0; j < ELEMENTSOF(table); j++)
3774 if (p->parse == table[j].callback) {
3775 rvalue = table[j].rvalue;
3779 fprintf(f, "%s=%s\n", lvalue, rvalue);