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"
64 #include "seccomp-util.h"
67 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
68 int config_parse_warn_compat(
73 unsigned section_line,
80 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
81 "Support for option %s= has been disabled at compile time and is ignored",
87 int config_parse_unit_deps(const char *unit,
91 unsigned section_line,
98 UnitDependency d = ltype;
100 const char *word, *state;
107 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
108 _cleanup_free_ char *t = NULL, *k = NULL;
111 t = strndup(word, l);
115 r = unit_name_printf(u, t, &k);
117 log_syntax(unit, LOG_ERR, filename, line, -r,
118 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
122 r = unit_add_dependency_by_name(u, d, k, NULL, true);
124 log_syntax(unit, LOG_ERR, filename, line, -r,
125 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
128 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
133 int config_parse_unit_string_printf(const char *unit,
134 const char *filename,
137 unsigned section_line,
145 _cleanup_free_ char *k = NULL;
153 r = unit_full_printf(u, rvalue, &k);
155 log_syntax(unit, LOG_ERR, filename, line, -r,
156 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
158 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
159 k ? k : rvalue, data, userdata);
162 int config_parse_unit_strv_printf(const char *unit,
163 const char *filename,
166 unsigned section_line,
174 _cleanup_free_ char *k = NULL;
182 r = unit_full_printf(u, rvalue, &k);
184 log_syntax(unit, LOG_ERR, filename, line, -r,
185 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
187 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
188 k ? k : rvalue, data, userdata);
191 int config_parse_unit_path_printf(const char *unit,
192 const char *filename,
195 unsigned section_line,
202 _cleanup_free_ char *k = NULL;
211 r = unit_full_printf(u, rvalue, &k);
213 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
217 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
220 int config_parse_unit_path_strv_printf(
222 const char *filename,
225 unsigned section_line,
233 const char *word, *state;
243 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
244 _cleanup_free_ char *k = NULL;
250 r = unit_full_printf(u, t, &k);
252 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
256 if (!utf8_is_valid(k)) {
257 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
261 if (!path_is_absolute(k)) {
262 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
266 path_kill_slashes(k);
275 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
280 int config_parse_socket_listen(const char *unit,
281 const char *filename,
284 unsigned section_line,
291 SocketPort *p, *tail;
302 if (isempty(rvalue)) {
303 /* An empty assignment removes all ports */
304 socket_free_ports(s);
308 p = new0(SocketPort, 1);
312 if (ltype != SOCKET_SOCKET) {
315 r = unit_full_printf(UNIT(s), rvalue, &p->path);
317 p->path = strdup(rvalue);
322 log_syntax(unit, LOG_ERR, filename, line, -r,
323 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
326 path_kill_slashes(p->path);
328 } else if (streq(lvalue, "ListenNetlink")) {
329 _cleanup_free_ char *k = NULL;
331 p->type = SOCKET_SOCKET;
332 r = unit_full_printf(UNIT(s), rvalue, &k);
334 log_syntax(unit, LOG_ERR, filename, line, -r,
335 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
337 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
339 log_syntax(unit, LOG_ERR, filename, line, -r,
340 "Failed to parse address value, ignoring: %s", rvalue);
346 _cleanup_free_ char *k = NULL;
348 p->type = SOCKET_SOCKET;
349 r = unit_full_printf(UNIT(s), rvalue, &k);
351 log_syntax(unit, LOG_ERR, filename, line, -r,
352 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
354 r = socket_address_parse(&p->address, k ? k : rvalue);
356 log_syntax(unit, LOG_ERR, filename, line, -r,
357 "Failed to parse address value, ignoring: %s", rvalue);
362 if (streq(lvalue, "ListenStream"))
363 p->address.type = SOCK_STREAM;
364 else if (streq(lvalue, "ListenDatagram"))
365 p->address.type = SOCK_DGRAM;
367 assert(streq(lvalue, "ListenSequentialPacket"));
368 p->address.type = SOCK_SEQPACKET;
371 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
372 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
373 "Address family not supported, ignoring: %s", rvalue);
383 LIST_FIND_TAIL(port, s->ports, tail);
384 LIST_INSERT_AFTER(port, s->ports, tail, p);
386 LIST_PREPEND(port, s->ports, p);
391 int config_parse_socket_bind(const char *unit,
392 const char *filename,
395 unsigned section_line,
403 SocketAddressBindIPv6Only b;
412 b = socket_address_bind_ipv6_only_from_string(rvalue);
416 r = parse_boolean(rvalue);
418 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
419 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
423 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
425 s->bind_ipv6_only = b;
430 int config_parse_exec_nice(const char *unit,
431 const char *filename,
434 unsigned section_line,
441 ExecContext *c = data;
449 r = safe_atoi(rvalue, &priority);
451 log_syntax(unit, LOG_ERR, filename, line, -r,
452 "Failed to parse nice priority, ignoring: %s. ", rvalue);
456 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
457 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
458 "Nice priority out of range, ignoring: %s", rvalue);
468 int config_parse_exec_oom_score_adjust(const char* unit,
469 const char *filename,
472 unsigned section_line,
479 ExecContext *c = data;
487 r = safe_atoi(rvalue, &oa);
489 log_syntax(unit, LOG_ERR, filename, line, -r,
490 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
494 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
495 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
496 "OOM score adjust value out of range, ignoring: %s", rvalue);
500 c->oom_score_adjust = oa;
501 c->oom_score_adjust_set = true;
506 int config_parse_exec(const char *unit,
507 const char *filename,
510 unsigned section_line,
517 ExecCommand **e = data, *nce;
529 if (isempty(rvalue)) {
530 /* An empty assignment resets the list */
531 exec_command_free_list(*e);
536 /* We accept an absolute path as first argument, or
537 * alternatively an absolute prefixed with @ to allow
538 * overriding of argv[0]. */
541 const char *word, *state;
543 bool honour_argv0 = false, ignore = false;
549 rvalue += strspn(rvalue, WHITESPACE);
554 for (i = 0; i < 2; i++) {
555 if (rvalue[0] == '-' && !ignore) {
560 if (rvalue[0] == '@' && !honour_argv0) {
566 if (*rvalue != '/') {
567 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
568 "Executable path is not absolute, ignoring: %s", rvalue);
573 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
574 if (strneq(word, ";", MAX(l, 1U)))
579 if (!isempty(state)) {
580 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
581 "Trailing garbage, ignoring.");
586 n = new(char*, k + !honour_argv0);
591 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
592 if (strneq(word, ";", MAX(l, 1U)))
594 else if (strneq(word, "\\;", MAX(l, 1U)))
597 if (honour_argv0 && word == rvalue) {
600 path = strndup(word, l);
606 if (!utf8_is_valid(path)) {
607 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
615 c = n[k++] = cunescape_length(word, l);
621 if (!utf8_is_valid(c)) {
622 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
632 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
633 "Invalid command line, ignoring: %s", rvalue);
646 assert(path_is_absolute(path));
648 nce = new0(ExecCommand, 1);
656 nce->ignore = ignore;
658 path_kill_slashes(nce->path);
660 exec_command_append_list(e, nce);
676 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
677 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
679 int config_parse_socket_bindtodevice(const char* unit,
680 const char *filename,
683 unsigned section_line,
698 if (rvalue[0] && !streq(rvalue, "*")) {
705 free(s->bind_to_device);
706 s->bind_to_device = n;
711 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
712 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
714 int config_parse_exec_io_class(const char *unit,
715 const char *filename,
718 unsigned section_line,
725 ExecContext *c = data;
733 x = ioprio_class_from_string(rvalue);
735 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
736 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
740 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
741 c->ioprio_set = true;
746 int config_parse_exec_io_priority(const char *unit,
747 const char *filename,
750 unsigned section_line,
757 ExecContext *c = data;
765 r = safe_atoi(rvalue, &i);
766 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
767 log_syntax(unit, LOG_ERR, filename, line, -r,
768 "Failed to parse IO priority, ignoring: %s", rvalue);
772 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
773 c->ioprio_set = true;
778 int config_parse_exec_cpu_sched_policy(const char *unit,
779 const char *filename,
782 unsigned section_line,
790 ExecContext *c = data;
798 x = sched_policy_from_string(rvalue);
800 log_syntax(unit, LOG_ERR, filename, line, -x,
801 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
805 c->cpu_sched_policy = x;
806 /* Moving to or from real-time policy? We need to adjust the priority */
807 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
808 c->cpu_sched_set = true;
813 int config_parse_exec_cpu_sched_prio(const char *unit,
814 const char *filename,
817 unsigned section_line,
824 ExecContext *c = data;
832 r = safe_atoi(rvalue, &i);
834 log_syntax(unit, LOG_ERR, filename, line, -r,
835 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
839 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
840 min = sched_get_priority_min(c->cpu_sched_policy);
841 max = sched_get_priority_max(c->cpu_sched_policy);
843 if (i < min || i > max) {
844 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
845 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
849 c->cpu_sched_priority = i;
850 c->cpu_sched_set = true;
855 int config_parse_exec_cpu_affinity(const char *unit,
856 const char *filename,
859 unsigned section_line,
866 ExecContext *c = data;
867 const char *word, *state;
875 if (isempty(rvalue)) {
876 /* An empty assignment resets the CPU list */
883 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
884 _cleanup_free_ char *t = NULL;
888 t = strndup(word, l);
892 r = safe_atou(t, &cpu);
895 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
900 if (r < 0 || cpu >= c->cpuset_ncpus) {
901 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
902 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
906 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
909 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
910 "Trailing garbage, ignoring.");
915 int config_parse_exec_capabilities(const char *unit,
916 const char *filename,
919 unsigned section_line,
926 ExecContext *c = data;
934 cap = cap_from_text(rvalue);
936 log_syntax(unit, LOG_ERR, filename, line, errno,
937 "Failed to parse capabilities, ignoring: %s", rvalue);
942 cap_free(c->capabilities);
943 c->capabilities = cap;
948 int config_parse_exec_secure_bits(const char *unit,
949 const char *filename,
952 unsigned section_line,
959 ExecContext *c = data;
961 const char *word, *state;
968 if (isempty(rvalue)) {
969 /* An empty assignment resets the field */
974 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
975 if (first_word(word, "keep-caps"))
976 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
977 else if (first_word(word, "keep-caps-locked"))
978 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
979 else if (first_word(word, "no-setuid-fixup"))
980 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
981 else if (first_word(word, "no-setuid-fixup-locked"))
982 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
983 else if (first_word(word, "noroot"))
984 c->secure_bits |= 1<<SECURE_NOROOT;
985 else if (first_word(word, "noroot-locked"))
986 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
988 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
989 "Failed to parse secure bits, ignoring: %s", rvalue);
994 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
995 "Invalid syntax, garbage at the end, ignoring.");
1000 int config_parse_bounding_set(const char *unit,
1001 const char *filename,
1003 const char *section,
1004 unsigned section_line,
1011 uint64_t *capability_bounding_set_drop = data;
1012 const char *word, *state;
1014 bool invert = false;
1022 if (rvalue[0] == '~') {
1027 /* Note that we store this inverted internally, since the
1028 * kernel wants it like this. But we actually expose it
1029 * non-inverted everywhere to have a fully normalized
1032 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1033 _cleanup_free_ char *t = NULL;
1037 t = strndup(word, l);
1041 r = cap_from_name(t, &cap);
1043 log_syntax(unit, LOG_ERR, filename, line, errno,
1044 "Failed to parse capability in bounding set, ignoring: %s", t);
1048 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1050 if (!isempty(state))
1051 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1052 "Trailing garbage, ignoring.");
1055 *capability_bounding_set_drop |= sum;
1057 *capability_bounding_set_drop |= ~sum;
1062 int config_parse_limit(const char *unit,
1063 const char *filename,
1065 const char *section,
1066 unsigned section_line,
1073 struct rlimit **rl = data;
1074 unsigned long long u;
1083 if (streq(rvalue, "infinity"))
1084 u = (unsigned long long) RLIM_INFINITY;
1088 r = safe_atollu(rvalue, &u);
1090 log_syntax(unit, LOG_ERR, filename, line, -r,
1091 "Failed to parse resource value, ignoring: %s", rvalue);
1097 *rl = new(struct rlimit, 1);
1102 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1106 #ifdef HAVE_SYSV_COMPAT
1107 int config_parse_sysv_priority(const char *unit,
1108 const char *filename,
1110 const char *section,
1111 unsigned section_line,
1118 int *priority = data;
1126 r = safe_atoi(rvalue, &i);
1127 if (r < 0 || i < 0) {
1128 log_syntax(unit, LOG_ERR, filename, line, -r,
1129 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1133 *priority = (int) i;
1138 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1140 int config_parse_kill_signal(const char *unit,
1141 const char *filename,
1143 const char *section,
1144 unsigned section_line,
1159 r = signal_from_string_try_harder(rvalue);
1161 log_syntax(unit, LOG_ERR, filename, line, -r,
1162 "Failed to parse kill signal, ignoring: %s", rvalue);
1170 int config_parse_exec_mount_flags(const char *unit,
1171 const char *filename,
1173 const char *section,
1174 unsigned section_line,
1181 ExecContext *c = data;
1182 const char *word, *state;
1184 unsigned long flags = 0;
1191 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1192 _cleanup_free_ char *t;
1194 t = strndup(word, l);
1198 if (streq(t, "shared"))
1200 else if (streq(t, "slave"))
1202 else if (streq(word, "private"))
1205 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1206 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1210 if (!isempty(state))
1211 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1212 "Trailing garbage, ignoring.");
1214 c->mount_flags = flags;
1218 int config_parse_exec_selinux_context(
1220 const char *filename,
1222 const char *section,
1223 unsigned section_line,
1230 ExecContext *c = data;
1241 if (isempty(rvalue)) {
1242 free(c->selinux_context);
1243 c->selinux_context = NULL;
1244 c->selinux_context_ignore = false;
1248 if (rvalue[0] == '-') {
1254 r = unit_name_printf(u, rvalue, &k);
1256 log_syntax(unit, LOG_ERR, filename, line, -r,
1257 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1261 free(c->selinux_context);
1262 c->selinux_context = k;
1263 c->selinux_context_ignore = ignore;
1268 int config_parse_exec_apparmor_profile(
1270 const char *filename,
1272 const char *section,
1273 unsigned section_line,
1280 ExecContext *c = data;
1291 if (isempty(rvalue)) {
1292 free(c->apparmor_profile);
1293 c->apparmor_profile = NULL;
1294 c->apparmor_profile_ignore = false;
1298 if (rvalue[0] == '-') {
1304 r = unit_name_printf(u, rvalue, &k);
1306 log_syntax(unit, LOG_ERR, filename, line, -r,
1307 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1311 free(c->apparmor_profile);
1312 c->apparmor_profile = k;
1313 c->apparmor_profile_ignore = ignore;
1318 int config_parse_exec_smack_process_label(
1320 const char *filename,
1322 const char *section,
1323 unsigned section_line,
1330 ExecContext *c = data;
1341 if (isempty(rvalue)) {
1342 free(c->smack_process_label);
1343 c->smack_process_label = NULL;
1344 c->smack_process_label_ignore = false;
1348 if (rvalue[0] == '-') {
1354 r = unit_name_printf(u, rvalue, &k);
1356 log_syntax(unit, LOG_ERR, filename, line, -r,
1357 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1361 free(c->smack_process_label);
1362 c->smack_process_label = k;
1363 c->smack_process_label_ignore = ignore;
1368 int config_parse_timer(const char *unit,
1369 const char *filename,
1371 const char *section,
1372 unsigned section_line,
1383 CalendarSpec *c = NULL;
1390 if (isempty(rvalue)) {
1391 /* Empty assignment resets list */
1392 timer_free_values(t);
1396 b = timer_base_from_string(lvalue);
1398 log_syntax(unit, LOG_ERR, filename, line, -b,
1399 "Failed to parse timer base, ignoring: %s", lvalue);
1403 if (b == TIMER_CALENDAR) {
1404 if (calendar_spec_from_string(rvalue, &c) < 0) {
1405 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1406 "Failed to parse calendar specification, ignoring: %s",
1411 if (parse_sec(rvalue, &u) < 0) {
1412 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1413 "Failed to parse timer value, ignoring: %s",
1419 v = new0(TimerValue, 1);
1425 v->calendar_spec = c;
1427 LIST_PREPEND(value, t->values, v);
1432 int config_parse_trigger_unit(
1434 const char *filename,
1436 const char *section,
1437 unsigned section_line,
1444 _cleanup_free_ char *p = NULL;
1454 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1455 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1456 "Multiple units to trigger specified, ignoring: %s", rvalue);
1460 r = unit_name_printf(u, rvalue, &p);
1462 log_syntax(unit, LOG_ERR, filename, line, -r,
1463 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1465 type = unit_name_to_type(p ?: rvalue);
1467 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1468 "Unit type not valid, ignoring: %s", rvalue);
1472 if (type == u->type) {
1473 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1474 "Trigger cannot be of same type, ignoring: %s", rvalue);
1478 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1480 log_syntax(unit, LOG_ERR, filename, line, -r,
1481 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1488 int config_parse_path_spec(const char *unit,
1489 const char *filename,
1491 const char *section,
1492 unsigned section_line,
1502 _cleanup_free_ char *k = NULL;
1510 if (isempty(rvalue)) {
1511 /* Empty assignment clears list */
1516 b = path_type_from_string(lvalue);
1518 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1519 "Failed to parse path type, ignoring: %s", lvalue);
1523 r = unit_full_printf(UNIT(p), rvalue, &k);
1529 log_syntax(unit, LOG_ERR, filename, line, -r,
1530 "Failed to resolve unit specifiers on %s. Ignoring.",
1534 if (!path_is_absolute(k)) {
1535 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1536 "Path is not absolute, ignoring: %s", k);
1540 s = new0(PathSpec, 1);
1545 s->path = path_kill_slashes(k);
1550 LIST_PREPEND(spec, p->specs, s);
1555 int config_parse_socket_service(const char *unit,
1556 const char *filename,
1558 const char *section,
1559 unsigned section_line,
1566 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1570 _cleanup_free_ char *p = NULL;
1577 r = unit_name_printf(UNIT(s), rvalue, &p);
1579 log_syntax(unit, LOG_ERR, filename, line, -r,
1580 "Failed to resolve specifiers, ignoring: %s", rvalue);
1584 if (!endswith(p, ".service")) {
1585 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1586 "Unit must be of type service, ignoring: %s", rvalue);
1590 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1592 log_syntax(unit, LOG_ERR, filename, line, -r,
1593 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1597 unit_ref_set(&s->service, x);
1602 int config_parse_service_sockets(const char *unit,
1603 const char *filename,
1605 const char *section,
1606 unsigned section_line,
1615 const char *word, *state;
1623 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1624 _cleanup_free_ char *t = NULL, *k = NULL;
1626 t = strndup(word, l);
1630 r = unit_name_printf(UNIT(s), t, &k);
1632 log_syntax(unit, LOG_ERR, filename, line, -r,
1633 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1635 if (!endswith(k ?: t, ".socket")) {
1636 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1637 "Unit must be of type socket, ignoring: %s", k ?: t);
1641 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1643 log_syntax(unit, LOG_ERR, filename, line, -r,
1644 "Failed to add dependency on %s, ignoring: %s",
1645 k ?: t, strerror(-r));
1647 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1651 if (!isempty(state))
1652 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1653 "Trailing garbage, ignoring.");
1658 int config_parse_service_timeout(const char *unit,
1659 const char *filename,
1661 const char *section,
1662 unsigned section_line,
1669 Service *s = userdata;
1677 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1678 rvalue, data, userdata);
1682 if (streq(lvalue, "TimeoutSec")) {
1683 s->start_timeout_defined = true;
1684 s->timeout_stop_usec = s->timeout_start_usec;
1685 } else if (streq(lvalue, "TimeoutStartSec"))
1686 s->start_timeout_defined = true;
1691 int config_parse_busname_service(
1693 const char *filename,
1695 const char *section,
1696 unsigned section_line,
1703 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1707 _cleanup_free_ char *p = NULL;
1714 r = unit_name_printf(UNIT(n), rvalue, &p);
1716 log_syntax(unit, LOG_ERR, filename, line, -r,
1717 "Failed to resolve specifiers, ignoring: %s", rvalue);
1721 if (!endswith(p, ".service")) {
1722 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1723 "Unit must be of type service, ignoring: %s", rvalue);
1727 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1729 log_syntax(unit, LOG_ERR, filename, line, -r,
1730 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1734 unit_ref_set(&n->service, x);
1739 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, busname_policy_access, BusNamePolicyAccess, "Failed to parse bus name policy access");
1741 int config_parse_bus_policy(
1743 const char *filename,
1745 const char *section,
1746 unsigned section_line,
1753 _cleanup_free_ BusNamePolicy *p = NULL;
1754 _cleanup_free_ char *id_str = NULL;
1755 BusName *busname = data;
1763 p = new0(BusNamePolicy, 1);
1767 if (streq(lvalue, "AllowUser"))
1768 p->type = BUSNAME_POLICY_TYPE_USER;
1769 else if (streq(lvalue, "AllowGroup"))
1770 p->type = BUSNAME_POLICY_TYPE_GROUP;
1772 assert_not_reached("Unknown lvalue");
1774 id_str = strdup(rvalue);
1778 access_str = strpbrk(id_str, WHITESPACE);
1780 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1781 "Invalid busname policy value '%s'", rvalue);
1787 access_str += strspn(access_str, WHITESPACE);
1789 p->access = busname_policy_access_from_string(access_str);
1790 if (p->access < 0) {
1791 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1792 "Invalid busname policy access type '%s'", access_str);
1799 LIST_PREPEND(policy, busname->policy, p);
1805 int config_parse_unit_env_file(const char *unit,
1806 const char *filename,
1808 const char *section,
1809 unsigned section_line,
1818 _cleanup_free_ char *n = NULL;
1827 if (isempty(rvalue)) {
1828 /* Empty assignment frees the list */
1834 r = unit_full_printf(u, rvalue, &n);
1836 log_syntax(unit, LOG_ERR, filename, line, -r,
1837 "Failed to resolve specifiers, ignoring: %s", rvalue);
1840 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1841 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1842 "Path '%s' is not absolute, ignoring.", s);
1846 r = strv_extend(env, s);
1853 int config_parse_environ(const char *unit,
1854 const char *filename,
1856 const char *section,
1857 unsigned section_line,
1866 const char *word, *state;
1868 _cleanup_free_ char *k = NULL;
1876 if (isempty(rvalue)) {
1877 /* Empty assignment resets the list */
1884 r = unit_full_printf(u, rvalue, &k);
1886 log_syntax(unit, LOG_ERR, filename, line, -r,
1887 "Failed to resolve specifiers, ignoring: %s", rvalue);
1895 FOREACH_WORD_QUOTED(word, l, k, state) {
1896 _cleanup_free_ char *n;
1899 n = cunescape_length(word, l);
1903 if (!env_assignment_is_valid(n)) {
1904 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1905 "Invalid environment assignment, ignoring: %s", rvalue);
1909 x = strv_env_set(*env, n);
1916 if (!isempty(state))
1917 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1918 "Trailing garbage, ignoring.");
1923 int config_parse_ip_tos(const char *unit,
1924 const char *filename,
1926 const char *section,
1927 unsigned section_line,
1934 int *ip_tos = data, x;
1941 x = ip_tos_from_string(rvalue);
1943 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1944 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1952 int config_parse_unit_condition_path(const char *unit,
1953 const char *filename,
1955 const char *section,
1956 unsigned section_line,
1963 ConditionType cond = ltype;
1965 bool trigger, negate;
1967 _cleanup_free_ char *p = NULL;
1975 if (isempty(rvalue)) {
1976 /* Empty assignment resets the list */
1977 condition_free_list(u->conditions);
1978 u->conditions = NULL;
1982 trigger = rvalue[0] == '|';
1986 negate = rvalue[0] == '!';
1990 r = unit_full_printf(u, rvalue, &p);
1992 log_syntax(unit, LOG_ERR, filename, line, -r,
1993 "Failed to resolve specifiers, ignoring: %s", rvalue);
2000 if (!path_is_absolute(p)) {
2001 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2002 "Path in condition not absolute, ignoring: %s", p);
2006 c = condition_new(cond, p, trigger, negate);
2010 LIST_PREPEND(conditions, u->conditions, c);
2014 int config_parse_unit_condition_string(const char *unit,
2015 const char *filename,
2017 const char *section,
2018 unsigned section_line,
2025 ConditionType cond = ltype;
2027 bool trigger, negate;
2029 _cleanup_free_ char *s = NULL;
2037 if (isempty(rvalue)) {
2038 /* Empty assignment resets the list */
2039 condition_free_list(u->conditions);
2040 u->conditions = NULL;
2044 trigger = rvalue[0] == '|';
2048 negate = rvalue[0] == '!';
2052 r = unit_full_printf(u, rvalue, &s);
2054 log_syntax(unit, LOG_ERR, filename, line, -r,
2055 "Failed to resolve specifiers, ignoring: %s", rvalue);
2062 c = condition_new(cond, s, trigger, negate);
2066 LIST_PREPEND(conditions, u->conditions, c);
2070 int config_parse_unit_condition_null(const char *unit,
2071 const char *filename,
2073 const char *section,
2074 unsigned section_line,
2083 bool trigger, negate;
2091 if (isempty(rvalue)) {
2092 /* Empty assignment resets the list */
2093 condition_free_list(u->conditions);
2094 u->conditions = NULL;
2098 trigger = rvalue[0] == '|';
2102 negate = rvalue[0] == '!';
2106 b = parse_boolean(rvalue);
2108 log_syntax(unit, LOG_ERR, filename, line, -b,
2109 "Failed to parse boolean value in condition, ignoring: %s",
2117 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2121 LIST_PREPEND(conditions, u->conditions, c);
2125 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2126 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2128 int config_parse_unit_requires_mounts_for(
2130 const char *filename,
2132 const char *section,
2133 unsigned section_line,
2141 const char *word, *state;
2149 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2151 _cleanup_free_ char *n;
2153 n = strndup(word, l);
2157 if (!utf8_is_valid(n)) {
2158 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2162 r = unit_require_mounts_for(u, n);
2164 log_syntax(unit, LOG_ERR, filename, line, -r,
2165 "Failed to add required mount for, ignoring: %s", rvalue);
2169 if (!isempty(state))
2170 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2171 "Trailing garbage, ignoring.");
2176 int config_parse_documentation(const char *unit,
2177 const char *filename,
2179 const char *section,
2180 unsigned section_line,
2196 if (isempty(rvalue)) {
2197 /* Empty assignment resets the list */
2198 strv_free(u->documentation);
2199 u->documentation = NULL;
2203 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2204 rvalue, data, userdata);
2208 for (a = b = u->documentation; a && *a; a++) {
2210 if (is_valid_documentation_url(*a))
2213 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2214 "Invalid URL, ignoring: %s", *a);
2225 int config_parse_syscall_filter(
2227 const char *filename,
2229 const char *section,
2230 unsigned section_line,
2237 static const char default_syscalls[] =
2244 ExecContext *c = data;
2246 bool invert = false;
2247 const char *word, *state;
2256 if (isempty(rvalue)) {
2257 /* Empty assignment resets the list */
2258 set_free(c->syscall_filter);
2259 c->syscall_filter = NULL;
2260 c->syscall_whitelist = false;
2264 if (rvalue[0] == '~') {
2269 if (!c->syscall_filter) {
2270 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2271 if (!c->syscall_filter)
2275 /* Allow everything but the ones listed */
2276 c->syscall_whitelist = false;
2280 /* Allow nothing but the ones listed */
2281 c->syscall_whitelist = true;
2283 /* Accept default syscalls if we are on a whitelist */
2284 NULSTR_FOREACH(i, default_syscalls) {
2287 id = seccomp_syscall_resolve_name(i);
2291 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2300 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2301 _cleanup_free_ char *t = NULL;
2304 t = strndup(word, l);
2308 id = seccomp_syscall_resolve_name(t);
2310 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2311 "Failed to parse system call, ignoring: %s", t);
2315 /* If we previously wanted to forbid a syscall and now
2316 * we want to allow it, then remove it from the list
2318 if (!invert == c->syscall_whitelist) {
2319 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2325 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2327 if (!isempty(state))
2328 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2329 "Trailing garbage, ignoring.");
2331 /* Turn on NNP, but only if it wasn't configured explicitly
2332 * before, and only if we are in user mode. */
2333 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2334 c->no_new_privileges = true;
2339 int config_parse_syscall_archs(
2341 const char *filename,
2343 const char *section,
2344 unsigned section_line,
2352 const char *word, *state;
2356 if (isempty(rvalue)) {
2362 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2366 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2367 _cleanup_free_ char *t = NULL;
2370 t = strndup(word, l);
2374 r = seccomp_arch_from_string(t, &a);
2376 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2377 "Failed to parse system call architecture, ignoring: %s", t);
2381 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2387 if (!isempty(state))
2388 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2389 "Trailing garbage, ignoring.");
2394 int config_parse_syscall_errno(
2396 const char *filename,
2398 const char *section,
2399 unsigned section_line,
2406 ExecContext *c = data;
2413 if (isempty(rvalue)) {
2414 /* Empty assignment resets to KILL */
2415 c->syscall_errno = 0;
2419 e = errno_from_name(rvalue);
2421 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2422 "Failed to parse error number, ignoring: %s", rvalue);
2426 c->syscall_errno = e;
2430 int config_parse_address_families(
2432 const char *filename,
2434 const char *section,
2435 unsigned section_line,
2442 ExecContext *c = data;
2444 bool invert = false;
2445 const char *word, *state;
2454 if (isempty(rvalue)) {
2455 /* Empty assignment resets the list */
2456 set_free(c->address_families);
2457 c->address_families = NULL;
2458 c->address_families_whitelist = false;
2462 if (rvalue[0] == '~') {
2467 if (!c->address_families) {
2468 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2469 if (!c->address_families)
2472 c->address_families_whitelist = !invert;
2475 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2476 _cleanup_free_ char *t = NULL;
2479 t = strndup(word, l);
2483 af = af_from_name(t);
2485 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2486 "Failed to parse address family, ignoring: %s", t);
2490 /* If we previously wanted to forbid an address family and now
2491 * we want to allow it, then remove it from the list
2493 if (!invert == c->address_families_whitelist) {
2494 r = set_put(c->address_families, INT_TO_PTR(af));
2500 set_remove(c->address_families, INT_TO_PTR(af));
2502 if (!isempty(state))
2503 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2504 "Trailing garbage, ignoring.");
2510 int config_parse_unit_slice(
2512 const char *filename,
2514 const char *section,
2515 unsigned section_line,
2522 _cleanup_free_ char *k = NULL;
2523 Unit *u = userdata, *slice;
2531 r = unit_name_printf(u, rvalue, &k);
2533 log_syntax(unit, LOG_ERR, filename, line, -r,
2534 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2541 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2543 log_syntax(unit, LOG_ERR, filename, line, -r,
2544 "Failed to load slice unit %s. Ignoring.", k);
2548 if (slice->type != UNIT_SLICE) {
2549 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2550 "Slice unit %s is not a slice. Ignoring.", k);
2554 unit_ref_set(&u->slice, slice);
2558 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2560 int config_parse_cpu_shares(
2562 const char *filename,
2564 const char *section,
2565 unsigned section_line,
2572 unsigned long *shares = data, lu;
2579 if (isempty(rvalue)) {
2580 *shares = (unsigned long) -1;
2584 r = safe_atolu(rvalue, &lu);
2585 if (r < 0 || lu <= 0) {
2586 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2587 "CPU shares '%s' invalid. Ignoring.", rvalue);
2595 int config_parse_cpu_quota(
2597 const char *filename,
2599 const char *section,
2600 unsigned section_line,
2607 CGroupContext *c = data;
2614 if (isempty(rvalue)) {
2615 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2619 if (!endswith(rvalue, "%")) {
2621 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2622 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2626 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2627 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2628 "CPU quota '%s' invalid. Ignoring.", rvalue);
2632 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2637 int config_parse_memory_limit(
2639 const char *filename,
2641 const char *section,
2642 unsigned section_line,
2649 CGroupContext *c = data;
2653 if (isempty(rvalue)) {
2654 c->memory_limit = (uint64_t) -1;
2658 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2660 r = parse_size(rvalue, 1024, &bytes);
2662 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2663 "Memory limit '%s' invalid. Ignoring.", rvalue);
2667 c->memory_limit = (uint64_t) bytes;
2671 int config_parse_device_allow(
2673 const char *filename,
2675 const char *section,
2676 unsigned section_line,
2683 _cleanup_free_ char *path = NULL;
2684 CGroupContext *c = data;
2685 CGroupDeviceAllow *a;
2689 if (isempty(rvalue)) {
2690 while (c->device_allow)
2691 cgroup_context_free_device_allow(c, c->device_allow);
2696 n = strcspn(rvalue, WHITESPACE);
2697 path = strndup(rvalue, n);
2701 if (!startswith(path, "/dev/") &&
2702 !startswith(path, "block-") &&
2703 !startswith(path, "char-")) {
2704 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2705 "Invalid device node path '%s'. Ignoring.", path);
2709 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2713 if (!in_charset(m, "rwm")) {
2714 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2715 "Invalid device rights '%s'. Ignoring.", m);
2719 a = new0(CGroupDeviceAllow, 1);
2725 a->r = !!strchr(m, 'r');
2726 a->w = !!strchr(m, 'w');
2727 a->m = !!strchr(m, 'm');
2729 LIST_PREPEND(device_allow, c->device_allow, a);
2733 int config_parse_blockio_weight(
2735 const char *filename,
2737 const char *section,
2738 unsigned section_line,
2745 unsigned long *weight = data, lu;
2752 if (isempty(rvalue)) {
2753 *weight = (unsigned long) -1;
2757 r = safe_atolu(rvalue, &lu);
2758 if (r < 0 || lu < 10 || lu > 1000) {
2759 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2760 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2768 int config_parse_blockio_device_weight(
2770 const char *filename,
2772 const char *section,
2773 unsigned section_line,
2780 _cleanup_free_ char *path = NULL;
2781 CGroupBlockIODeviceWeight *w;
2782 CGroupContext *c = data;
2792 if (isempty(rvalue)) {
2793 while (c->blockio_device_weights)
2794 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2799 n = strcspn(rvalue, WHITESPACE);
2800 weight = rvalue + n;
2802 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2803 "Expected block device and device weight. Ignoring.");
2807 path = strndup(rvalue, n);
2811 if (!path_startswith(path, "/dev")) {
2812 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2813 "Invalid device node path '%s'. Ignoring.", path);
2817 weight += strspn(weight, WHITESPACE);
2818 r = safe_atolu(weight, &lu);
2819 if (r < 0 || lu < 10 || lu > 1000) {
2820 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2821 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2825 w = new0(CGroupBlockIODeviceWeight, 1);
2834 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2838 int config_parse_blockio_bandwidth(
2840 const char *filename,
2842 const char *section,
2843 unsigned section_line,
2850 _cleanup_free_ char *path = NULL;
2851 CGroupBlockIODeviceBandwidth *b;
2852 CGroupContext *c = data;
2853 const char *bandwidth;
2863 read = streq("BlockIOReadBandwidth", lvalue);
2865 if (isempty(rvalue)) {
2866 CGroupBlockIODeviceBandwidth *next;
2868 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2869 if (b->read == read)
2870 cgroup_context_free_blockio_device_bandwidth(c, b);
2875 n = strcspn(rvalue, WHITESPACE);
2876 bandwidth = rvalue + n;
2877 bandwidth += strspn(bandwidth, WHITESPACE);
2880 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2881 "Expected space separated pair of device node and bandwidth. Ignoring.");
2885 path = strndup(rvalue, n);
2889 if (!path_startswith(path, "/dev")) {
2890 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2891 "Invalid device node path '%s'. Ignoring.", path);
2895 r = parse_size(bandwidth, 1000, &bytes);
2896 if (r < 0 || bytes <= 0) {
2897 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2898 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2902 b = new0(CGroupBlockIODeviceBandwidth, 1);
2908 b->bandwidth = (uint64_t) bytes;
2911 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2916 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2918 int config_parse_job_mode_isolate(
2920 const char *filename,
2922 const char *section,
2923 unsigned section_line,
2937 r = parse_boolean(rvalue);
2939 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2940 "Failed to parse boolean, ignoring: %s", rvalue);
2944 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2948 int config_parse_personality(
2950 const char *filename,
2952 const char *section,
2953 unsigned section_line,
2960 unsigned long *personality = data, p;
2965 assert(personality);
2967 p = personality_from_string(rvalue);
2968 if (p == 0xffffffffUL) {
2969 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2970 "Failed to parse personality, ignoring: %s", rvalue);
2978 int config_parse_runtime_directory(
2980 const char *filename,
2982 const char *section,
2983 unsigned section_line,
2991 const char *word, *state;
3000 if (isempty(rvalue)) {
3001 /* Empty assignment resets the list */
3007 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3008 _cleanup_free_ char *n;
3010 n = strndup(word, l);
3014 if (!filename_is_safe(n)) {
3015 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3016 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3020 r = strv_push(rt, n);
3026 if (!isempty(state))
3027 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3028 "Trailing garbage, ignoring.");
3033 int config_parse_set_status(
3035 const char *filename,
3037 const char *section,
3038 unsigned section_line,
3046 const char *word, *state;
3048 ExitStatusSet *status_set = data;
3055 /* Empty assignment resets the list */
3056 if (isempty(rvalue)) {
3057 exit_status_set_free(status_set);
3061 FOREACH_WORD(word, l, rvalue, state) {
3062 _cleanup_free_ char *temp;
3065 temp = strndup(word, l);
3069 r = safe_atoi(temp, &val);
3071 val = signal_from_string_try_harder(temp);
3074 log_syntax(unit, LOG_ERR, filename, line, -val,
3075 "Failed to parse value, ignoring: %s", word);
3079 if (val < 0 || val > 255) {
3080 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3081 "Value %d is outside range 0-255, ignoring", val);
3086 r = set_ensure_allocated(&status_set->status, NULL, NULL);
3090 r = set_put(status_set->status, INT_TO_PTR(val));
3092 log_syntax(unit, LOG_ERR, filename, line, -r,
3093 "Unable to store: %s", word);
3097 if (!isempty(state))
3098 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3099 "Trailing garbage, ignoring.");
3104 int config_parse_namespace_path_strv(
3106 const char *filename,
3108 const char *section,
3109 unsigned section_line,
3117 const char *word, *state;
3126 if (isempty(rvalue)) {
3127 /* Empty assignment resets the list */
3133 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3134 _cleanup_free_ char *n;
3137 n = strndup(word, l);
3141 if (!utf8_is_valid(n)) {
3142 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3146 offset = n[0] == '-';
3147 if (!path_is_absolute(n + offset)) {
3148 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3149 "Not an absolute path, ignoring: %s", rvalue);
3153 path_kill_slashes(n);
3155 r = strv_push(sv, n);
3161 if (!isempty(state))
3162 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3163 "Trailing garbage, ignoring.");
3168 int config_parse_no_new_privileges(
3170 const char *filename,
3172 const char *section,
3173 unsigned section_line,
3180 ExecContext *c = data;
3188 k = parse_boolean(rvalue);
3190 log_syntax(unit, LOG_ERR, filename, line, -k,
3191 "Failed to parse boolean value, ignoring: %s", rvalue);
3195 c->no_new_privileges = !!k;
3196 c->no_new_privileges_set = true;
3201 int config_parse_protect_home(
3203 const char *filename,
3205 const char *section,
3206 unsigned section_line,
3213 ExecContext *c = data;
3221 /* Our enum shall be a superset of booleans, hence first try
3222 * to parse as as boolean, and then as enum */
3224 k = parse_boolean(rvalue);
3226 c->protect_home = PROTECT_HOME_YES;
3228 c->protect_home = PROTECT_HOME_NO;
3232 h = protect_home_from_string(rvalue);
3234 log_syntax(unit, LOG_ERR, filename, line, -h,
3235 "Failed to parse protect home value, ignoring: %s", rvalue);
3239 c->protect_home = h;
3245 int config_parse_protect_system(
3247 const char *filename,
3249 const char *section,
3250 unsigned section_line,
3257 ExecContext *c = data;
3265 /* Our enum shall be a superset of booleans, hence first try
3266 * to parse as as boolean, and then as enum */
3268 k = parse_boolean(rvalue);
3270 c->protect_system = PROTECT_SYSTEM_YES;
3272 c->protect_system = PROTECT_SYSTEM_NO;
3276 s = protect_system_from_string(rvalue);
3278 log_syntax(unit, LOG_ERR, filename, line, -s,
3279 "Failed to parse protect system value, ignoring: %s", rvalue);
3283 c->protect_system = s;
3289 #define FOLLOW_MAX 8
3291 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3302 /* This will update the filename pointer if the loaded file is
3303 * reached by a symlink. The old string will be freed. */
3306 char *target, *name;
3308 if (c++ >= FOLLOW_MAX)
3311 path_kill_slashes(*filename);
3313 /* Add the file name we are currently looking at to
3314 * the names of this unit, but only if it is a valid
3316 name = basename(*filename);
3318 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3320 id = set_get(names, name);
3326 r = set_consume(names, id);
3332 /* Try to open the file name, but don't if its a symlink */
3333 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3340 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3341 r = readlink_and_make_absolute(*filename, &target);
3349 f = fdopen(fd, "re");
3361 static int merge_by_names(Unit **u, Set *names, const char *id) {
3369 /* Let's try to add in all symlink names we found */
3370 while ((k = set_steal_first(names))) {
3372 /* First try to merge in the other name into our
3374 r = unit_merge_by_name(*u, k);
3378 /* Hmm, we couldn't merge the other unit into
3379 * ours? Then let's try it the other way
3382 other = manager_get_unit((*u)->manager, k);
3386 r = unit_merge(other, *u);
3389 return merge_by_names(u, names, NULL);
3397 unit_choose_id(*u, id);
3405 static int load_from_path(Unit *u, const char *path) {
3407 _cleanup_set_free_free_ Set *symlink_names = NULL;
3408 _cleanup_fclose_ FILE *f = NULL;
3409 _cleanup_free_ char *filename = NULL;
3417 symlink_names = set_new(string_hash_func, string_compare_func);
3421 if (path_is_absolute(path)) {
3423 filename = strdup(path);
3427 r = open_follow(&filename, &f, symlink_names, &id);
3439 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3441 /* Instead of opening the path right away, we manually
3442 * follow all symlinks and add their name to our unit
3443 * name set while doing so */
3444 filename = path_make_absolute(path, *p);
3448 if (u->manager->unit_path_cache &&
3449 !set_get(u->manager->unit_path_cache, filename))
3452 r = open_follow(&filename, &f, symlink_names, &id);
3461 /* Empty the symlink names for the next run */
3462 set_clear_free(symlink_names);
3471 /* Hmm, no suitable file found? */
3475 r = merge_by_names(&merged, symlink_names, id);
3480 u->load_state = UNIT_MERGED;
3484 if (fstat(fileno(f), &st) < 0)
3487 if (null_or_empty(&st))
3488 u->load_state = UNIT_MASKED;
3490 u->load_state = UNIT_LOADED;
3492 /* Now, parse the file contents */
3493 r = config_parse(u->id, filename, f,
3494 UNIT_VTABLE(u)->sections,
3495 config_item_perf_lookup, load_fragment_gperf_lookup,
3496 false, true, false, u);
3501 free(u->fragment_path);
3502 u->fragment_path = filename;
3505 u->fragment_mtime = timespec_load(&st.st_mtim);
3507 if (u->source_path) {
3508 if (stat(u->source_path, &st) >= 0)
3509 u->source_mtime = timespec_load(&st.st_mtim);
3511 u->source_mtime = 0;
3517 int unit_load_fragment(Unit *u) {
3523 assert(u->load_state == UNIT_STUB);
3526 /* First, try to find the unit under its id. We always look
3527 * for unit files in the default directories, to make it easy
3528 * to override things by placing things in /etc/systemd/system */
3529 r = load_from_path(u, u->id);
3533 /* Try to find an alias we can load this with */
3534 if (u->load_state == UNIT_STUB)
3535 SET_FOREACH(t, u->names, i) {
3540 r = load_from_path(u, t);
3544 if (u->load_state != UNIT_STUB)
3548 /* And now, try looking for it under the suggested (originally linked) path */
3549 if (u->load_state == UNIT_STUB && u->fragment_path) {
3551 r = load_from_path(u, u->fragment_path);
3555 if (u->load_state == UNIT_STUB) {
3556 /* Hmm, this didn't work? Then let's get rid
3557 * of the fragment path stored for us, so that
3558 * we don't point to an invalid location. */
3559 free(u->fragment_path);
3560 u->fragment_path = NULL;
3564 /* Look for a template */
3565 if (u->load_state == UNIT_STUB && u->instance) {
3566 _cleanup_free_ char *k;
3568 k = unit_name_template(u->id);
3572 r = load_from_path(u, k);
3576 if (u->load_state == UNIT_STUB)
3577 SET_FOREACH(t, u->names, i) {
3578 _cleanup_free_ char *z = NULL;
3583 z = unit_name_template(t);
3587 r = load_from_path(u, z);
3591 if (u->load_state != UNIT_STUB)
3599 void unit_dump_config_items(FILE *f) {
3600 static const struct {
3601 const ConfigParserCallback callback;
3604 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3605 { config_parse_warn_compat, "NOTSUPPORTED" },
3607 { config_parse_int, "INTEGER" },
3608 { config_parse_unsigned, "UNSIGNED" },
3609 { config_parse_iec_size, "SIZE" },
3610 { config_parse_iec_off, "SIZE" },
3611 { config_parse_si_size, "SIZE" },
3612 { config_parse_bool, "BOOLEAN" },
3613 { config_parse_string, "STRING" },
3614 { config_parse_path, "PATH" },
3615 { config_parse_unit_path_printf, "PATH" },
3616 { config_parse_strv, "STRING [...]" },
3617 { config_parse_exec_nice, "NICE" },
3618 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3619 { config_parse_exec_io_class, "IOCLASS" },
3620 { config_parse_exec_io_priority, "IOPRIORITY" },
3621 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3622 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3623 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3624 { config_parse_mode, "MODE" },
3625 { config_parse_unit_env_file, "FILE" },
3626 { config_parse_output, "OUTPUT" },
3627 { config_parse_input, "INPUT" },
3628 { config_parse_log_facility, "FACILITY" },
3629 { config_parse_log_level, "LEVEL" },
3630 { config_parse_exec_capabilities, "CAPABILITIES" },
3631 { config_parse_exec_secure_bits, "SECUREBITS" },
3632 { config_parse_bounding_set, "BOUNDINGSET" },
3633 { config_parse_limit, "LIMIT" },
3634 { config_parse_unit_deps, "UNIT [...]" },
3635 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3636 { config_parse_service_type, "SERVICETYPE" },
3637 { config_parse_service_restart, "SERVICERESTART" },
3638 #ifdef HAVE_SYSV_COMPAT
3639 { config_parse_sysv_priority, "SYSVPRIORITY" },
3641 { config_parse_kill_mode, "KILLMODE" },
3642 { config_parse_kill_signal, "SIGNAL" },
3643 { config_parse_socket_listen, "SOCKET [...]" },
3644 { config_parse_socket_bind, "SOCKETBIND" },
3645 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3646 { config_parse_sec, "SECONDS" },
3647 { config_parse_nsec, "NANOSECONDS" },
3648 { config_parse_namespace_path_strv, "PATH [...]" },
3649 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3650 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3651 { config_parse_unit_string_printf, "STRING" },
3652 { config_parse_trigger_unit, "UNIT" },
3653 { config_parse_timer, "TIMER" },
3654 { config_parse_path_spec, "PATH" },
3655 { config_parse_notify_access, "ACCESS" },
3656 { config_parse_ip_tos, "TOS" },
3657 { config_parse_unit_condition_path, "CONDITION" },
3658 { config_parse_unit_condition_string, "CONDITION" },
3659 { config_parse_unit_condition_null, "CONDITION" },
3660 { config_parse_unit_slice, "SLICE" },
3661 { config_parse_documentation, "URL" },
3662 { config_parse_service_timeout, "SECONDS" },
3663 { config_parse_failure_action, "ACTION" },
3664 { config_parse_set_status, "STATUS" },
3665 { config_parse_service_sockets, "SOCKETS" },
3666 { config_parse_environ, "ENVIRON" },
3668 { config_parse_syscall_filter, "SYSCALLS" },
3669 { config_parse_syscall_archs, "ARCHS" },
3670 { config_parse_syscall_errno, "ERRNO" },
3671 { config_parse_address_families, "FAMILIES" },
3673 { config_parse_cpu_shares, "SHARES" },
3674 { config_parse_memory_limit, "LIMIT" },
3675 { config_parse_device_allow, "DEVICE" },
3676 { config_parse_device_policy, "POLICY" },
3677 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3678 { config_parse_blockio_weight, "WEIGHT" },
3679 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3680 { config_parse_long, "LONG" },
3681 { config_parse_socket_service, "SERVICE" },
3683 { config_parse_exec_selinux_context, "LABEL" },
3685 { config_parse_job_mode, "MODE" },
3686 { config_parse_job_mode_isolate, "BOOLEAN" },
3687 { config_parse_personality, "PERSONALITY" },
3690 const char *prev = NULL;
3695 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3696 const char *rvalue = "OTHER", *lvalue;
3700 const ConfigPerfItem *p;
3702 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3704 dot = strchr(i, '.');
3705 lvalue = dot ? dot + 1 : i;
3709 if (!prev || !strneq(prev, i, prefix_len+1)) {
3713 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3716 for (j = 0; j < ELEMENTSOF(table); j++)
3717 if (p->parse == table[j].callback) {
3718 rvalue = table[j].rvalue;
3722 fprintf(f, "%s=%s\n", lvalue, rvalue);