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 _cleanup_free_ SocketPort *p = NULL;
303 if (isempty(rvalue)) {
304 /* An empty assignment removes all ports */
305 socket_free_ports(s);
309 p = new0(SocketPort, 1);
313 if (ltype != SOCKET_SOCKET) {
316 r = unit_full_printf(UNIT(s), rvalue, &p->path);
318 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 ?: rvalue);
339 log_syntax(unit, LOG_ERR, filename, line, -r,
340 "Failed to parse address value, ignoring: %s", rvalue);
345 _cleanup_free_ char *k = NULL;
347 p->type = SOCKET_SOCKET;
348 r = unit_full_printf(UNIT(s), rvalue, &k);
350 log_syntax(unit, LOG_ERR, filename, line, -r,
351 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
353 r = socket_address_parse(&p->address, k ? k : rvalue);
355 log_syntax(unit, LOG_ERR, filename, line, -r,
356 "Failed to parse address value, ignoring: %s", rvalue);
360 if (streq(lvalue, "ListenStream"))
361 p->address.type = SOCK_STREAM;
362 else if (streq(lvalue, "ListenDatagram"))
363 p->address.type = SOCK_DGRAM;
365 assert(streq(lvalue, "ListenSequentialPacket"));
366 p->address.type = SOCK_SEQPACKET;
369 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
370 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
371 "Address family not supported, ignoring: %s", rvalue);
380 LIST_FIND_TAIL(port, s->ports, tail);
381 LIST_INSERT_AFTER(port, s->ports, tail, p);
383 LIST_PREPEND(port, s->ports, p);
389 int config_parse_socket_bind(const char *unit,
390 const char *filename,
393 unsigned section_line,
401 SocketAddressBindIPv6Only b;
410 b = socket_address_bind_ipv6_only_from_string(rvalue);
414 r = parse_boolean(rvalue);
416 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
417 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
421 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
423 s->bind_ipv6_only = b;
428 int config_parse_exec_nice(const char *unit,
429 const char *filename,
432 unsigned section_line,
439 ExecContext *c = data;
447 r = safe_atoi(rvalue, &priority);
449 log_syntax(unit, LOG_ERR, filename, line, -r,
450 "Failed to parse nice priority, ignoring: %s. ", rvalue);
454 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
455 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
456 "Nice priority out of range, ignoring: %s", rvalue);
466 int config_parse_exec_oom_score_adjust(const char* unit,
467 const char *filename,
470 unsigned section_line,
477 ExecContext *c = data;
485 r = safe_atoi(rvalue, &oa);
487 log_syntax(unit, LOG_ERR, filename, line, -r,
488 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
492 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
493 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
494 "OOM score adjust value out of range, ignoring: %s", rvalue);
498 c->oom_score_adjust = oa;
499 c->oom_score_adjust_set = true;
504 int config_parse_exec(const char *unit,
505 const char *filename,
508 unsigned section_line,
515 ExecCommand **e = data, *nce;
527 if (isempty(rvalue)) {
528 /* An empty assignment resets the list */
529 exec_command_free_list(*e);
534 /* We accept an absolute path as first argument, or
535 * alternatively an absolute prefixed with @ to allow
536 * overriding of argv[0]. */
539 const char *word, *state;
541 bool honour_argv0 = false, ignore = false;
547 rvalue += strspn(rvalue, WHITESPACE);
552 for (i = 0; i < 2; i++) {
553 if (rvalue[0] == '-' && !ignore) {
558 if (rvalue[0] == '@' && !honour_argv0) {
564 if (*rvalue != '/') {
565 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
566 "Executable path is not absolute, ignoring: %s", rvalue);
571 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
572 if (strneq(word, ";", MAX(l, 1U)))
577 if (!isempty(state)) {
578 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
579 "Trailing garbage, ignoring.");
584 n = new(char*, k + !honour_argv0);
589 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
590 if (strneq(word, ";", MAX(l, 1U)))
592 else if (strneq(word, "\\;", MAX(l, 1U)))
595 if (honour_argv0 && word == rvalue) {
598 path = strndup(word, l);
604 if (!utf8_is_valid(path)) {
605 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
613 c = n[k++] = cunescape_length(word, l);
619 if (!utf8_is_valid(c)) {
620 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
630 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
631 "Invalid command line, ignoring: %s", rvalue);
644 assert(path_is_absolute(path));
646 nce = new0(ExecCommand, 1);
654 nce->ignore = ignore;
656 path_kill_slashes(nce->path);
658 exec_command_append_list(e, nce);
674 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
675 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
677 int config_parse_socket_bindtodevice(const char* unit,
678 const char *filename,
681 unsigned section_line,
696 if (rvalue[0] && !streq(rvalue, "*")) {
703 free(s->bind_to_device);
704 s->bind_to_device = n;
709 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
710 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
712 int config_parse_exec_io_class(const char *unit,
713 const char *filename,
716 unsigned section_line,
723 ExecContext *c = data;
731 x = ioprio_class_from_string(rvalue);
733 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
734 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
738 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
739 c->ioprio_set = true;
744 int config_parse_exec_io_priority(const char *unit,
745 const char *filename,
748 unsigned section_line,
755 ExecContext *c = data;
763 r = safe_atoi(rvalue, &i);
764 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
765 log_syntax(unit, LOG_ERR, filename, line, -r,
766 "Failed to parse IO priority, ignoring: %s", rvalue);
770 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
771 c->ioprio_set = true;
776 int config_parse_exec_cpu_sched_policy(const char *unit,
777 const char *filename,
780 unsigned section_line,
788 ExecContext *c = data;
796 x = sched_policy_from_string(rvalue);
798 log_syntax(unit, LOG_ERR, filename, line, -x,
799 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
803 c->cpu_sched_policy = x;
804 /* Moving to or from real-time policy? We need to adjust the priority */
805 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
806 c->cpu_sched_set = true;
811 int config_parse_exec_cpu_sched_prio(const char *unit,
812 const char *filename,
815 unsigned section_line,
822 ExecContext *c = data;
830 r = safe_atoi(rvalue, &i);
832 log_syntax(unit, LOG_ERR, filename, line, -r,
833 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
837 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
838 min = sched_get_priority_min(c->cpu_sched_policy);
839 max = sched_get_priority_max(c->cpu_sched_policy);
841 if (i < min || i > max) {
842 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
843 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
847 c->cpu_sched_priority = i;
848 c->cpu_sched_set = true;
853 int config_parse_exec_cpu_affinity(const char *unit,
854 const char *filename,
857 unsigned section_line,
864 ExecContext *c = data;
865 const char *word, *state;
873 if (isempty(rvalue)) {
874 /* An empty assignment resets the CPU list */
881 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
882 _cleanup_free_ char *t = NULL;
886 t = strndup(word, l);
890 r = safe_atou(t, &cpu);
893 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
898 if (r < 0 || cpu >= c->cpuset_ncpus) {
899 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
900 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
904 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
907 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
908 "Trailing garbage, ignoring.");
913 int config_parse_exec_capabilities(const char *unit,
914 const char *filename,
917 unsigned section_line,
924 ExecContext *c = data;
932 cap = cap_from_text(rvalue);
934 log_syntax(unit, LOG_ERR, filename, line, errno,
935 "Failed to parse capabilities, ignoring: %s", rvalue);
940 cap_free(c->capabilities);
941 c->capabilities = cap;
946 int config_parse_exec_secure_bits(const char *unit,
947 const char *filename,
950 unsigned section_line,
957 ExecContext *c = data;
959 const char *word, *state;
966 if (isempty(rvalue)) {
967 /* An empty assignment resets the field */
972 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
973 if (first_word(word, "keep-caps"))
974 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
975 else if (first_word(word, "keep-caps-locked"))
976 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
977 else if (first_word(word, "no-setuid-fixup"))
978 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
979 else if (first_word(word, "no-setuid-fixup-locked"))
980 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
981 else if (first_word(word, "noroot"))
982 c->secure_bits |= 1<<SECURE_NOROOT;
983 else if (first_word(word, "noroot-locked"))
984 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
986 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
987 "Failed to parse secure bits, ignoring: %s", rvalue);
992 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
993 "Invalid syntax, garbage at the end, ignoring.");
998 int config_parse_bounding_set(const char *unit,
999 const char *filename,
1001 const char *section,
1002 unsigned section_line,
1009 uint64_t *capability_bounding_set_drop = data;
1010 const char *word, *state;
1012 bool invert = false;
1020 if (rvalue[0] == '~') {
1025 /* Note that we store this inverted internally, since the
1026 * kernel wants it like this. But we actually expose it
1027 * non-inverted everywhere to have a fully normalized
1030 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1031 _cleanup_free_ char *t = NULL;
1035 t = strndup(word, l);
1039 r = cap_from_name(t, &cap);
1041 log_syntax(unit, LOG_ERR, filename, line, errno,
1042 "Failed to parse capability in bounding set, ignoring: %s", t);
1046 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1048 if (!isempty(state))
1049 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1050 "Trailing garbage, ignoring.");
1053 *capability_bounding_set_drop |= sum;
1055 *capability_bounding_set_drop |= ~sum;
1060 int config_parse_limit(const char *unit,
1061 const char *filename,
1063 const char *section,
1064 unsigned section_line,
1071 struct rlimit **rl = data;
1072 unsigned long long u;
1081 if (streq(rvalue, "infinity"))
1082 u = (unsigned long long) RLIM_INFINITY;
1086 r = safe_atollu(rvalue, &u);
1088 log_syntax(unit, LOG_ERR, filename, line, -r,
1089 "Failed to parse resource value, ignoring: %s", rvalue);
1095 *rl = new(struct rlimit, 1);
1100 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1104 #ifdef HAVE_SYSV_COMPAT
1105 int config_parse_sysv_priority(const char *unit,
1106 const char *filename,
1108 const char *section,
1109 unsigned section_line,
1116 int *priority = data;
1124 r = safe_atoi(rvalue, &i);
1125 if (r < 0 || i < 0) {
1126 log_syntax(unit, LOG_ERR, filename, line, -r,
1127 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1131 *priority = (int) i;
1136 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1138 int config_parse_kill_signal(const char *unit,
1139 const char *filename,
1141 const char *section,
1142 unsigned section_line,
1157 r = signal_from_string_try_harder(rvalue);
1159 log_syntax(unit, LOG_ERR, filename, line, -r,
1160 "Failed to parse kill signal, ignoring: %s", rvalue);
1168 int config_parse_exec_mount_flags(const char *unit,
1169 const char *filename,
1171 const char *section,
1172 unsigned section_line,
1179 ExecContext *c = data;
1180 const char *word, *state;
1182 unsigned long flags = 0;
1189 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1190 _cleanup_free_ char *t;
1192 t = strndup(word, l);
1196 if (streq(t, "shared"))
1198 else if (streq(t, "slave"))
1200 else if (streq(word, "private"))
1203 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1204 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1208 if (!isempty(state))
1209 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1210 "Trailing garbage, ignoring.");
1212 c->mount_flags = flags;
1216 int config_parse_exec_selinux_context(
1218 const char *filename,
1220 const char *section,
1221 unsigned section_line,
1228 ExecContext *c = data;
1239 if (isempty(rvalue)) {
1240 free(c->selinux_context);
1241 c->selinux_context = NULL;
1242 c->selinux_context_ignore = false;
1246 if (rvalue[0] == '-') {
1252 r = unit_name_printf(u, rvalue, &k);
1254 log_syntax(unit, LOG_ERR, filename, line, -r,
1255 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1259 free(c->selinux_context);
1260 c->selinux_context = k;
1261 c->selinux_context_ignore = ignore;
1266 int config_parse_exec_apparmor_profile(
1268 const char *filename,
1270 const char *section,
1271 unsigned section_line,
1278 ExecContext *c = data;
1289 if (isempty(rvalue)) {
1290 free(c->apparmor_profile);
1291 c->apparmor_profile = NULL;
1292 c->apparmor_profile_ignore = false;
1296 if (rvalue[0] == '-') {
1302 r = unit_name_printf(u, rvalue, &k);
1304 log_syntax(unit, LOG_ERR, filename, line, -r,
1305 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1309 free(c->apparmor_profile);
1310 c->apparmor_profile = k;
1311 c->apparmor_profile_ignore = ignore;
1316 int config_parse_timer(const char *unit,
1317 const char *filename,
1319 const char *section,
1320 unsigned section_line,
1331 CalendarSpec *c = NULL;
1338 if (isempty(rvalue)) {
1339 /* Empty assignment resets list */
1340 timer_free_values(t);
1344 b = timer_base_from_string(lvalue);
1346 log_syntax(unit, LOG_ERR, filename, line, -b,
1347 "Failed to parse timer base, ignoring: %s", lvalue);
1351 if (b == TIMER_CALENDAR) {
1352 if (calendar_spec_from_string(rvalue, &c) < 0) {
1353 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1354 "Failed to parse calendar specification, ignoring: %s",
1359 if (parse_sec(rvalue, &u) < 0) {
1360 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1361 "Failed to parse timer value, ignoring: %s",
1367 v = new0(TimerValue, 1);
1370 calendar_spec_free(c);
1376 v->calendar_spec = c;
1378 LIST_PREPEND(value, t->values, v);
1383 int config_parse_trigger_unit(
1385 const char *filename,
1387 const char *section,
1388 unsigned section_line,
1395 _cleanup_free_ char *p = NULL;
1405 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1406 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1407 "Multiple units to trigger specified, ignoring: %s", rvalue);
1411 r = unit_name_printf(u, rvalue, &p);
1413 log_syntax(unit, LOG_ERR, filename, line, -r,
1414 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1416 type = unit_name_to_type(p ?: rvalue);
1418 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1419 "Unit type not valid, ignoring: %s", rvalue);
1423 if (type == u->type) {
1424 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1425 "Trigger cannot be of same type, ignoring: %s", rvalue);
1429 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1431 log_syntax(unit, LOG_ERR, filename, line, -r,
1432 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1439 int config_parse_path_spec(const char *unit,
1440 const char *filename,
1442 const char *section,
1443 unsigned section_line,
1453 _cleanup_free_ char *k = NULL;
1461 if (isempty(rvalue)) {
1462 /* Empty assignment clears list */
1467 b = path_type_from_string(lvalue);
1469 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1470 "Failed to parse path type, ignoring: %s", lvalue);
1474 r = unit_full_printf(UNIT(p), rvalue, &k);
1480 log_syntax(unit, LOG_ERR, filename, line, -r,
1481 "Failed to resolve unit specifiers on %s. Ignoring.",
1485 if (!path_is_absolute(k)) {
1486 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1487 "Path is not absolute, ignoring: %s", k);
1491 s = new0(PathSpec, 1);
1496 s->path = path_kill_slashes(k);
1501 LIST_PREPEND(spec, p->specs, s);
1506 int config_parse_socket_service(const char *unit,
1507 const char *filename,
1509 const char *section,
1510 unsigned section_line,
1517 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1521 _cleanup_free_ char *p = NULL;
1528 r = unit_name_printf(UNIT(s), rvalue, &p);
1530 log_syntax(unit, LOG_ERR, filename, line, -r,
1531 "Failed to resolve specifiers, ignoring: %s", rvalue);
1535 if (!endswith(p, ".service")) {
1536 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1537 "Unit must be of type service, ignoring: %s", rvalue);
1541 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1543 log_syntax(unit, LOG_ERR, filename, line, -r,
1544 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1548 unit_ref_set(&s->service, x);
1553 int config_parse_service_sockets(const char *unit,
1554 const char *filename,
1556 const char *section,
1557 unsigned section_line,
1566 const char *word, *state;
1574 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1575 _cleanup_free_ char *t = NULL, *k = NULL;
1577 t = strndup(word, l);
1581 r = unit_name_printf(UNIT(s), t, &k);
1583 log_syntax(unit, LOG_ERR, filename, line, -r,
1584 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1586 if (!endswith(k ?: t, ".socket")) {
1587 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1588 "Unit must be of type socket, ignoring: %s", k ?: t);
1592 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1594 log_syntax(unit, LOG_ERR, filename, line, -r,
1595 "Failed to add dependency on %s, ignoring: %s",
1596 k ?: t, strerror(-r));
1598 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1602 if (!isempty(state))
1603 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1604 "Trailing garbage, ignoring.");
1609 int config_parse_service_timeout(const char *unit,
1610 const char *filename,
1612 const char *section,
1613 unsigned section_line,
1620 Service *s = userdata;
1628 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1629 rvalue, data, userdata);
1633 if (streq(lvalue, "TimeoutSec")) {
1634 s->start_timeout_defined = true;
1635 s->timeout_stop_usec = s->timeout_start_usec;
1636 } else if (streq(lvalue, "TimeoutStartSec"))
1637 s->start_timeout_defined = true;
1642 int config_parse_busname_service(
1644 const char *filename,
1646 const char *section,
1647 unsigned section_line,
1654 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1658 _cleanup_free_ char *p = NULL;
1665 r = unit_name_printf(UNIT(n), rvalue, &p);
1667 log_syntax(unit, LOG_ERR, filename, line, -r,
1668 "Failed to resolve specifiers, ignoring: %s", rvalue);
1672 if (!endswith(p, ".service")) {
1673 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1674 "Unit must be of type service, ignoring: %s", rvalue);
1678 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1680 log_syntax(unit, LOG_ERR, filename, line, -r,
1681 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1685 unit_ref_set(&n->service, x);
1690 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1692 int config_parse_bus_policy(
1694 const char *filename,
1696 const char *section,
1697 unsigned section_line,
1704 _cleanup_free_ BusNamePolicy *p = NULL;
1705 _cleanup_free_ char *id_str = NULL;
1706 BusName *busname = data;
1714 p = new0(BusNamePolicy, 1);
1718 if (streq(lvalue, "AllowUser"))
1719 p->type = BUSNAME_POLICY_TYPE_USER;
1720 else if (streq(lvalue, "AllowGroup"))
1721 p->type = BUSNAME_POLICY_TYPE_GROUP;
1723 assert_not_reached("Unknown lvalue");
1725 id_str = strdup(rvalue);
1729 access_str = strpbrk(id_str, WHITESPACE);
1731 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1732 "Invalid busname policy value '%s'", rvalue);
1738 access_str += strspn(access_str, WHITESPACE);
1740 p->access = bus_policy_access_from_string(access_str);
1741 if (p->access < 0) {
1742 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1743 "Invalid busname policy access type '%s'", access_str);
1750 LIST_PREPEND(policy, busname->policy, p);
1756 int config_parse_bus_endpoint_policy(
1758 const char *filename,
1760 const char *section,
1761 unsigned section_line,
1768 _cleanup_free_ char *name = NULL;
1769 BusPolicyAccess access;
1770 ExecContext *c = data;
1779 name = strdup(rvalue);
1783 access_str = strpbrk(name, WHITESPACE);
1785 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1786 "Invalid endpoint policy value '%s'", rvalue);
1792 access_str += strspn(access_str, WHITESPACE);
1794 access = bus_policy_access_from_string(access_str);
1795 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1796 access >= _BUS_POLICY_ACCESS_MAX) {
1797 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1798 "Invalid endpoint policy access type '%s'", access_str);
1802 if (!c->bus_endpoint) {
1803 r = bus_endpoint_new(&c->bus_endpoint);
1809 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1812 int config_parse_unit_env_file(const char *unit,
1813 const char *filename,
1815 const char *section,
1816 unsigned section_line,
1825 _cleanup_free_ char *n = NULL;
1834 if (isempty(rvalue)) {
1835 /* Empty assignment frees the list */
1841 r = unit_full_printf(u, rvalue, &n);
1843 log_syntax(unit, LOG_ERR, filename, line, -r,
1844 "Failed to resolve specifiers, ignoring: %s", rvalue);
1847 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1848 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1849 "Path '%s' is not absolute, ignoring.", s);
1853 r = strv_extend(env, s);
1860 int config_parse_environ(const char *unit,
1861 const char *filename,
1863 const char *section,
1864 unsigned section_line,
1873 const char *word, *state;
1875 _cleanup_free_ char *k = NULL;
1883 if (isempty(rvalue)) {
1884 /* Empty assignment resets the list */
1891 r = unit_full_printf(u, rvalue, &k);
1893 log_syntax(unit, LOG_ERR, filename, line, -r,
1894 "Failed to resolve specifiers, ignoring: %s", rvalue);
1902 FOREACH_WORD_QUOTED(word, l, k, state) {
1903 _cleanup_free_ char *n;
1906 n = cunescape_length(word, l);
1910 if (!env_assignment_is_valid(n)) {
1911 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1912 "Invalid environment assignment, ignoring: %s", rvalue);
1916 x = strv_env_set(*env, n);
1923 if (!isempty(state))
1924 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1925 "Trailing garbage, ignoring.");
1930 int config_parse_ip_tos(const char *unit,
1931 const char *filename,
1933 const char *section,
1934 unsigned section_line,
1941 int *ip_tos = data, x;
1948 x = ip_tos_from_string(rvalue);
1950 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1951 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1959 int config_parse_unit_condition_path(const char *unit,
1960 const char *filename,
1962 const char *section,
1963 unsigned section_line,
1970 ConditionType cond = ltype;
1972 bool trigger, negate;
1974 _cleanup_free_ char *p = NULL;
1982 if (isempty(rvalue)) {
1983 /* Empty assignment resets the list */
1984 condition_free_list(u->conditions);
1985 u->conditions = NULL;
1989 trigger = rvalue[0] == '|';
1993 negate = rvalue[0] == '!';
1997 r = unit_full_printf(u, rvalue, &p);
1999 log_syntax(unit, LOG_ERR, filename, line, -r,
2000 "Failed to resolve specifiers, ignoring: %s", rvalue);
2007 if (!path_is_absolute(p)) {
2008 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2009 "Path in condition not absolute, ignoring: %s", p);
2013 c = condition_new(cond, p, trigger, negate);
2017 LIST_PREPEND(conditions, u->conditions, c);
2021 int config_parse_unit_condition_string(const char *unit,
2022 const char *filename,
2024 const char *section,
2025 unsigned section_line,
2032 ConditionType cond = ltype;
2034 bool trigger, negate;
2036 _cleanup_free_ char *s = NULL;
2044 if (isempty(rvalue)) {
2045 /* Empty assignment resets the list */
2046 condition_free_list(u->conditions);
2047 u->conditions = NULL;
2051 trigger = rvalue[0] == '|';
2055 negate = rvalue[0] == '!';
2059 r = unit_full_printf(u, rvalue, &s);
2061 log_syntax(unit, LOG_ERR, filename, line, -r,
2062 "Failed to resolve specifiers, ignoring: %s", rvalue);
2069 c = condition_new(cond, s, trigger, negate);
2073 LIST_PREPEND(conditions, u->conditions, c);
2077 int config_parse_unit_condition_null(const char *unit,
2078 const char *filename,
2080 const char *section,
2081 unsigned section_line,
2090 bool trigger, negate;
2098 if (isempty(rvalue)) {
2099 /* Empty assignment resets the list */
2100 condition_free_list(u->conditions);
2101 u->conditions = NULL;
2105 trigger = rvalue[0] == '|';
2109 negate = rvalue[0] == '!';
2113 b = parse_boolean(rvalue);
2115 log_syntax(unit, LOG_ERR, filename, line, -b,
2116 "Failed to parse boolean value in condition, ignoring: %s",
2124 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2128 LIST_PREPEND(conditions, u->conditions, c);
2132 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2133 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2135 int config_parse_unit_requires_mounts_for(
2137 const char *filename,
2139 const char *section,
2140 unsigned section_line,
2148 const char *word, *state;
2156 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2158 _cleanup_free_ char *n;
2160 n = strndup(word, l);
2164 if (!utf8_is_valid(n)) {
2165 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2169 r = unit_require_mounts_for(u, n);
2171 log_syntax(unit, LOG_ERR, filename, line, -r,
2172 "Failed to add required mount for, ignoring: %s", rvalue);
2176 if (!isempty(state))
2177 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2178 "Trailing garbage, ignoring.");
2183 int config_parse_documentation(const char *unit,
2184 const char *filename,
2186 const char *section,
2187 unsigned section_line,
2203 if (isempty(rvalue)) {
2204 /* Empty assignment resets the list */
2205 strv_free(u->documentation);
2206 u->documentation = NULL;
2210 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2211 rvalue, data, userdata);
2215 for (a = b = u->documentation; a && *a; a++) {
2217 if (is_valid_documentation_url(*a))
2220 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2221 "Invalid URL, ignoring: %s", *a);
2232 int config_parse_syscall_filter(
2234 const char *filename,
2236 const char *section,
2237 unsigned section_line,
2244 static const char default_syscalls[] =
2251 ExecContext *c = data;
2253 bool invert = false;
2254 const char *word, *state;
2263 if (isempty(rvalue)) {
2264 /* Empty assignment resets the list */
2265 set_free(c->syscall_filter);
2266 c->syscall_filter = NULL;
2267 c->syscall_whitelist = false;
2271 if (rvalue[0] == '~') {
2276 if (!c->syscall_filter) {
2277 c->syscall_filter = set_new(NULL);
2278 if (!c->syscall_filter)
2282 /* Allow everything but the ones listed */
2283 c->syscall_whitelist = false;
2287 /* Allow nothing but the ones listed */
2288 c->syscall_whitelist = true;
2290 /* Accept default syscalls if we are on a whitelist */
2291 NULSTR_FOREACH(i, default_syscalls) {
2294 id = seccomp_syscall_resolve_name(i);
2298 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2307 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2308 _cleanup_free_ char *t = NULL;
2311 t = strndup(word, l);
2315 id = seccomp_syscall_resolve_name(t);
2317 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2318 "Failed to parse system call, ignoring: %s", t);
2322 /* If we previously wanted to forbid a syscall and now
2323 * we want to allow it, then remove it from the list
2325 if (!invert == c->syscall_whitelist) {
2326 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2332 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2334 if (!isempty(state))
2335 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2336 "Trailing garbage, ignoring.");
2338 /* Turn on NNP, but only if it wasn't configured explicitly
2339 * before, and only if we are in user mode. */
2340 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2341 c->no_new_privileges = true;
2346 int config_parse_syscall_archs(
2348 const char *filename,
2350 const char *section,
2351 unsigned section_line,
2359 const char *word, *state;
2363 if (isempty(rvalue)) {
2369 r = set_ensure_allocated(archs, NULL);
2373 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2374 _cleanup_free_ char *t = NULL;
2377 t = strndup(word, l);
2381 r = seccomp_arch_from_string(t, &a);
2383 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2384 "Failed to parse system call architecture, ignoring: %s", t);
2388 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2394 if (!isempty(state))
2395 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2396 "Trailing garbage, ignoring.");
2401 int config_parse_syscall_errno(
2403 const char *filename,
2405 const char *section,
2406 unsigned section_line,
2413 ExecContext *c = data;
2420 if (isempty(rvalue)) {
2421 /* Empty assignment resets to KILL */
2422 c->syscall_errno = 0;
2426 e = errno_from_name(rvalue);
2428 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2429 "Failed to parse error number, ignoring: %s", rvalue);
2433 c->syscall_errno = e;
2437 int config_parse_address_families(
2439 const char *filename,
2441 const char *section,
2442 unsigned section_line,
2449 ExecContext *c = data;
2451 bool invert = false;
2452 const char *word, *state;
2461 if (isempty(rvalue)) {
2462 /* Empty assignment resets the list */
2463 set_free(c->address_families);
2464 c->address_families = NULL;
2465 c->address_families_whitelist = false;
2469 if (rvalue[0] == '~') {
2474 if (!c->address_families) {
2475 c->address_families = set_new(NULL);
2476 if (!c->address_families)
2479 c->address_families_whitelist = !invert;
2482 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2483 _cleanup_free_ char *t = NULL;
2486 t = strndup(word, l);
2490 af = af_from_name(t);
2492 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2493 "Failed to parse address family, ignoring: %s", t);
2497 /* If we previously wanted to forbid an address family and now
2498 * we want to allow it, then remove it from the list
2500 if (!invert == c->address_families_whitelist) {
2501 r = set_put(c->address_families, INT_TO_PTR(af));
2507 set_remove(c->address_families, INT_TO_PTR(af));
2509 if (!isempty(state))
2510 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2511 "Trailing garbage, ignoring.");
2517 int config_parse_unit_slice(
2519 const char *filename,
2521 const char *section,
2522 unsigned section_line,
2529 _cleanup_free_ char *k = NULL;
2530 Unit *u = userdata, *slice;
2538 r = unit_name_printf(u, rvalue, &k);
2540 log_syntax(unit, LOG_ERR, filename, line, -r,
2541 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2548 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2550 log_syntax(unit, LOG_ERR, filename, line, -r,
2551 "Failed to load slice unit %s. Ignoring.", k);
2555 if (slice->type != UNIT_SLICE) {
2556 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2557 "Slice unit %s is not a slice. Ignoring.", k);
2561 unit_ref_set(&u->slice, slice);
2565 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2567 int config_parse_cpu_shares(
2569 const char *filename,
2571 const char *section,
2572 unsigned section_line,
2579 unsigned long *shares = data, lu;
2586 if (isempty(rvalue)) {
2587 *shares = (unsigned long) -1;
2591 r = safe_atolu(rvalue, &lu);
2592 if (r < 0 || lu <= 0) {
2593 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2594 "CPU shares '%s' invalid. Ignoring.", rvalue);
2602 int config_parse_cpu_quota(
2604 const char *filename,
2606 const char *section,
2607 unsigned section_line,
2614 CGroupContext *c = data;
2621 if (isempty(rvalue)) {
2622 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2626 if (!endswith(rvalue, "%")) {
2628 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2629 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2633 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2634 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2635 "CPU quota '%s' invalid. Ignoring.", rvalue);
2639 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2644 int config_parse_memory_limit(
2646 const char *filename,
2648 const char *section,
2649 unsigned section_line,
2656 CGroupContext *c = data;
2660 if (isempty(rvalue)) {
2661 c->memory_limit = (uint64_t) -1;
2665 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2667 r = parse_size(rvalue, 1024, &bytes);
2669 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2670 "Memory limit '%s' invalid. Ignoring.", rvalue);
2674 c->memory_limit = (uint64_t) bytes;
2678 int config_parse_device_allow(
2680 const char *filename,
2682 const char *section,
2683 unsigned section_line,
2690 _cleanup_free_ char *path = NULL;
2691 CGroupContext *c = data;
2692 CGroupDeviceAllow *a;
2696 if (isempty(rvalue)) {
2697 while (c->device_allow)
2698 cgroup_context_free_device_allow(c, c->device_allow);
2703 n = strcspn(rvalue, WHITESPACE);
2704 path = strndup(rvalue, n);
2708 if (!startswith(path, "/dev/") &&
2709 !startswith(path, "block-") &&
2710 !startswith(path, "char-")) {
2711 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2712 "Invalid device node path '%s'. Ignoring.", path);
2716 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2720 if (!in_charset(m, "rwm")) {
2721 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2722 "Invalid device rights '%s'. Ignoring.", m);
2726 a = new0(CGroupDeviceAllow, 1);
2732 a->r = !!strchr(m, 'r');
2733 a->w = !!strchr(m, 'w');
2734 a->m = !!strchr(m, 'm');
2736 LIST_PREPEND(device_allow, c->device_allow, a);
2740 int config_parse_blockio_weight(
2742 const char *filename,
2744 const char *section,
2745 unsigned section_line,
2752 unsigned long *weight = data, lu;
2759 if (isempty(rvalue)) {
2760 *weight = (unsigned long) -1;
2764 r = safe_atolu(rvalue, &lu);
2765 if (r < 0 || lu < 10 || lu > 1000) {
2766 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2767 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2775 int config_parse_blockio_device_weight(
2777 const char *filename,
2779 const char *section,
2780 unsigned section_line,
2787 _cleanup_free_ char *path = NULL;
2788 CGroupBlockIODeviceWeight *w;
2789 CGroupContext *c = data;
2799 if (isempty(rvalue)) {
2800 while (c->blockio_device_weights)
2801 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2806 n = strcspn(rvalue, WHITESPACE);
2807 weight = rvalue + n;
2809 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2810 "Expected block device and device weight. Ignoring.");
2814 path = strndup(rvalue, n);
2818 if (!path_startswith(path, "/dev")) {
2819 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2820 "Invalid device node path '%s'. Ignoring.", path);
2824 weight += strspn(weight, WHITESPACE);
2825 r = safe_atolu(weight, &lu);
2826 if (r < 0 || lu < 10 || lu > 1000) {
2827 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2828 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2832 w = new0(CGroupBlockIODeviceWeight, 1);
2841 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2845 int config_parse_blockio_bandwidth(
2847 const char *filename,
2849 const char *section,
2850 unsigned section_line,
2857 _cleanup_free_ char *path = NULL;
2858 CGroupBlockIODeviceBandwidth *b;
2859 CGroupContext *c = data;
2860 const char *bandwidth;
2870 read = streq("BlockIOReadBandwidth", lvalue);
2872 if (isempty(rvalue)) {
2873 CGroupBlockIODeviceBandwidth *next;
2875 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2876 if (b->read == read)
2877 cgroup_context_free_blockio_device_bandwidth(c, b);
2882 n = strcspn(rvalue, WHITESPACE);
2883 bandwidth = rvalue + n;
2884 bandwidth += strspn(bandwidth, WHITESPACE);
2887 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2888 "Expected space separated pair of device node and bandwidth. Ignoring.");
2892 path = strndup(rvalue, n);
2896 if (!path_startswith(path, "/dev")) {
2897 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2898 "Invalid device node path '%s'. Ignoring.", path);
2902 r = parse_size(bandwidth, 1000, &bytes);
2903 if (r < 0 || bytes <= 0) {
2904 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2905 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2909 b = new0(CGroupBlockIODeviceBandwidth, 1);
2915 b->bandwidth = (uint64_t) bytes;
2918 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2923 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2925 int config_parse_job_mode_isolate(
2927 const char *filename,
2929 const char *section,
2930 unsigned section_line,
2944 r = parse_boolean(rvalue);
2946 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2947 "Failed to parse boolean, ignoring: %s", rvalue);
2951 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2955 int config_parse_personality(
2957 const char *filename,
2959 const char *section,
2960 unsigned section_line,
2967 unsigned long *personality = data, p;
2972 assert(personality);
2974 p = personality_from_string(rvalue);
2975 if (p == 0xffffffffUL) {
2976 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2977 "Failed to parse personality, ignoring: %s", rvalue);
2985 int config_parse_runtime_directory(
2987 const char *filename,
2989 const char *section,
2990 unsigned section_line,
2998 const char *word, *state;
3007 if (isempty(rvalue)) {
3008 /* Empty assignment resets the list */
3014 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3015 _cleanup_free_ char *n;
3017 n = strndup(word, l);
3021 if (!filename_is_safe(n)) {
3022 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3023 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3027 r = strv_push(rt, n);
3033 if (!isempty(state))
3034 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3035 "Trailing garbage, ignoring.");
3040 int config_parse_set_status(
3042 const char *filename,
3044 const char *section,
3045 unsigned section_line,
3053 const char *word, *state;
3055 ExitStatusSet *status_set = data;
3062 /* Empty assignment resets the list */
3063 if (isempty(rvalue)) {
3064 exit_status_set_free(status_set);
3068 FOREACH_WORD(word, l, rvalue, state) {
3069 _cleanup_free_ char *temp;
3072 temp = strndup(word, l);
3076 r = safe_atoi(temp, &val);
3078 val = signal_from_string_try_harder(temp);
3081 log_syntax(unit, LOG_ERR, filename, line, -val,
3082 "Failed to parse value, ignoring: %s", word);
3086 if (val < 0 || val > 255) {
3087 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3088 "Value %d is outside range 0-255, ignoring", val);
3093 r = set_ensure_allocated(&status_set->status, NULL);
3097 r = set_put(status_set->status, INT_TO_PTR(val));
3099 log_syntax(unit, LOG_ERR, filename, line, -r,
3100 "Unable to store: %s", word);
3104 if (!isempty(state))
3105 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3106 "Trailing garbage, ignoring.");
3111 int config_parse_namespace_path_strv(
3113 const char *filename,
3115 const char *section,
3116 unsigned section_line,
3124 const char *word, *state;
3133 if (isempty(rvalue)) {
3134 /* Empty assignment resets the list */
3140 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3141 _cleanup_free_ char *n;
3144 n = strndup(word, l);
3148 if (!utf8_is_valid(n)) {
3149 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3153 offset = n[0] == '-';
3154 if (!path_is_absolute(n + offset)) {
3155 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3156 "Not an absolute path, ignoring: %s", rvalue);
3160 path_kill_slashes(n);
3162 r = strv_push(sv, n);
3168 if (!isempty(state))
3169 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3170 "Trailing garbage, ignoring.");
3175 int config_parse_no_new_privileges(
3177 const char *filename,
3179 const char *section,
3180 unsigned section_line,
3187 ExecContext *c = data;
3195 k = parse_boolean(rvalue);
3197 log_syntax(unit, LOG_ERR, filename, line, -k,
3198 "Failed to parse boolean value, ignoring: %s", rvalue);
3202 c->no_new_privileges = !!k;
3203 c->no_new_privileges_set = true;
3208 int config_parse_protect_home(
3210 const char *filename,
3212 const char *section,
3213 unsigned section_line,
3220 ExecContext *c = data;
3228 /* Our enum shall be a superset of booleans, hence first try
3229 * to parse as as boolean, and then as enum */
3231 k = parse_boolean(rvalue);
3233 c->protect_home = PROTECT_HOME_YES;
3235 c->protect_home = PROTECT_HOME_NO;
3239 h = protect_home_from_string(rvalue);
3241 log_syntax(unit, LOG_ERR, filename, line, -h,
3242 "Failed to parse protect home value, ignoring: %s", rvalue);
3246 c->protect_home = h;
3252 int config_parse_protect_system(
3254 const char *filename,
3256 const char *section,
3257 unsigned section_line,
3264 ExecContext *c = data;
3272 /* Our enum shall be a superset of booleans, hence first try
3273 * to parse as as boolean, and then as enum */
3275 k = parse_boolean(rvalue);
3277 c->protect_system = PROTECT_SYSTEM_YES;
3279 c->protect_system = PROTECT_SYSTEM_NO;
3283 s = protect_system_from_string(rvalue);
3285 log_syntax(unit, LOG_ERR, filename, line, -s,
3286 "Failed to parse protect system value, ignoring: %s", rvalue);
3290 c->protect_system = s;
3296 #define FOLLOW_MAX 8
3298 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3309 /* This will update the filename pointer if the loaded file is
3310 * reached by a symlink. The old string will be freed. */
3313 char *target, *name;
3315 if (c++ >= FOLLOW_MAX)
3318 path_kill_slashes(*filename);
3320 /* Add the file name we are currently looking at to
3321 * the names of this unit, but only if it is a valid
3323 name = basename(*filename);
3325 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3327 id = set_get(names, name);
3333 r = set_consume(names, id);
3339 /* Try to open the file name, but don't if its a symlink */
3340 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3347 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3348 r = readlink_and_make_absolute(*filename, &target);
3356 f = fdopen(fd, "re");
3368 static int merge_by_names(Unit **u, Set *names, const char *id) {
3376 /* Let's try to add in all symlink names we found */
3377 while ((k = set_steal_first(names))) {
3379 /* First try to merge in the other name into our
3381 r = unit_merge_by_name(*u, k);
3385 /* Hmm, we couldn't merge the other unit into
3386 * ours? Then let's try it the other way
3389 other = manager_get_unit((*u)->manager, k);
3393 r = unit_merge(other, *u);
3396 return merge_by_names(u, names, NULL);
3404 unit_choose_id(*u, id);
3412 static int load_from_path(Unit *u, const char *path) {
3414 _cleanup_set_free_free_ Set *symlink_names = NULL;
3415 _cleanup_fclose_ FILE *f = NULL;
3416 _cleanup_free_ char *filename = NULL;
3424 symlink_names = set_new(&string_hash_ops);
3428 if (path_is_absolute(path)) {
3430 filename = strdup(path);
3434 r = open_follow(&filename, &f, symlink_names, &id);
3446 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3448 /* Instead of opening the path right away, we manually
3449 * follow all symlinks and add their name to our unit
3450 * name set while doing so */
3451 filename = path_make_absolute(path, *p);
3455 if (u->manager->unit_path_cache &&
3456 !set_get(u->manager->unit_path_cache, filename))
3459 r = open_follow(&filename, &f, symlink_names, &id);
3468 /* Empty the symlink names for the next run */
3469 set_clear_free(symlink_names);
3478 /* Hmm, no suitable file found? */
3482 r = merge_by_names(&merged, symlink_names, id);
3487 u->load_state = UNIT_MERGED;
3491 if (fstat(fileno(f), &st) < 0)
3494 if (null_or_empty(&st))
3495 u->load_state = UNIT_MASKED;
3497 u->load_state = UNIT_LOADED;
3499 /* Now, parse the file contents */
3500 r = config_parse(u->id, filename, f,
3501 UNIT_VTABLE(u)->sections,
3502 config_item_perf_lookup, load_fragment_gperf_lookup,
3503 false, true, false, u);
3508 free(u->fragment_path);
3509 u->fragment_path = filename;
3512 u->fragment_mtime = timespec_load(&st.st_mtim);
3514 if (u->source_path) {
3515 if (stat(u->source_path, &st) >= 0)
3516 u->source_mtime = timespec_load(&st.st_mtim);
3518 u->source_mtime = 0;
3524 int unit_load_fragment(Unit *u) {
3530 assert(u->load_state == UNIT_STUB);
3533 /* First, try to find the unit under its id. We always look
3534 * for unit files in the default directories, to make it easy
3535 * to override things by placing things in /etc/systemd/system */
3536 r = load_from_path(u, u->id);
3540 /* Try to find an alias we can load this with */
3541 if (u->load_state == UNIT_STUB)
3542 SET_FOREACH(t, u->names, i) {
3547 r = load_from_path(u, t);
3551 if (u->load_state != UNIT_STUB)
3555 /* And now, try looking for it under the suggested (originally linked) path */
3556 if (u->load_state == UNIT_STUB && u->fragment_path) {
3558 r = load_from_path(u, u->fragment_path);
3562 if (u->load_state == UNIT_STUB) {
3563 /* Hmm, this didn't work? Then let's get rid
3564 * of the fragment path stored for us, so that
3565 * we don't point to an invalid location. */
3566 free(u->fragment_path);
3567 u->fragment_path = NULL;
3571 /* Look for a template */
3572 if (u->load_state == UNIT_STUB && u->instance) {
3573 _cleanup_free_ char *k;
3575 k = unit_name_template(u->id);
3579 r = load_from_path(u, k);
3583 if (u->load_state == UNIT_STUB)
3584 SET_FOREACH(t, u->names, i) {
3585 _cleanup_free_ char *z = NULL;
3590 z = unit_name_template(t);
3594 r = load_from_path(u, z);
3598 if (u->load_state != UNIT_STUB)
3606 void unit_dump_config_items(FILE *f) {
3607 static const struct {
3608 const ConfigParserCallback callback;
3611 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3612 { config_parse_warn_compat, "NOTSUPPORTED" },
3614 { config_parse_int, "INTEGER" },
3615 { config_parse_unsigned, "UNSIGNED" },
3616 { config_parse_iec_size, "SIZE" },
3617 { config_parse_iec_off, "SIZE" },
3618 { config_parse_si_size, "SIZE" },
3619 { config_parse_bool, "BOOLEAN" },
3620 { config_parse_string, "STRING" },
3621 { config_parse_path, "PATH" },
3622 { config_parse_unit_path_printf, "PATH" },
3623 { config_parse_strv, "STRING [...]" },
3624 { config_parse_exec_nice, "NICE" },
3625 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3626 { config_parse_exec_io_class, "IOCLASS" },
3627 { config_parse_exec_io_priority, "IOPRIORITY" },
3628 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3629 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3630 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3631 { config_parse_mode, "MODE" },
3632 { config_parse_unit_env_file, "FILE" },
3633 { config_parse_output, "OUTPUT" },
3634 { config_parse_input, "INPUT" },
3635 { config_parse_log_facility, "FACILITY" },
3636 { config_parse_log_level, "LEVEL" },
3637 { config_parse_exec_capabilities, "CAPABILITIES" },
3638 { config_parse_exec_secure_bits, "SECUREBITS" },
3639 { config_parse_bounding_set, "BOUNDINGSET" },
3640 { config_parse_limit, "LIMIT" },
3641 { config_parse_unit_deps, "UNIT [...]" },
3642 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3643 { config_parse_service_type, "SERVICETYPE" },
3644 { config_parse_service_restart, "SERVICERESTART" },
3645 #ifdef HAVE_SYSV_COMPAT
3646 { config_parse_sysv_priority, "SYSVPRIORITY" },
3648 { config_parse_kill_mode, "KILLMODE" },
3649 { config_parse_kill_signal, "SIGNAL" },
3650 { config_parse_socket_listen, "SOCKET [...]" },
3651 { config_parse_socket_bind, "SOCKETBIND" },
3652 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3653 { config_parse_sec, "SECONDS" },
3654 { config_parse_nsec, "NANOSECONDS" },
3655 { config_parse_namespace_path_strv, "PATH [...]" },
3656 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3657 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3658 { config_parse_unit_string_printf, "STRING" },
3659 { config_parse_trigger_unit, "UNIT" },
3660 { config_parse_timer, "TIMER" },
3661 { config_parse_path_spec, "PATH" },
3662 { config_parse_notify_access, "ACCESS" },
3663 { config_parse_ip_tos, "TOS" },
3664 { config_parse_unit_condition_path, "CONDITION" },
3665 { config_parse_unit_condition_string, "CONDITION" },
3666 { config_parse_unit_condition_null, "CONDITION" },
3667 { config_parse_unit_slice, "SLICE" },
3668 { config_parse_documentation, "URL" },
3669 { config_parse_service_timeout, "SECONDS" },
3670 { config_parse_failure_action, "ACTION" },
3671 { config_parse_set_status, "STATUS" },
3672 { config_parse_service_sockets, "SOCKETS" },
3673 { config_parse_environ, "ENVIRON" },
3675 { config_parse_syscall_filter, "SYSCALLS" },
3676 { config_parse_syscall_archs, "ARCHS" },
3677 { config_parse_syscall_errno, "ERRNO" },
3678 { config_parse_address_families, "FAMILIES" },
3680 { config_parse_cpu_shares, "SHARES" },
3681 { config_parse_memory_limit, "LIMIT" },
3682 { config_parse_device_allow, "DEVICE" },
3683 { config_parse_device_policy, "POLICY" },
3684 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3685 { config_parse_blockio_weight, "WEIGHT" },
3686 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3687 { config_parse_long, "LONG" },
3688 { config_parse_socket_service, "SERVICE" },
3690 { config_parse_exec_selinux_context, "LABEL" },
3692 { config_parse_job_mode, "MODE" },
3693 { config_parse_job_mode_isolate, "BOOLEAN" },
3694 { config_parse_personality, "PERSONALITY" },
3697 const char *prev = NULL;
3702 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3703 const char *rvalue = "OTHER", *lvalue;
3707 const ConfigPerfItem *p;
3709 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3711 dot = strchr(i, '.');
3712 lvalue = dot ? dot + 1 : i;
3716 if (!prev || !strneq(prev, i, prefix_len+1)) {
3720 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3723 for (j = 0; j < ELEMENTSOF(table); j++)
3724 if (p->parse == table[j].callback) {
3725 rvalue = table[j].rvalue;
3729 fprintf(f, "%s=%s\n", lvalue, rvalue);