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,
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);
100 int config_parse_unit_deps(const char *unit,
101 const char *filename,
104 unsigned section_line,
111 UnitDependency d = ltype;
113 const char *word, *state;
120 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
121 _cleanup_free_ char *t = NULL, *k = NULL;
124 t = strndup(word, l);
128 r = unit_name_printf(u, t, &k);
130 log_syntax(unit, LOG_ERR, filename, line, -r,
131 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
135 r = unit_add_dependency_by_name(u, d, k, NULL, true);
137 log_syntax(unit, LOG_ERR, filename, line, -r,
138 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
141 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
146 int config_parse_unit_string_printf(const char *unit,
147 const char *filename,
150 unsigned section_line,
158 _cleanup_free_ char *k = NULL;
166 r = unit_full_printf(u, rvalue, &k);
168 log_syntax(unit, LOG_ERR, filename, line, -r,
169 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
171 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
172 k ? k : rvalue, data, userdata);
175 int config_parse_unit_strv_printf(const char *unit,
176 const char *filename,
179 unsigned section_line,
187 _cleanup_free_ char *k = NULL;
195 r = unit_full_printf(u, rvalue, &k);
197 log_syntax(unit, LOG_ERR, filename, line, -r,
198 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
200 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
201 k ? k : rvalue, data, userdata);
204 int config_parse_unit_path_printf(const char *unit,
205 const char *filename,
208 unsigned section_line,
215 _cleanup_free_ char *k = NULL;
224 r = unit_full_printf(u, rvalue, &k);
226 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
230 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
233 int config_parse_unit_path_strv_printf(
235 const char *filename,
238 unsigned section_line,
246 const char *word, *state;
256 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
257 _cleanup_free_ char *k = NULL;
263 r = unit_full_printf(u, t, &k);
265 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
269 if (!utf8_is_valid(k)) {
270 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
274 if (!path_is_absolute(k)) {
275 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
279 path_kill_slashes(k);
288 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
293 int config_parse_socket_listen(const char *unit,
294 const char *filename,
297 unsigned section_line,
304 _cleanup_free_ SocketPort *p = NULL;
316 if (isempty(rvalue)) {
317 /* An empty assignment removes all ports */
318 socket_free_ports(s);
322 p = new0(SocketPort, 1);
326 if (ltype != SOCKET_SOCKET) {
329 r = unit_full_printf(UNIT(s), rvalue, &p->path);
331 p->path = strdup(rvalue);
335 log_syntax(unit, LOG_ERR, filename, line, -r,
336 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
339 path_kill_slashes(p->path);
341 } else if (streq(lvalue, "ListenNetlink")) {
342 _cleanup_free_ char *k = NULL;
344 p->type = SOCKET_SOCKET;
345 r = unit_full_printf(UNIT(s), rvalue, &k);
347 log_syntax(unit, LOG_ERR, filename, line, -r,
348 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
350 r = socket_address_parse_netlink(&p->address, k ?: rvalue);
352 log_syntax(unit, LOG_ERR, filename, line, -r,
353 "Failed to parse address value, ignoring: %s", rvalue);
358 _cleanup_free_ char *k = NULL;
360 p->type = SOCKET_SOCKET;
361 r = unit_full_printf(UNIT(s), rvalue, &k);
363 log_syntax(unit, LOG_ERR, filename, line, -r,
364 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
366 r = socket_address_parse(&p->address, k ? k : rvalue);
368 log_syntax(unit, LOG_ERR, filename, line, -r,
369 "Failed to parse address value, ignoring: %s", rvalue);
373 if (streq(lvalue, "ListenStream"))
374 p->address.type = SOCK_STREAM;
375 else if (streq(lvalue, "ListenDatagram"))
376 p->address.type = SOCK_DGRAM;
378 assert(streq(lvalue, "ListenSequentialPacket"));
379 p->address.type = SOCK_SEQPACKET;
382 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
383 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
384 "Address family not supported, ignoring: %s", rvalue);
393 LIST_FIND_TAIL(port, s->ports, tail);
394 LIST_INSERT_AFTER(port, s->ports, tail, p);
396 LIST_PREPEND(port, s->ports, p);
402 int config_parse_socket_bind(const char *unit,
403 const char *filename,
406 unsigned section_line,
414 SocketAddressBindIPv6Only b;
423 b = socket_address_bind_ipv6_only_from_string(rvalue);
427 r = parse_boolean(rvalue);
429 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
430 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
434 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
436 s->bind_ipv6_only = b;
441 int config_parse_exec_nice(const char *unit,
442 const char *filename,
445 unsigned section_line,
452 ExecContext *c = data;
460 r = safe_atoi(rvalue, &priority);
462 log_syntax(unit, LOG_ERR, filename, line, -r,
463 "Failed to parse nice priority, ignoring: %s. ", rvalue);
467 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
468 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
469 "Nice priority out of range, ignoring: %s", rvalue);
479 int config_parse_exec_oom_score_adjust(const char* unit,
480 const char *filename,
483 unsigned section_line,
490 ExecContext *c = data;
498 r = safe_atoi(rvalue, &oa);
500 log_syntax(unit, LOG_ERR, filename, line, -r,
501 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
505 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
506 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
507 "OOM score adjust value out of range, ignoring: %s", rvalue);
511 c->oom_score_adjust = oa;
512 c->oom_score_adjust_set = true;
517 int config_parse_exec(const char *unit,
518 const char *filename,
521 unsigned section_line,
528 ExecCommand **e = data, *nce;
540 if (isempty(rvalue)) {
541 /* An empty assignment resets the list */
542 exec_command_free_list(*e);
547 /* We accept an absolute path as first argument, or
548 * alternatively an absolute prefixed with @ to allow
549 * overriding of argv[0]. */
552 const char *word, *state;
554 bool honour_argv0 = false, ignore = false;
560 rvalue += strspn(rvalue, WHITESPACE);
565 for (i = 0; i < 2; i++) {
566 if (rvalue[0] == '-' && !ignore) {
571 if (rvalue[0] == '@' && !honour_argv0) {
577 if (*rvalue != '/') {
578 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
579 "Executable path is not absolute, ignoring: %s", rvalue);
584 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
585 if (strneq(word, ";", MAX(l, 1U)))
590 if (!isempty(state)) {
591 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
592 "Trailing garbage, ignoring.");
597 n = new(char*, k + !honour_argv0);
602 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
603 if (strneq(word, ";", MAX(l, 1U)))
605 else if (strneq(word, "\\;", MAX(l, 1U)))
608 if (honour_argv0 && word == rvalue) {
611 path = strndup(word, l);
617 if (!utf8_is_valid(path)) {
618 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
626 c = n[k++] = cunescape_length(word, l);
632 if (!utf8_is_valid(c)) {
633 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
643 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
644 "Invalid command line, ignoring: %s", rvalue);
657 assert(path_is_absolute(path));
659 nce = new0(ExecCommand, 1);
667 nce->ignore = ignore;
669 path_kill_slashes(nce->path);
671 exec_command_append_list(e, nce);
687 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
688 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
690 int config_parse_socket_bindtodevice(const char* unit,
691 const char *filename,
694 unsigned section_line,
709 if (rvalue[0] && !streq(rvalue, "*")) {
716 free(s->bind_to_device);
717 s->bind_to_device = n;
722 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
723 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
725 int config_parse_exec_io_class(const char *unit,
726 const char *filename,
729 unsigned section_line,
736 ExecContext *c = data;
744 x = ioprio_class_from_string(rvalue);
746 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
747 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
751 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
752 c->ioprio_set = true;
757 int config_parse_exec_io_priority(const char *unit,
758 const char *filename,
761 unsigned section_line,
768 ExecContext *c = data;
776 r = safe_atoi(rvalue, &i);
777 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
778 log_syntax(unit, LOG_ERR, filename, line, -r,
779 "Failed to parse IO priority, ignoring: %s", rvalue);
783 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
784 c->ioprio_set = true;
789 int config_parse_exec_cpu_sched_policy(const char *unit,
790 const char *filename,
793 unsigned section_line,
801 ExecContext *c = data;
809 x = sched_policy_from_string(rvalue);
811 log_syntax(unit, LOG_ERR, filename, line, -x,
812 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
816 c->cpu_sched_policy = x;
817 /* Moving to or from real-time policy? We need to adjust the priority */
818 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
819 c->cpu_sched_set = true;
824 int config_parse_exec_cpu_sched_prio(const char *unit,
825 const char *filename,
828 unsigned section_line,
835 ExecContext *c = data;
843 r = safe_atoi(rvalue, &i);
845 log_syntax(unit, LOG_ERR, filename, line, -r,
846 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
850 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
851 min = sched_get_priority_min(c->cpu_sched_policy);
852 max = sched_get_priority_max(c->cpu_sched_policy);
854 if (i < min || i > max) {
855 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
856 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
860 c->cpu_sched_priority = i;
861 c->cpu_sched_set = true;
866 int config_parse_exec_cpu_affinity(const char *unit,
867 const char *filename,
870 unsigned section_line,
877 ExecContext *c = data;
878 const char *word, *state;
886 if (isempty(rvalue)) {
887 /* An empty assignment resets the CPU list */
894 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
895 _cleanup_free_ char *t = NULL;
899 t = strndup(word, l);
903 r = safe_atou(t, &cpu);
906 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
911 if (r < 0 || cpu >= c->cpuset_ncpus) {
912 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
913 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
917 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
920 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
921 "Trailing garbage, ignoring.");
926 int config_parse_exec_capabilities(const char *unit,
927 const char *filename,
930 unsigned section_line,
937 ExecContext *c = data;
945 cap = cap_from_text(rvalue);
947 log_syntax(unit, LOG_ERR, filename, line, errno,
948 "Failed to parse capabilities, ignoring: %s", rvalue);
953 cap_free(c->capabilities);
954 c->capabilities = cap;
959 int config_parse_exec_secure_bits(const char *unit,
960 const char *filename,
963 unsigned section_line,
970 ExecContext *c = data;
972 const char *word, *state;
979 if (isempty(rvalue)) {
980 /* An empty assignment resets the field */
985 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
986 if (first_word(word, "keep-caps"))
987 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
988 else if (first_word(word, "keep-caps-locked"))
989 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
990 else if (first_word(word, "no-setuid-fixup"))
991 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
992 else if (first_word(word, "no-setuid-fixup-locked"))
993 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
994 else if (first_word(word, "noroot"))
995 c->secure_bits |= 1<<SECURE_NOROOT;
996 else if (first_word(word, "noroot-locked"))
997 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
999 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1000 "Failed to parse secure bits, ignoring: %s", rvalue);
1004 if (!isempty(state))
1005 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1006 "Invalid syntax, garbage at the end, ignoring.");
1011 int config_parse_bounding_set(const char *unit,
1012 const char *filename,
1014 const char *section,
1015 unsigned section_line,
1022 uint64_t *capability_bounding_set_drop = data;
1023 const char *word, *state;
1025 bool invert = false;
1033 if (rvalue[0] == '~') {
1038 /* Note that we store this inverted internally, since the
1039 * kernel wants it like this. But we actually expose it
1040 * non-inverted everywhere to have a fully normalized
1043 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1044 _cleanup_free_ char *t = NULL;
1048 t = strndup(word, l);
1052 r = cap_from_name(t, &cap);
1054 log_syntax(unit, LOG_ERR, filename, line, errno,
1055 "Failed to parse capability in bounding set, ignoring: %s", t);
1059 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1061 if (!isempty(state))
1062 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1063 "Trailing garbage, ignoring.");
1066 *capability_bounding_set_drop |= sum;
1068 *capability_bounding_set_drop |= ~sum;
1073 int config_parse_limit(const char *unit,
1074 const char *filename,
1076 const char *section,
1077 unsigned section_line,
1084 struct rlimit **rl = data;
1085 unsigned long long u;
1094 if (streq(rvalue, "infinity"))
1095 u = (unsigned long long) RLIM_INFINITY;
1099 r = safe_atollu(rvalue, &u);
1101 log_syntax(unit, LOG_ERR, filename, line, -r,
1102 "Failed to parse resource value, ignoring: %s", rvalue);
1108 *rl = new(struct rlimit, 1);
1113 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1117 #ifdef HAVE_SYSV_COMPAT
1118 int config_parse_sysv_priority(const char *unit,
1119 const char *filename,
1121 const char *section,
1122 unsigned section_line,
1129 int *priority = data;
1137 r = safe_atoi(rvalue, &i);
1138 if (r < 0 || i < 0) {
1139 log_syntax(unit, LOG_ERR, filename, line, -r,
1140 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1144 *priority = (int) i;
1149 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1151 int config_parse_kill_signal(const char *unit,
1152 const char *filename,
1154 const char *section,
1155 unsigned section_line,
1170 r = signal_from_string_try_harder(rvalue);
1172 log_syntax(unit, LOG_ERR, filename, line, -r,
1173 "Failed to parse kill signal, ignoring: %s", rvalue);
1181 int config_parse_exec_mount_flags(const char *unit,
1182 const char *filename,
1184 const char *section,
1185 unsigned section_line,
1192 ExecContext *c = data;
1193 const char *word, *state;
1195 unsigned long flags = 0;
1202 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1203 _cleanup_free_ char *t;
1205 t = strndup(word, l);
1209 if (streq(t, "shared"))
1211 else if (streq(t, "slave"))
1213 else if (streq(word, "private"))
1216 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1217 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1221 if (!isempty(state))
1222 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1223 "Trailing garbage, ignoring.");
1225 c->mount_flags = flags;
1229 int config_parse_exec_selinux_context(
1231 const char *filename,
1233 const char *section,
1234 unsigned section_line,
1241 ExecContext *c = data;
1252 if (isempty(rvalue)) {
1253 free(c->selinux_context);
1254 c->selinux_context = NULL;
1255 c->selinux_context_ignore = false;
1259 if (rvalue[0] == '-') {
1265 r = unit_name_printf(u, rvalue, &k);
1267 log_syntax(unit, LOG_ERR, filename, line, -r,
1268 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1272 free(c->selinux_context);
1273 c->selinux_context = k;
1274 c->selinux_context_ignore = ignore;
1279 int config_parse_exec_apparmor_profile(
1281 const char *filename,
1283 const char *section,
1284 unsigned section_line,
1291 ExecContext *c = data;
1302 if (isempty(rvalue)) {
1303 free(c->apparmor_profile);
1304 c->apparmor_profile = NULL;
1305 c->apparmor_profile_ignore = false;
1309 if (rvalue[0] == '-') {
1315 r = unit_name_printf(u, rvalue, &k);
1317 log_syntax(unit, LOG_ERR, filename, line, -r,
1318 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1322 free(c->apparmor_profile);
1323 c->apparmor_profile = k;
1324 c->apparmor_profile_ignore = ignore;
1329 int config_parse_exec_smack_process_label(
1331 const char *filename,
1333 const char *section,
1334 unsigned section_line,
1341 ExecContext *c = data;
1352 if (isempty(rvalue)) {
1353 free(c->smack_process_label);
1354 c->smack_process_label = NULL;
1355 c->smack_process_label_ignore = false;
1359 if (rvalue[0] == '-') {
1365 r = unit_name_printf(u, rvalue, &k);
1367 log_syntax(unit, LOG_ERR, filename, line, -r,
1368 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1372 free(c->smack_process_label);
1373 c->smack_process_label = k;
1374 c->smack_process_label_ignore = ignore;
1379 int config_parse_timer(const char *unit,
1380 const char *filename,
1382 const char *section,
1383 unsigned section_line,
1394 CalendarSpec *c = NULL;
1401 if (isempty(rvalue)) {
1402 /* Empty assignment resets list */
1403 timer_free_values(t);
1407 b = timer_base_from_string(lvalue);
1409 log_syntax(unit, LOG_ERR, filename, line, -b,
1410 "Failed to parse timer base, ignoring: %s", lvalue);
1414 if (b == TIMER_CALENDAR) {
1415 if (calendar_spec_from_string(rvalue, &c) < 0) {
1416 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1417 "Failed to parse calendar specification, ignoring: %s",
1422 if (parse_sec(rvalue, &u) < 0) {
1423 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1424 "Failed to parse timer value, ignoring: %s",
1430 v = new0(TimerValue, 1);
1432 calendar_spec_free(c);
1438 v->calendar_spec = c;
1440 LIST_PREPEND(value, t->values, v);
1445 int config_parse_trigger_unit(
1447 const char *filename,
1449 const char *section,
1450 unsigned section_line,
1457 _cleanup_free_ char *p = NULL;
1467 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1468 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1469 "Multiple units to trigger specified, ignoring: %s", rvalue);
1473 r = unit_name_printf(u, rvalue, &p);
1475 log_syntax(unit, LOG_ERR, filename, line, -r,
1476 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1478 type = unit_name_to_type(p ?: rvalue);
1480 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1481 "Unit type not valid, ignoring: %s", rvalue);
1485 if (type == u->type) {
1486 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1487 "Trigger cannot be of same type, ignoring: %s", rvalue);
1491 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1493 log_syntax(unit, LOG_ERR, filename, line, -r,
1494 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1501 int config_parse_path_spec(const char *unit,
1502 const char *filename,
1504 const char *section,
1505 unsigned section_line,
1515 _cleanup_free_ char *k = NULL;
1523 if (isempty(rvalue)) {
1524 /* Empty assignment clears list */
1529 b = path_type_from_string(lvalue);
1531 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1532 "Failed to parse path type, ignoring: %s", lvalue);
1536 r = unit_full_printf(UNIT(p), rvalue, &k);
1542 log_syntax(unit, LOG_ERR, filename, line, -r,
1543 "Failed to resolve unit specifiers on %s. Ignoring.",
1547 if (!path_is_absolute(k)) {
1548 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1549 "Path is not absolute, ignoring: %s", k);
1553 s = new0(PathSpec, 1);
1558 s->path = path_kill_slashes(k);
1563 LIST_PREPEND(spec, p->specs, s);
1568 int config_parse_socket_service(const char *unit,
1569 const char *filename,
1571 const char *section,
1572 unsigned section_line,
1579 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1583 _cleanup_free_ char *p = NULL;
1590 r = unit_name_printf(UNIT(s), rvalue, &p);
1592 log_syntax(unit, LOG_ERR, filename, line, -r,
1593 "Failed to resolve specifiers, ignoring: %s", rvalue);
1597 if (!endswith(p, ".service")) {
1598 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1599 "Unit must be of type service, ignoring: %s", rvalue);
1603 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1605 log_syntax(unit, LOG_ERR, filename, line, -r,
1606 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1610 unit_ref_set(&s->service, x);
1615 int config_parse_service_sockets(const char *unit,
1616 const char *filename,
1618 const char *section,
1619 unsigned section_line,
1628 const char *word, *state;
1636 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1637 _cleanup_free_ char *t = NULL, *k = NULL;
1639 t = strndup(word, l);
1643 r = unit_name_printf(UNIT(s), t, &k);
1645 log_syntax(unit, LOG_ERR, filename, line, -r,
1646 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1648 if (!endswith(k ?: t, ".socket")) {
1649 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1650 "Unit must be of type socket, ignoring: %s", k ?: t);
1654 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1656 log_syntax(unit, LOG_ERR, filename, line, -r,
1657 "Failed to add dependency on %s, ignoring: %s",
1658 k ?: t, strerror(-r));
1660 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1664 if (!isempty(state))
1665 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1666 "Trailing garbage, ignoring.");
1671 int config_parse_service_timeout(const char *unit,
1672 const char *filename,
1674 const char *section,
1675 unsigned section_line,
1682 Service *s = userdata;
1690 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1691 rvalue, data, userdata);
1695 if (streq(lvalue, "TimeoutSec")) {
1696 s->start_timeout_defined = true;
1697 s->timeout_stop_usec = s->timeout_start_usec;
1698 } else if (streq(lvalue, "TimeoutStartSec"))
1699 s->start_timeout_defined = true;
1704 int config_parse_busname_service(
1706 const char *filename,
1708 const char *section,
1709 unsigned section_line,
1716 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1720 _cleanup_free_ char *p = NULL;
1727 r = unit_name_printf(UNIT(n), rvalue, &p);
1729 log_syntax(unit, LOG_ERR, filename, line, -r,
1730 "Failed to resolve specifiers, ignoring: %s", rvalue);
1734 if (!endswith(p, ".service")) {
1735 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1736 "Unit must be of type service, ignoring: %s", rvalue);
1740 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1742 log_syntax(unit, LOG_ERR, filename, line, -r,
1743 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1747 unit_ref_set(&n->service, x);
1752 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1754 int config_parse_bus_policy(
1756 const char *filename,
1758 const char *section,
1759 unsigned section_line,
1766 _cleanup_free_ BusNamePolicy *p = NULL;
1767 _cleanup_free_ char *id_str = NULL;
1768 BusName *busname = data;
1776 p = new0(BusNamePolicy, 1);
1780 if (streq(lvalue, "AllowUser"))
1781 p->type = BUSNAME_POLICY_TYPE_USER;
1782 else if (streq(lvalue, "AllowGroup"))
1783 p->type = BUSNAME_POLICY_TYPE_GROUP;
1785 assert_not_reached("Unknown lvalue");
1787 id_str = strdup(rvalue);
1791 access_str = strpbrk(id_str, WHITESPACE);
1793 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1794 "Invalid busname policy value '%s'", rvalue);
1800 access_str += strspn(access_str, WHITESPACE);
1802 p->access = bus_policy_access_from_string(access_str);
1803 if (p->access < 0) {
1804 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1805 "Invalid busname policy access type '%s'", access_str);
1812 LIST_PREPEND(policy, busname->policy, p);
1818 int config_parse_bus_endpoint_policy(
1820 const char *filename,
1822 const char *section,
1823 unsigned section_line,
1830 _cleanup_free_ char *name = NULL;
1831 BusPolicyAccess access;
1832 ExecContext *c = data;
1841 name = strdup(rvalue);
1845 access_str = strpbrk(name, WHITESPACE);
1847 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1848 "Invalid endpoint policy value '%s'", rvalue);
1854 access_str += strspn(access_str, WHITESPACE);
1856 access = bus_policy_access_from_string(access_str);
1857 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1858 access >= _BUS_POLICY_ACCESS_MAX) {
1859 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1860 "Invalid endpoint policy access type '%s'", access_str);
1864 if (!c->bus_endpoint) {
1865 r = bus_endpoint_new(&c->bus_endpoint);
1871 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1874 int config_parse_unit_env_file(const char *unit,
1875 const char *filename,
1877 const char *section,
1878 unsigned section_line,
1887 _cleanup_free_ char *n = NULL;
1896 if (isempty(rvalue)) {
1897 /* Empty assignment frees the list */
1903 r = unit_full_printf(u, rvalue, &n);
1905 log_syntax(unit, LOG_ERR, filename, line, -r,
1906 "Failed to resolve specifiers, ignoring: %s", rvalue);
1909 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1910 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1911 "Path '%s' is not absolute, ignoring.", s);
1915 r = strv_extend(env, s);
1922 int config_parse_environ(const char *unit,
1923 const char *filename,
1925 const char *section,
1926 unsigned section_line,
1935 const char *word, *state;
1937 _cleanup_free_ char *k = NULL;
1945 if (isempty(rvalue)) {
1946 /* Empty assignment resets the list */
1953 r = unit_full_printf(u, rvalue, &k);
1955 log_syntax(unit, LOG_ERR, filename, line, -r,
1956 "Failed to resolve specifiers, ignoring: %s", rvalue);
1964 FOREACH_WORD_QUOTED(word, l, k, state) {
1965 _cleanup_free_ char *n;
1968 n = cunescape_length(word, l);
1972 if (!env_assignment_is_valid(n)) {
1973 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1974 "Invalid environment assignment, ignoring: %s", rvalue);
1978 x = strv_env_set(*env, n);
1985 if (!isempty(state))
1986 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1987 "Trailing garbage, ignoring.");
1992 int config_parse_ip_tos(const char *unit,
1993 const char *filename,
1995 const char *section,
1996 unsigned section_line,
2003 int *ip_tos = data, x;
2010 x = ip_tos_from_string(rvalue);
2012 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2013 "Failed to parse IP TOS value, ignoring: %s", rvalue);
2021 int config_parse_unit_condition_path(
2023 const char *filename,
2025 const char *section,
2026 unsigned section_line,
2033 _cleanup_free_ char *p = NULL;
2034 Condition **list = data, *c;
2035 ConditionType t = ltype;
2036 bool trigger, negate;
2045 if (isempty(rvalue)) {
2046 /* Empty assignment resets the list */
2047 condition_free_list(*list);
2052 trigger = rvalue[0] == '|';
2056 negate = rvalue[0] == '!';
2060 r = unit_full_printf(u, rvalue, &p);
2062 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2066 if (!path_is_absolute(p)) {
2067 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2071 c = condition_new(t, p, trigger, negate);
2075 LIST_PREPEND(conditions, *list, c);
2079 int config_parse_unit_condition_string(
2081 const char *filename,
2083 const char *section,
2084 unsigned section_line,
2091 _cleanup_free_ char *s = NULL;
2092 Condition **list = data, *c;
2093 ConditionType t = ltype;
2094 bool trigger, negate;
2103 if (isempty(rvalue)) {
2104 /* Empty assignment resets the list */
2105 condition_free_list(*list);
2110 trigger = rvalue[0] == '|';
2114 negate = rvalue[0] == '!';
2118 r = unit_full_printf(u, rvalue, &s);
2120 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2124 c = condition_new(t, s, trigger, negate);
2128 LIST_PREPEND(conditions, *list, c);
2132 int config_parse_unit_condition_null(
2134 const char *filename,
2136 const char *section,
2137 unsigned section_line,
2144 Condition **list = data, *c;
2145 bool trigger, negate;
2153 if (isempty(rvalue)) {
2154 /* Empty assignment resets the list */
2155 condition_free_list(*list);
2160 trigger = rvalue[0] == '|';
2164 negate = rvalue[0] == '!';
2168 b = parse_boolean(rvalue);
2170 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2177 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2181 LIST_PREPEND(conditions, *list, c);
2185 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2186 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2188 int config_parse_unit_requires_mounts_for(
2190 const char *filename,
2192 const char *section,
2193 unsigned section_line,
2201 const char *word, *state;
2209 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2211 _cleanup_free_ char *n;
2213 n = strndup(word, l);
2217 if (!utf8_is_valid(n)) {
2218 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2222 r = unit_require_mounts_for(u, n);
2224 log_syntax(unit, LOG_ERR, filename, line, -r,
2225 "Failed to add required mount for, ignoring: %s", rvalue);
2229 if (!isempty(state))
2230 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2231 "Trailing garbage, ignoring.");
2236 int config_parse_documentation(const char *unit,
2237 const char *filename,
2239 const char *section,
2240 unsigned section_line,
2256 if (isempty(rvalue)) {
2257 /* Empty assignment resets the list */
2258 strv_free(u->documentation);
2259 u->documentation = NULL;
2263 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2264 rvalue, data, userdata);
2268 for (a = b = u->documentation; a && *a; a++) {
2270 if (is_valid_documentation_url(*a))
2273 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2274 "Invalid URL, ignoring: %s", *a);
2285 int config_parse_syscall_filter(
2287 const char *filename,
2289 const char *section,
2290 unsigned section_line,
2297 static const char default_syscalls[] =
2304 ExecContext *c = data;
2306 bool invert = false;
2307 const char *word, *state;
2316 if (isempty(rvalue)) {
2317 /* Empty assignment resets the list */
2318 set_free(c->syscall_filter);
2319 c->syscall_filter = NULL;
2320 c->syscall_whitelist = false;
2324 if (rvalue[0] == '~') {
2329 if (!c->syscall_filter) {
2330 c->syscall_filter = set_new(NULL);
2331 if (!c->syscall_filter)
2335 /* Allow everything but the ones listed */
2336 c->syscall_whitelist = false;
2340 /* Allow nothing but the ones listed */
2341 c->syscall_whitelist = true;
2343 /* Accept default syscalls if we are on a whitelist */
2344 NULSTR_FOREACH(i, default_syscalls) {
2347 id = seccomp_syscall_resolve_name(i);
2351 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2360 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2361 _cleanup_free_ char *t = NULL;
2364 t = strndup(word, l);
2368 id = seccomp_syscall_resolve_name(t);
2370 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2371 "Failed to parse system call, ignoring: %s", t);
2375 /* If we previously wanted to forbid a syscall and now
2376 * we want to allow it, then remove it from the list
2378 if (!invert == c->syscall_whitelist) {
2379 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2385 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2387 if (!isempty(state))
2388 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2389 "Trailing garbage, ignoring.");
2391 /* Turn on NNP, but only if it wasn't configured explicitly
2392 * before, and only if we are in user mode. */
2393 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2394 c->no_new_privileges = true;
2399 int config_parse_syscall_archs(
2401 const char *filename,
2403 const char *section,
2404 unsigned section_line,
2412 const char *word, *state;
2416 if (isempty(rvalue)) {
2422 r = set_ensure_allocated(archs, NULL);
2426 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2427 _cleanup_free_ char *t = NULL;
2430 t = strndup(word, l);
2434 r = seccomp_arch_from_string(t, &a);
2436 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2437 "Failed to parse system call architecture, ignoring: %s", t);
2441 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2447 if (!isempty(state))
2448 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2449 "Trailing garbage, ignoring.");
2454 int config_parse_syscall_errno(
2456 const char *filename,
2458 const char *section,
2459 unsigned section_line,
2466 ExecContext *c = data;
2473 if (isempty(rvalue)) {
2474 /* Empty assignment resets to KILL */
2475 c->syscall_errno = 0;
2479 e = errno_from_name(rvalue);
2481 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2482 "Failed to parse error number, ignoring: %s", rvalue);
2486 c->syscall_errno = e;
2490 int config_parse_address_families(
2492 const char *filename,
2494 const char *section,
2495 unsigned section_line,
2502 ExecContext *c = data;
2503 bool invert = false;
2504 const char *word, *state;
2512 if (isempty(rvalue)) {
2513 /* Empty assignment resets the list */
2514 set_free(c->address_families);
2515 c->address_families = NULL;
2516 c->address_families_whitelist = false;
2520 if (rvalue[0] == '~') {
2525 if (!c->address_families) {
2526 c->address_families = set_new(NULL);
2527 if (!c->address_families)
2530 c->address_families_whitelist = !invert;
2533 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2534 _cleanup_free_ char *t = NULL;
2537 t = strndup(word, l);
2541 af = af_from_name(t);
2543 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2544 "Failed to parse address family, ignoring: %s", t);
2548 /* If we previously wanted to forbid an address family and now
2549 * we want to allow it, then remove it from the list
2551 if (!invert == c->address_families_whitelist) {
2552 r = set_put(c->address_families, INT_TO_PTR(af));
2558 set_remove(c->address_families, INT_TO_PTR(af));
2560 if (!isempty(state))
2561 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2562 "Trailing garbage, ignoring.");
2568 int config_parse_unit_slice(
2570 const char *filename,
2572 const char *section,
2573 unsigned section_line,
2580 _cleanup_free_ char *k = NULL;
2581 Unit *u = userdata, *slice;
2589 r = unit_name_printf(u, rvalue, &k);
2591 log_syntax(unit, LOG_ERR, filename, line, -r,
2592 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2599 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2601 log_syntax(unit, LOG_ERR, filename, line, -r,
2602 "Failed to load slice unit %s. Ignoring.", k);
2606 if (slice->type != UNIT_SLICE) {
2607 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2608 "Slice unit %s is not a slice. Ignoring.", k);
2612 unit_ref_set(&u->slice, slice);
2616 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2618 int config_parse_cpu_shares(
2620 const char *filename,
2622 const char *section,
2623 unsigned section_line,
2630 unsigned long *shares = data, lu;
2637 if (isempty(rvalue)) {
2638 *shares = (unsigned long) -1;
2642 r = safe_atolu(rvalue, &lu);
2643 if (r < 0 || lu <= 0) {
2644 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2645 "CPU shares '%s' invalid. Ignoring.", rvalue);
2653 int config_parse_cpu_quota(
2655 const char *filename,
2657 const char *section,
2658 unsigned section_line,
2665 CGroupContext *c = data;
2672 if (isempty(rvalue)) {
2673 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2677 if (!endswith(rvalue, "%")) {
2679 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2680 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2684 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2685 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2686 "CPU quota '%s' invalid. Ignoring.", rvalue);
2690 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2695 int config_parse_memory_limit(
2697 const char *filename,
2699 const char *section,
2700 unsigned section_line,
2707 CGroupContext *c = data;
2711 if (isempty(rvalue)) {
2712 c->memory_limit = (uint64_t) -1;
2716 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2718 r = parse_size(rvalue, 1024, &bytes);
2720 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2721 "Memory limit '%s' invalid. Ignoring.", rvalue);
2725 c->memory_limit = (uint64_t) bytes;
2729 int config_parse_device_allow(
2731 const char *filename,
2733 const char *section,
2734 unsigned section_line,
2741 _cleanup_free_ char *path = NULL;
2742 CGroupContext *c = data;
2743 CGroupDeviceAllow *a;
2747 if (isempty(rvalue)) {
2748 while (c->device_allow)
2749 cgroup_context_free_device_allow(c, c->device_allow);
2754 n = strcspn(rvalue, WHITESPACE);
2755 path = strndup(rvalue, n);
2759 if (!startswith(path, "/dev/") &&
2760 !startswith(path, "block-") &&
2761 !startswith(path, "char-")) {
2762 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2763 "Invalid device node path '%s'. Ignoring.", path);
2767 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2771 if (!in_charset(m, "rwm")) {
2772 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2773 "Invalid device rights '%s'. Ignoring.", m);
2777 a = new0(CGroupDeviceAllow, 1);
2783 a->r = !!strchr(m, 'r');
2784 a->w = !!strchr(m, 'w');
2785 a->m = !!strchr(m, 'm');
2787 LIST_PREPEND(device_allow, c->device_allow, a);
2791 int config_parse_blockio_weight(
2793 const char *filename,
2795 const char *section,
2796 unsigned section_line,
2803 unsigned long *weight = data, lu;
2810 if (isempty(rvalue)) {
2811 *weight = (unsigned long) -1;
2815 r = safe_atolu(rvalue, &lu);
2816 if (r < 0 || lu < 10 || lu > 1000) {
2817 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2818 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2826 int config_parse_blockio_device_weight(
2828 const char *filename,
2830 const char *section,
2831 unsigned section_line,
2838 _cleanup_free_ char *path = NULL;
2839 CGroupBlockIODeviceWeight *w;
2840 CGroupContext *c = data;
2850 if (isempty(rvalue)) {
2851 while (c->blockio_device_weights)
2852 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2857 n = strcspn(rvalue, WHITESPACE);
2858 weight = rvalue + n;
2860 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2861 "Expected block device and device weight. Ignoring.");
2865 path = strndup(rvalue, n);
2869 if (!path_startswith(path, "/dev")) {
2870 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2871 "Invalid device node path '%s'. Ignoring.", path);
2875 weight += strspn(weight, WHITESPACE);
2876 r = safe_atolu(weight, &lu);
2877 if (r < 0 || lu < 10 || lu > 1000) {
2878 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2879 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2883 w = new0(CGroupBlockIODeviceWeight, 1);
2892 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2896 int config_parse_blockio_bandwidth(
2898 const char *filename,
2900 const char *section,
2901 unsigned section_line,
2908 _cleanup_free_ char *path = NULL;
2909 CGroupBlockIODeviceBandwidth *b;
2910 CGroupContext *c = data;
2911 const char *bandwidth;
2921 read = streq("BlockIOReadBandwidth", lvalue);
2923 if (isempty(rvalue)) {
2924 CGroupBlockIODeviceBandwidth *next;
2926 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2927 if (b->read == read)
2928 cgroup_context_free_blockio_device_bandwidth(c, b);
2933 n = strcspn(rvalue, WHITESPACE);
2934 bandwidth = rvalue + n;
2935 bandwidth += strspn(bandwidth, WHITESPACE);
2938 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2939 "Expected space separated pair of device node and bandwidth. Ignoring.");
2943 path = strndup(rvalue, n);
2947 if (!path_startswith(path, "/dev")) {
2948 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2949 "Invalid device node path '%s'. Ignoring.", path);
2953 r = parse_size(bandwidth, 1000, &bytes);
2954 if (r < 0 || bytes <= 0) {
2955 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2956 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2960 b = new0(CGroupBlockIODeviceBandwidth, 1);
2966 b->bandwidth = (uint64_t) bytes;
2969 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2974 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2976 int config_parse_job_mode_isolate(
2978 const char *filename,
2980 const char *section,
2981 unsigned section_line,
2995 r = parse_boolean(rvalue);
2997 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2998 "Failed to parse boolean, ignoring: %s", rvalue);
3002 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3006 int config_parse_personality(
3008 const char *filename,
3010 const char *section,
3011 unsigned section_line,
3018 unsigned long *personality = data, p;
3023 assert(personality);
3025 p = personality_from_string(rvalue);
3026 if (p == 0xffffffffUL) {
3027 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3028 "Failed to parse personality, ignoring: %s", rvalue);
3036 int config_parse_runtime_directory(
3038 const char *filename,
3040 const char *section,
3041 unsigned section_line,
3049 const char *word, *state;
3058 if (isempty(rvalue)) {
3059 /* Empty assignment resets the list */
3065 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3066 _cleanup_free_ char *n;
3068 n = strndup(word, l);
3072 if (!filename_is_safe(n)) {
3073 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3074 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3078 r = strv_push(rt, n);
3084 if (!isempty(state))
3085 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3086 "Trailing garbage, ignoring.");
3091 int config_parse_set_status(
3093 const char *filename,
3095 const char *section,
3096 unsigned section_line,
3104 const char *word, *state;
3106 ExitStatusSet *status_set = data;
3113 /* Empty assignment resets the list */
3114 if (isempty(rvalue)) {
3115 exit_status_set_free(status_set);
3119 FOREACH_WORD(word, l, rvalue, state) {
3120 _cleanup_free_ char *temp;
3123 temp = strndup(word, l);
3127 r = safe_atoi(temp, &val);
3129 val = signal_from_string_try_harder(temp);
3132 log_syntax(unit, LOG_ERR, filename, line, -val,
3133 "Failed to parse value, ignoring: %s", word);
3137 if (val < 0 || val > 255) {
3138 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3139 "Value %d is outside range 0-255, ignoring", val);
3144 r = set_ensure_allocated(&status_set->status, NULL);
3148 r = set_put(status_set->status, INT_TO_PTR(val));
3150 log_syntax(unit, LOG_ERR, filename, line, -r,
3151 "Unable to store: %s", word);
3155 if (!isempty(state))
3156 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3157 "Trailing garbage, ignoring.");
3162 int config_parse_namespace_path_strv(
3164 const char *filename,
3166 const char *section,
3167 unsigned section_line,
3175 const char *word, *state;
3184 if (isempty(rvalue)) {
3185 /* Empty assignment resets the list */
3191 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3192 _cleanup_free_ char *n;
3195 n = strndup(word, l);
3199 if (!utf8_is_valid(n)) {
3200 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3204 offset = n[0] == '-';
3205 if (!path_is_absolute(n + offset)) {
3206 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3207 "Not an absolute path, ignoring: %s", rvalue);
3211 path_kill_slashes(n);
3213 r = strv_push(sv, n);
3219 if (!isempty(state))
3220 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3221 "Trailing garbage, ignoring.");
3226 int config_parse_no_new_privileges(
3228 const char *filename,
3230 const char *section,
3231 unsigned section_line,
3238 ExecContext *c = data;
3246 k = parse_boolean(rvalue);
3248 log_syntax(unit, LOG_ERR, filename, line, -k,
3249 "Failed to parse boolean value, ignoring: %s", rvalue);
3253 c->no_new_privileges = !!k;
3254 c->no_new_privileges_set = true;
3259 int config_parse_protect_home(
3261 const char *filename,
3263 const char *section,
3264 unsigned section_line,
3271 ExecContext *c = data;
3279 /* Our enum shall be a superset of booleans, hence first try
3280 * to parse as as boolean, and then as enum */
3282 k = parse_boolean(rvalue);
3284 c->protect_home = PROTECT_HOME_YES;
3286 c->protect_home = PROTECT_HOME_NO;
3290 h = protect_home_from_string(rvalue);
3292 log_syntax(unit, LOG_ERR, filename, line, -h,
3293 "Failed to parse protect home value, ignoring: %s", rvalue);
3297 c->protect_home = h;
3303 int config_parse_protect_system(
3305 const char *filename,
3307 const char *section,
3308 unsigned section_line,
3315 ExecContext *c = data;
3323 /* Our enum shall be a superset of booleans, hence first try
3324 * to parse as as boolean, and then as enum */
3326 k = parse_boolean(rvalue);
3328 c->protect_system = PROTECT_SYSTEM_YES;
3330 c->protect_system = PROTECT_SYSTEM_NO;
3334 s = protect_system_from_string(rvalue);
3336 log_syntax(unit, LOG_ERR, filename, line, -s,
3337 "Failed to parse protect system value, ignoring: %s", rvalue);
3341 c->protect_system = s;
3347 #define FOLLOW_MAX 8
3349 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3360 /* This will update the filename pointer if the loaded file is
3361 * reached by a symlink. The old string will be freed. */
3364 char *target, *name;
3366 if (c++ >= FOLLOW_MAX)
3369 path_kill_slashes(*filename);
3371 /* Add the file name we are currently looking at to
3372 * the names of this unit, but only if it is a valid
3374 name = basename(*filename);
3376 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3378 id = set_get(names, name);
3384 r = set_consume(names, id);
3390 /* Try to open the file name, but don't if its a symlink */
3391 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3398 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3399 r = readlink_and_make_absolute(*filename, &target);
3407 f = fdopen(fd, "re");
3419 static int merge_by_names(Unit **u, Set *names, const char *id) {
3427 /* Let's try to add in all symlink names we found */
3428 while ((k = set_steal_first(names))) {
3430 /* First try to merge in the other name into our
3432 r = unit_merge_by_name(*u, k);
3436 /* Hmm, we couldn't merge the other unit into
3437 * ours? Then let's try it the other way
3440 other = manager_get_unit((*u)->manager, k);
3444 r = unit_merge(other, *u);
3447 return merge_by_names(u, names, NULL);
3455 unit_choose_id(*u, id);
3463 static int load_from_path(Unit *u, const char *path) {
3465 _cleanup_set_free_free_ Set *symlink_names = NULL;
3466 _cleanup_fclose_ FILE *f = NULL;
3467 _cleanup_free_ char *filename = NULL;
3475 symlink_names = set_new(&string_hash_ops);
3479 if (path_is_absolute(path)) {
3481 filename = strdup(path);
3485 r = open_follow(&filename, &f, symlink_names, &id);
3497 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3499 /* Instead of opening the path right away, we manually
3500 * follow all symlinks and add their name to our unit
3501 * name set while doing so */
3502 filename = path_make_absolute(path, *p);
3506 if (u->manager->unit_path_cache &&
3507 !set_get(u->manager->unit_path_cache, filename))
3510 r = open_follow(&filename, &f, symlink_names, &id);
3519 /* Empty the symlink names for the next run */
3520 set_clear_free(symlink_names);
3529 /* Hmm, no suitable file found? */
3533 r = merge_by_names(&merged, symlink_names, id);
3538 u->load_state = UNIT_MERGED;
3542 if (fstat(fileno(f), &st) < 0)
3545 if (null_or_empty(&st))
3546 u->load_state = UNIT_MASKED;
3548 u->load_state = UNIT_LOADED;
3550 /* Now, parse the file contents */
3551 r = config_parse(u->id, filename, f,
3552 UNIT_VTABLE(u)->sections,
3553 config_item_perf_lookup, load_fragment_gperf_lookup,
3554 false, true, false, u);
3559 free(u->fragment_path);
3560 u->fragment_path = filename;
3563 u->fragment_mtime = timespec_load(&st.st_mtim);
3565 if (u->source_path) {
3566 if (stat(u->source_path, &st) >= 0)
3567 u->source_mtime = timespec_load(&st.st_mtim);
3569 u->source_mtime = 0;
3575 int unit_load_fragment(Unit *u) {
3581 assert(u->load_state == UNIT_STUB);
3584 /* First, try to find the unit under its id. We always look
3585 * for unit files in the default directories, to make it easy
3586 * to override things by placing things in /etc/systemd/system */
3587 r = load_from_path(u, u->id);
3591 /* Try to find an alias we can load this with */
3592 if (u->load_state == UNIT_STUB)
3593 SET_FOREACH(t, u->names, i) {
3598 r = load_from_path(u, t);
3602 if (u->load_state != UNIT_STUB)
3606 /* And now, try looking for it under the suggested (originally linked) path */
3607 if (u->load_state == UNIT_STUB && u->fragment_path) {
3609 r = load_from_path(u, u->fragment_path);
3613 if (u->load_state == UNIT_STUB) {
3614 /* Hmm, this didn't work? Then let's get rid
3615 * of the fragment path stored for us, so that
3616 * we don't point to an invalid location. */
3617 free(u->fragment_path);
3618 u->fragment_path = NULL;
3622 /* Look for a template */
3623 if (u->load_state == UNIT_STUB && u->instance) {
3624 _cleanup_free_ char *k;
3626 k = unit_name_template(u->id);
3630 r = load_from_path(u, k);
3634 if (u->load_state == UNIT_STUB)
3635 SET_FOREACH(t, u->names, i) {
3636 _cleanup_free_ char *z = NULL;
3641 z = unit_name_template(t);
3645 r = load_from_path(u, z);
3649 if (u->load_state != UNIT_STUB)
3657 void unit_dump_config_items(FILE *f) {
3658 static const struct {
3659 const ConfigParserCallback callback;
3662 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3663 { config_parse_warn_compat, "NOTSUPPORTED" },
3665 { config_parse_int, "INTEGER" },
3666 { config_parse_unsigned, "UNSIGNED" },
3667 { config_parse_iec_size, "SIZE" },
3668 { config_parse_iec_off, "SIZE" },
3669 { config_parse_si_size, "SIZE" },
3670 { config_parse_bool, "BOOLEAN" },
3671 { config_parse_string, "STRING" },
3672 { config_parse_path, "PATH" },
3673 { config_parse_unit_path_printf, "PATH" },
3674 { config_parse_strv, "STRING [...]" },
3675 { config_parse_exec_nice, "NICE" },
3676 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3677 { config_parse_exec_io_class, "IOCLASS" },
3678 { config_parse_exec_io_priority, "IOPRIORITY" },
3679 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3680 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3681 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3682 { config_parse_mode, "MODE" },
3683 { config_parse_unit_env_file, "FILE" },
3684 { config_parse_output, "OUTPUT" },
3685 { config_parse_input, "INPUT" },
3686 { config_parse_log_facility, "FACILITY" },
3687 { config_parse_log_level, "LEVEL" },
3688 { config_parse_exec_capabilities, "CAPABILITIES" },
3689 { config_parse_exec_secure_bits, "SECUREBITS" },
3690 { config_parse_bounding_set, "BOUNDINGSET" },
3691 { config_parse_limit, "LIMIT" },
3692 { config_parse_unit_deps, "UNIT [...]" },
3693 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3694 { config_parse_service_type, "SERVICETYPE" },
3695 { config_parse_service_restart, "SERVICERESTART" },
3696 #ifdef HAVE_SYSV_COMPAT
3697 { config_parse_sysv_priority, "SYSVPRIORITY" },
3699 { config_parse_kill_mode, "KILLMODE" },
3700 { config_parse_kill_signal, "SIGNAL" },
3701 { config_parse_socket_listen, "SOCKET [...]" },
3702 { config_parse_socket_bind, "SOCKETBIND" },
3703 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3704 { config_parse_sec, "SECONDS" },
3705 { config_parse_nsec, "NANOSECONDS" },
3706 { config_parse_namespace_path_strv, "PATH [...]" },
3707 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3708 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3709 { config_parse_unit_string_printf, "STRING" },
3710 { config_parse_trigger_unit, "UNIT" },
3711 { config_parse_timer, "TIMER" },
3712 { config_parse_path_spec, "PATH" },
3713 { config_parse_notify_access, "ACCESS" },
3714 { config_parse_ip_tos, "TOS" },
3715 { config_parse_unit_condition_path, "CONDITION" },
3716 { config_parse_unit_condition_string, "CONDITION" },
3717 { config_parse_unit_condition_null, "CONDITION" },
3718 { config_parse_unit_slice, "SLICE" },
3719 { config_parse_documentation, "URL" },
3720 { config_parse_service_timeout, "SECONDS" },
3721 { config_parse_failure_action, "ACTION" },
3722 { config_parse_set_status, "STATUS" },
3723 { config_parse_service_sockets, "SOCKETS" },
3724 { config_parse_environ, "ENVIRON" },
3726 { config_parse_syscall_filter, "SYSCALLS" },
3727 { config_parse_syscall_archs, "ARCHS" },
3728 { config_parse_syscall_errno, "ERRNO" },
3729 { config_parse_address_families, "FAMILIES" },
3731 { config_parse_cpu_shares, "SHARES" },
3732 { config_parse_memory_limit, "LIMIT" },
3733 { config_parse_device_allow, "DEVICE" },
3734 { config_parse_device_policy, "POLICY" },
3735 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3736 { config_parse_blockio_weight, "WEIGHT" },
3737 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3738 { config_parse_long, "LONG" },
3739 { config_parse_socket_service, "SERVICE" },
3741 { config_parse_exec_selinux_context, "LABEL" },
3743 { config_parse_job_mode, "MODE" },
3744 { config_parse_job_mode_isolate, "BOOLEAN" },
3745 { config_parse_personality, "PERSONALITY" },
3748 const char *prev = NULL;
3753 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3754 const char *rvalue = "OTHER", *lvalue;
3758 const ConfigPerfItem *p;
3760 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3762 dot = strchr(i, '.');
3763 lvalue = dot ? dot + 1 : i;
3767 if (!prev || !strneq(prev, i, prefix_len+1)) {
3771 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3774 for (j = 0; j < ELEMENTSOF(table); j++)
3775 if (p->parse == table[j].callback) {
3776 rvalue = table[j].rvalue;
3780 fprintf(f, "%s=%s\n", lvalue, rvalue);