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);
1369 calendar_spec_free(c);
1375 v->calendar_spec = c;
1377 LIST_PREPEND(value, t->values, v);
1382 int config_parse_trigger_unit(
1384 const char *filename,
1386 const char *section,
1387 unsigned section_line,
1394 _cleanup_free_ char *p = NULL;
1404 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1405 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1406 "Multiple units to trigger specified, ignoring: %s", rvalue);
1410 r = unit_name_printf(u, rvalue, &p);
1412 log_syntax(unit, LOG_ERR, filename, line, -r,
1413 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1415 type = unit_name_to_type(p ?: rvalue);
1417 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1418 "Unit type not valid, ignoring: %s", rvalue);
1422 if (type == u->type) {
1423 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1424 "Trigger cannot be of same type, ignoring: %s", rvalue);
1428 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1430 log_syntax(unit, LOG_ERR, filename, line, -r,
1431 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1438 int config_parse_path_spec(const char *unit,
1439 const char *filename,
1441 const char *section,
1442 unsigned section_line,
1452 _cleanup_free_ char *k = NULL;
1460 if (isempty(rvalue)) {
1461 /* Empty assignment clears list */
1466 b = path_type_from_string(lvalue);
1468 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1469 "Failed to parse path type, ignoring: %s", lvalue);
1473 r = unit_full_printf(UNIT(p), rvalue, &k);
1479 log_syntax(unit, LOG_ERR, filename, line, -r,
1480 "Failed to resolve unit specifiers on %s. Ignoring.",
1484 if (!path_is_absolute(k)) {
1485 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1486 "Path is not absolute, ignoring: %s", k);
1490 s = new0(PathSpec, 1);
1495 s->path = path_kill_slashes(k);
1500 LIST_PREPEND(spec, p->specs, s);
1505 int config_parse_socket_service(const char *unit,
1506 const char *filename,
1508 const char *section,
1509 unsigned section_line,
1516 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1520 _cleanup_free_ char *p = NULL;
1527 r = unit_name_printf(UNIT(s), rvalue, &p);
1529 log_syntax(unit, LOG_ERR, filename, line, -r,
1530 "Failed to resolve specifiers, ignoring: %s", rvalue);
1534 if (!endswith(p, ".service")) {
1535 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1536 "Unit must be of type service, ignoring: %s", rvalue);
1540 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1542 log_syntax(unit, LOG_ERR, filename, line, -r,
1543 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1547 unit_ref_set(&s->service, x);
1552 int config_parse_service_sockets(const char *unit,
1553 const char *filename,
1555 const char *section,
1556 unsigned section_line,
1565 const char *word, *state;
1573 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1574 _cleanup_free_ char *t = NULL, *k = NULL;
1576 t = strndup(word, l);
1580 r = unit_name_printf(UNIT(s), t, &k);
1582 log_syntax(unit, LOG_ERR, filename, line, -r,
1583 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1585 if (!endswith(k ?: t, ".socket")) {
1586 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1587 "Unit must be of type socket, ignoring: %s", k ?: t);
1591 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1593 log_syntax(unit, LOG_ERR, filename, line, -r,
1594 "Failed to add dependency on %s, ignoring: %s",
1595 k ?: t, strerror(-r));
1597 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1601 if (!isempty(state))
1602 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1603 "Trailing garbage, ignoring.");
1608 int config_parse_service_timeout(const char *unit,
1609 const char *filename,
1611 const char *section,
1612 unsigned section_line,
1619 Service *s = userdata;
1627 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1628 rvalue, data, userdata);
1632 if (streq(lvalue, "TimeoutSec")) {
1633 s->start_timeout_defined = true;
1634 s->timeout_stop_usec = s->timeout_start_usec;
1635 } else if (streq(lvalue, "TimeoutStartSec"))
1636 s->start_timeout_defined = true;
1641 int config_parse_busname_service(
1643 const char *filename,
1645 const char *section,
1646 unsigned section_line,
1653 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1657 _cleanup_free_ char *p = NULL;
1664 r = unit_name_printf(UNIT(n), rvalue, &p);
1666 log_syntax(unit, LOG_ERR, filename, line, -r,
1667 "Failed to resolve specifiers, ignoring: %s", rvalue);
1671 if (!endswith(p, ".service")) {
1672 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1673 "Unit must be of type service, ignoring: %s", rvalue);
1677 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1679 log_syntax(unit, LOG_ERR, filename, line, -r,
1680 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1684 unit_ref_set(&n->service, x);
1689 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1691 int config_parse_bus_policy(
1693 const char *filename,
1695 const char *section,
1696 unsigned section_line,
1703 _cleanup_free_ BusNamePolicy *p = NULL;
1704 _cleanup_free_ char *id_str = NULL;
1705 BusName *busname = data;
1713 p = new0(BusNamePolicy, 1);
1717 if (streq(lvalue, "AllowUser"))
1718 p->type = BUSNAME_POLICY_TYPE_USER;
1719 else if (streq(lvalue, "AllowGroup"))
1720 p->type = BUSNAME_POLICY_TYPE_GROUP;
1722 assert_not_reached("Unknown lvalue");
1724 id_str = strdup(rvalue);
1728 access_str = strpbrk(id_str, WHITESPACE);
1730 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1731 "Invalid busname policy value '%s'", rvalue);
1737 access_str += strspn(access_str, WHITESPACE);
1739 p->access = bus_policy_access_from_string(access_str);
1740 if (p->access < 0) {
1741 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1742 "Invalid busname policy access type '%s'", access_str);
1749 LIST_PREPEND(policy, busname->policy, p);
1755 int config_parse_bus_endpoint_policy(
1757 const char *filename,
1759 const char *section,
1760 unsigned section_line,
1767 _cleanup_free_ char *name = NULL;
1768 BusPolicyAccess access;
1769 ExecContext *c = data;
1778 name = strdup(rvalue);
1782 access_str = strpbrk(name, WHITESPACE);
1784 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1785 "Invalid endpoint policy value '%s'", rvalue);
1791 access_str += strspn(access_str, WHITESPACE);
1793 access = bus_policy_access_from_string(access_str);
1794 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1795 access >= _BUS_POLICY_ACCESS_MAX) {
1796 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1797 "Invalid endpoint policy access type '%s'", access_str);
1801 if (!c->bus_endpoint) {
1802 r = bus_endpoint_new(&c->bus_endpoint);
1808 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1811 int config_parse_unit_env_file(const char *unit,
1812 const char *filename,
1814 const char *section,
1815 unsigned section_line,
1824 _cleanup_free_ char *n = NULL;
1833 if (isempty(rvalue)) {
1834 /* Empty assignment frees the list */
1840 r = unit_full_printf(u, rvalue, &n);
1842 log_syntax(unit, LOG_ERR, filename, line, -r,
1843 "Failed to resolve specifiers, ignoring: %s", rvalue);
1846 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1847 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1848 "Path '%s' is not absolute, ignoring.", s);
1852 r = strv_extend(env, s);
1859 int config_parse_environ(const char *unit,
1860 const char *filename,
1862 const char *section,
1863 unsigned section_line,
1872 const char *word, *state;
1874 _cleanup_free_ char *k = NULL;
1882 if (isempty(rvalue)) {
1883 /* Empty assignment resets the list */
1890 r = unit_full_printf(u, rvalue, &k);
1892 log_syntax(unit, LOG_ERR, filename, line, -r,
1893 "Failed to resolve specifiers, ignoring: %s", rvalue);
1901 FOREACH_WORD_QUOTED(word, l, k, state) {
1902 _cleanup_free_ char *n;
1905 n = cunescape_length(word, l);
1909 if (!env_assignment_is_valid(n)) {
1910 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1911 "Invalid environment assignment, ignoring: %s", rvalue);
1915 x = strv_env_set(*env, n);
1922 if (!isempty(state))
1923 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1924 "Trailing garbage, ignoring.");
1929 int config_parse_ip_tos(const char *unit,
1930 const char *filename,
1932 const char *section,
1933 unsigned section_line,
1940 int *ip_tos = data, x;
1947 x = ip_tos_from_string(rvalue);
1949 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1950 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1958 int config_parse_unit_condition_path(
1960 const char *filename,
1962 const char *section,
1963 unsigned section_line,
1970 _cleanup_free_ char *p = NULL;
1971 Condition **list = data, *c;
1972 ConditionType t = ltype;
1973 bool trigger, negate;
1982 if (isempty(rvalue)) {
1983 /* Empty assignment resets the list */
1984 condition_free_list(*list);
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, "Failed to resolve specifiers, ignoring: %s", rvalue);
2003 if (!path_is_absolute(p)) {
2004 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2008 c = condition_new(t, p, trigger, negate);
2012 LIST_PREPEND(conditions, *list, c);
2016 int config_parse_unit_condition_string(
2018 const char *filename,
2020 const char *section,
2021 unsigned section_line,
2028 _cleanup_free_ char *s = NULL;
2029 Condition **list = data, *c;
2030 ConditionType t = ltype;
2031 bool trigger, negate;
2040 if (isempty(rvalue)) {
2041 /* Empty assignment resets the list */
2042 condition_free_list(*list);
2047 trigger = rvalue[0] == '|';
2051 negate = rvalue[0] == '!';
2055 r = unit_full_printf(u, rvalue, &s);
2057 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2061 c = condition_new(t, s, trigger, negate);
2065 LIST_PREPEND(conditions, *list, c);
2069 int config_parse_unit_condition_null(
2071 const char *filename,
2073 const char *section,
2074 unsigned section_line,
2081 Condition **list = data, *c;
2082 bool trigger, negate;
2090 if (isempty(rvalue)) {
2091 /* Empty assignment resets the list */
2092 condition_free_list(*list);
2097 trigger = rvalue[0] == '|';
2101 negate = rvalue[0] == '!';
2105 b = parse_boolean(rvalue);
2107 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2114 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2118 LIST_PREPEND(conditions, *list, c);
2122 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2123 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2125 int config_parse_unit_requires_mounts_for(
2127 const char *filename,
2129 const char *section,
2130 unsigned section_line,
2138 const char *word, *state;
2146 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2148 _cleanup_free_ char *n;
2150 n = strndup(word, l);
2154 if (!utf8_is_valid(n)) {
2155 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2159 r = unit_require_mounts_for(u, n);
2161 log_syntax(unit, LOG_ERR, filename, line, -r,
2162 "Failed to add required mount for, ignoring: %s", rvalue);
2166 if (!isempty(state))
2167 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2168 "Trailing garbage, ignoring.");
2173 int config_parse_documentation(const char *unit,
2174 const char *filename,
2176 const char *section,
2177 unsigned section_line,
2193 if (isempty(rvalue)) {
2194 /* Empty assignment resets the list */
2195 strv_free(u->documentation);
2196 u->documentation = NULL;
2200 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2201 rvalue, data, userdata);
2205 for (a = b = u->documentation; a && *a; a++) {
2207 if (is_valid_documentation_url(*a))
2210 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2211 "Invalid URL, ignoring: %s", *a);
2222 int config_parse_syscall_filter(
2224 const char *filename,
2226 const char *section,
2227 unsigned section_line,
2234 static const char default_syscalls[] =
2241 ExecContext *c = data;
2243 bool invert = false;
2244 const char *word, *state;
2253 if (isempty(rvalue)) {
2254 /* Empty assignment resets the list */
2255 set_free(c->syscall_filter);
2256 c->syscall_filter = NULL;
2257 c->syscall_whitelist = false;
2261 if (rvalue[0] == '~') {
2266 if (!c->syscall_filter) {
2267 c->syscall_filter = set_new(NULL);
2268 if (!c->syscall_filter)
2272 /* Allow everything but the ones listed */
2273 c->syscall_whitelist = false;
2277 /* Allow nothing but the ones listed */
2278 c->syscall_whitelist = true;
2280 /* Accept default syscalls if we are on a whitelist */
2281 NULSTR_FOREACH(i, default_syscalls) {
2284 id = seccomp_syscall_resolve_name(i);
2288 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2297 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2298 _cleanup_free_ char *t = NULL;
2301 t = strndup(word, l);
2305 id = seccomp_syscall_resolve_name(t);
2307 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2308 "Failed to parse system call, ignoring: %s", t);
2312 /* If we previously wanted to forbid a syscall and now
2313 * we want to allow it, then remove it from the list
2315 if (!invert == c->syscall_whitelist) {
2316 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2322 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2324 if (!isempty(state))
2325 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2326 "Trailing garbage, ignoring.");
2328 /* Turn on NNP, but only if it wasn't configured explicitly
2329 * before, and only if we are in user mode. */
2330 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2331 c->no_new_privileges = true;
2336 int config_parse_syscall_archs(
2338 const char *filename,
2340 const char *section,
2341 unsigned section_line,
2349 const char *word, *state;
2353 if (isempty(rvalue)) {
2359 r = set_ensure_allocated(archs, NULL);
2363 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2364 _cleanup_free_ char *t = NULL;
2367 t = strndup(word, l);
2371 r = seccomp_arch_from_string(t, &a);
2373 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2374 "Failed to parse system call architecture, ignoring: %s", t);
2378 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2384 if (!isempty(state))
2385 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2386 "Trailing garbage, ignoring.");
2391 int config_parse_syscall_errno(
2393 const char *filename,
2395 const char *section,
2396 unsigned section_line,
2403 ExecContext *c = data;
2410 if (isempty(rvalue)) {
2411 /* Empty assignment resets to KILL */
2412 c->syscall_errno = 0;
2416 e = errno_from_name(rvalue);
2418 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2419 "Failed to parse error number, ignoring: %s", rvalue);
2423 c->syscall_errno = e;
2427 int config_parse_address_families(
2429 const char *filename,
2431 const char *section,
2432 unsigned section_line,
2439 ExecContext *c = data;
2441 bool invert = false;
2442 const char *word, *state;
2451 if (isempty(rvalue)) {
2452 /* Empty assignment resets the list */
2453 set_free(c->address_families);
2454 c->address_families = NULL;
2455 c->address_families_whitelist = false;
2459 if (rvalue[0] == '~') {
2464 if (!c->address_families) {
2465 c->address_families = set_new(NULL);
2466 if (!c->address_families)
2469 c->address_families_whitelist = !invert;
2472 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2473 _cleanup_free_ char *t = NULL;
2476 t = strndup(word, l);
2480 af = af_from_name(t);
2482 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2483 "Failed to parse address family, ignoring: %s", t);
2487 /* If we previously wanted to forbid an address family and now
2488 * we want to allow it, then remove it from the list
2490 if (!invert == c->address_families_whitelist) {
2491 r = set_put(c->address_families, INT_TO_PTR(af));
2497 set_remove(c->address_families, INT_TO_PTR(af));
2499 if (!isempty(state))
2500 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2501 "Trailing garbage, ignoring.");
2507 int config_parse_unit_slice(
2509 const char *filename,
2511 const char *section,
2512 unsigned section_line,
2519 _cleanup_free_ char *k = NULL;
2520 Unit *u = userdata, *slice;
2528 r = unit_name_printf(u, rvalue, &k);
2530 log_syntax(unit, LOG_ERR, filename, line, -r,
2531 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2538 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2540 log_syntax(unit, LOG_ERR, filename, line, -r,
2541 "Failed to load slice unit %s. Ignoring.", k);
2545 if (slice->type != UNIT_SLICE) {
2546 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2547 "Slice unit %s is not a slice. Ignoring.", k);
2551 unit_ref_set(&u->slice, slice);
2555 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2557 int config_parse_cpu_shares(
2559 const char *filename,
2561 const char *section,
2562 unsigned section_line,
2569 unsigned long *shares = data, lu;
2576 if (isempty(rvalue)) {
2577 *shares = (unsigned long) -1;
2581 r = safe_atolu(rvalue, &lu);
2582 if (r < 0 || lu <= 0) {
2583 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2584 "CPU shares '%s' invalid. Ignoring.", rvalue);
2592 int config_parse_cpu_quota(
2594 const char *filename,
2596 const char *section,
2597 unsigned section_line,
2604 CGroupContext *c = data;
2611 if (isempty(rvalue)) {
2612 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2616 if (!endswith(rvalue, "%")) {
2618 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2619 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2623 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2624 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2625 "CPU quota '%s' invalid. Ignoring.", rvalue);
2629 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2634 int config_parse_memory_limit(
2636 const char *filename,
2638 const char *section,
2639 unsigned section_line,
2646 CGroupContext *c = data;
2650 if (isempty(rvalue)) {
2651 c->memory_limit = (uint64_t) -1;
2655 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2657 r = parse_size(rvalue, 1024, &bytes);
2659 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2660 "Memory limit '%s' invalid. Ignoring.", rvalue);
2664 c->memory_limit = (uint64_t) bytes;
2668 int config_parse_device_allow(
2670 const char *filename,
2672 const char *section,
2673 unsigned section_line,
2680 _cleanup_free_ char *path = NULL;
2681 CGroupContext *c = data;
2682 CGroupDeviceAllow *a;
2686 if (isempty(rvalue)) {
2687 while (c->device_allow)
2688 cgroup_context_free_device_allow(c, c->device_allow);
2693 n = strcspn(rvalue, WHITESPACE);
2694 path = strndup(rvalue, n);
2698 if (!startswith(path, "/dev/") &&
2699 !startswith(path, "block-") &&
2700 !startswith(path, "char-")) {
2701 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2702 "Invalid device node path '%s'. Ignoring.", path);
2706 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2710 if (!in_charset(m, "rwm")) {
2711 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2712 "Invalid device rights '%s'. Ignoring.", m);
2716 a = new0(CGroupDeviceAllow, 1);
2722 a->r = !!strchr(m, 'r');
2723 a->w = !!strchr(m, 'w');
2724 a->m = !!strchr(m, 'm');
2726 LIST_PREPEND(device_allow, c->device_allow, a);
2730 int config_parse_blockio_weight(
2732 const char *filename,
2734 const char *section,
2735 unsigned section_line,
2742 unsigned long *weight = data, lu;
2749 if (isempty(rvalue)) {
2750 *weight = (unsigned long) -1;
2754 r = safe_atolu(rvalue, &lu);
2755 if (r < 0 || lu < 10 || lu > 1000) {
2756 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2757 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2765 int config_parse_blockio_device_weight(
2767 const char *filename,
2769 const char *section,
2770 unsigned section_line,
2777 _cleanup_free_ char *path = NULL;
2778 CGroupBlockIODeviceWeight *w;
2779 CGroupContext *c = data;
2789 if (isempty(rvalue)) {
2790 while (c->blockio_device_weights)
2791 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2796 n = strcspn(rvalue, WHITESPACE);
2797 weight = rvalue + n;
2799 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2800 "Expected block device and device weight. Ignoring.");
2804 path = strndup(rvalue, n);
2808 if (!path_startswith(path, "/dev")) {
2809 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2810 "Invalid device node path '%s'. Ignoring.", path);
2814 weight += strspn(weight, WHITESPACE);
2815 r = safe_atolu(weight, &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);
2822 w = new0(CGroupBlockIODeviceWeight, 1);
2831 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2835 int config_parse_blockio_bandwidth(
2837 const char *filename,
2839 const char *section,
2840 unsigned section_line,
2847 _cleanup_free_ char *path = NULL;
2848 CGroupBlockIODeviceBandwidth *b;
2849 CGroupContext *c = data;
2850 const char *bandwidth;
2860 read = streq("BlockIOReadBandwidth", lvalue);
2862 if (isempty(rvalue)) {
2863 CGroupBlockIODeviceBandwidth *next;
2865 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2866 if (b->read == read)
2867 cgroup_context_free_blockio_device_bandwidth(c, b);
2872 n = strcspn(rvalue, WHITESPACE);
2873 bandwidth = rvalue + n;
2874 bandwidth += strspn(bandwidth, WHITESPACE);
2877 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2878 "Expected space separated pair of device node and bandwidth. Ignoring.");
2882 path = strndup(rvalue, n);
2886 if (!path_startswith(path, "/dev")) {
2887 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2888 "Invalid device node path '%s'. Ignoring.", path);
2892 r = parse_size(bandwidth, 1000, &bytes);
2893 if (r < 0 || bytes <= 0) {
2894 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2895 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2899 b = new0(CGroupBlockIODeviceBandwidth, 1);
2905 b->bandwidth = (uint64_t) bytes;
2908 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2913 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2915 int config_parse_job_mode_isolate(
2917 const char *filename,
2919 const char *section,
2920 unsigned section_line,
2934 r = parse_boolean(rvalue);
2936 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2937 "Failed to parse boolean, ignoring: %s", rvalue);
2941 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2945 int config_parse_personality(
2947 const char *filename,
2949 const char *section,
2950 unsigned section_line,
2957 unsigned long *personality = data, p;
2962 assert(personality);
2964 p = personality_from_string(rvalue);
2965 if (p == 0xffffffffUL) {
2966 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2967 "Failed to parse personality, ignoring: %s", rvalue);
2975 int config_parse_runtime_directory(
2977 const char *filename,
2979 const char *section,
2980 unsigned section_line,
2988 const char *word, *state;
2997 if (isempty(rvalue)) {
2998 /* Empty assignment resets the list */
3004 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3005 _cleanup_free_ char *n;
3007 n = strndup(word, l);
3011 if (!filename_is_safe(n)) {
3012 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3013 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3017 r = strv_push(rt, n);
3023 if (!isempty(state))
3024 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3025 "Trailing garbage, ignoring.");
3030 int config_parse_set_status(
3032 const char *filename,
3034 const char *section,
3035 unsigned section_line,
3043 const char *word, *state;
3045 ExitStatusSet *status_set = data;
3052 /* Empty assignment resets the list */
3053 if (isempty(rvalue)) {
3054 exit_status_set_free(status_set);
3058 FOREACH_WORD(word, l, rvalue, state) {
3059 _cleanup_free_ char *temp;
3062 temp = strndup(word, l);
3066 r = safe_atoi(temp, &val);
3068 val = signal_from_string_try_harder(temp);
3071 log_syntax(unit, LOG_ERR, filename, line, -val,
3072 "Failed to parse value, ignoring: %s", word);
3076 if (val < 0 || val > 255) {
3077 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3078 "Value %d is outside range 0-255, ignoring", val);
3083 r = set_ensure_allocated(&status_set->status, NULL);
3087 r = set_put(status_set->status, INT_TO_PTR(val));
3089 log_syntax(unit, LOG_ERR, filename, line, -r,
3090 "Unable to store: %s", word);
3094 if (!isempty(state))
3095 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3096 "Trailing garbage, ignoring.");
3101 int config_parse_namespace_path_strv(
3103 const char *filename,
3105 const char *section,
3106 unsigned section_line,
3114 const char *word, *state;
3123 if (isempty(rvalue)) {
3124 /* Empty assignment resets the list */
3130 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3131 _cleanup_free_ char *n;
3134 n = strndup(word, l);
3138 if (!utf8_is_valid(n)) {
3139 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3143 offset = n[0] == '-';
3144 if (!path_is_absolute(n + offset)) {
3145 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3146 "Not an absolute path, ignoring: %s", rvalue);
3150 path_kill_slashes(n);
3152 r = strv_push(sv, n);
3158 if (!isempty(state))
3159 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3160 "Trailing garbage, ignoring.");
3165 int config_parse_no_new_privileges(
3167 const char *filename,
3169 const char *section,
3170 unsigned section_line,
3177 ExecContext *c = data;
3185 k = parse_boolean(rvalue);
3187 log_syntax(unit, LOG_ERR, filename, line, -k,
3188 "Failed to parse boolean value, ignoring: %s", rvalue);
3192 c->no_new_privileges = !!k;
3193 c->no_new_privileges_set = true;
3198 int config_parse_protect_home(
3200 const char *filename,
3202 const char *section,
3203 unsigned section_line,
3210 ExecContext *c = data;
3218 /* Our enum shall be a superset of booleans, hence first try
3219 * to parse as as boolean, and then as enum */
3221 k = parse_boolean(rvalue);
3223 c->protect_home = PROTECT_HOME_YES;
3225 c->protect_home = PROTECT_HOME_NO;
3229 h = protect_home_from_string(rvalue);
3231 log_syntax(unit, LOG_ERR, filename, line, -h,
3232 "Failed to parse protect home value, ignoring: %s", rvalue);
3236 c->protect_home = h;
3242 int config_parse_protect_system(
3244 const char *filename,
3246 const char *section,
3247 unsigned section_line,
3254 ExecContext *c = data;
3262 /* Our enum shall be a superset of booleans, hence first try
3263 * to parse as as boolean, and then as enum */
3265 k = parse_boolean(rvalue);
3267 c->protect_system = PROTECT_SYSTEM_YES;
3269 c->protect_system = PROTECT_SYSTEM_NO;
3273 s = protect_system_from_string(rvalue);
3275 log_syntax(unit, LOG_ERR, filename, line, -s,
3276 "Failed to parse protect system value, ignoring: %s", rvalue);
3280 c->protect_system = s;
3286 #define FOLLOW_MAX 8
3288 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3299 /* This will update the filename pointer if the loaded file is
3300 * reached by a symlink. The old string will be freed. */
3303 char *target, *name;
3305 if (c++ >= FOLLOW_MAX)
3308 path_kill_slashes(*filename);
3310 /* Add the file name we are currently looking at to
3311 * the names of this unit, but only if it is a valid
3313 name = basename(*filename);
3315 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3317 id = set_get(names, name);
3323 r = set_consume(names, id);
3329 /* Try to open the file name, but don't if its a symlink */
3330 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3337 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3338 r = readlink_and_make_absolute(*filename, &target);
3346 f = fdopen(fd, "re");
3358 static int merge_by_names(Unit **u, Set *names, const char *id) {
3366 /* Let's try to add in all symlink names we found */
3367 while ((k = set_steal_first(names))) {
3369 /* First try to merge in the other name into our
3371 r = unit_merge_by_name(*u, k);
3375 /* Hmm, we couldn't merge the other unit into
3376 * ours? Then let's try it the other way
3379 other = manager_get_unit((*u)->manager, k);
3383 r = unit_merge(other, *u);
3386 return merge_by_names(u, names, NULL);
3394 unit_choose_id(*u, id);
3402 static int load_from_path(Unit *u, const char *path) {
3404 _cleanup_set_free_free_ Set *symlink_names = NULL;
3405 _cleanup_fclose_ FILE *f = NULL;
3406 _cleanup_free_ char *filename = NULL;
3414 symlink_names = set_new(&string_hash_ops);
3418 if (path_is_absolute(path)) {
3420 filename = strdup(path);
3424 r = open_follow(&filename, &f, symlink_names, &id);
3436 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3438 /* Instead of opening the path right away, we manually
3439 * follow all symlinks and add their name to our unit
3440 * name set while doing so */
3441 filename = path_make_absolute(path, *p);
3445 if (u->manager->unit_path_cache &&
3446 !set_get(u->manager->unit_path_cache, filename))
3449 r = open_follow(&filename, &f, symlink_names, &id);
3458 /* Empty the symlink names for the next run */
3459 set_clear_free(symlink_names);
3468 /* Hmm, no suitable file found? */
3472 r = merge_by_names(&merged, symlink_names, id);
3477 u->load_state = UNIT_MERGED;
3481 if (fstat(fileno(f), &st) < 0)
3484 if (null_or_empty(&st))
3485 u->load_state = UNIT_MASKED;
3487 u->load_state = UNIT_LOADED;
3489 /* Now, parse the file contents */
3490 r = config_parse(u->id, filename, f,
3491 UNIT_VTABLE(u)->sections,
3492 config_item_perf_lookup, load_fragment_gperf_lookup,
3493 false, true, false, u);
3498 free(u->fragment_path);
3499 u->fragment_path = filename;
3502 u->fragment_mtime = timespec_load(&st.st_mtim);
3504 if (u->source_path) {
3505 if (stat(u->source_path, &st) >= 0)
3506 u->source_mtime = timespec_load(&st.st_mtim);
3508 u->source_mtime = 0;
3514 int unit_load_fragment(Unit *u) {
3520 assert(u->load_state == UNIT_STUB);
3523 /* First, try to find the unit under its id. We always look
3524 * for unit files in the default directories, to make it easy
3525 * to override things by placing things in /etc/systemd/system */
3526 r = load_from_path(u, u->id);
3530 /* Try to find an alias we can load this with */
3531 if (u->load_state == UNIT_STUB)
3532 SET_FOREACH(t, u->names, i) {
3537 r = load_from_path(u, t);
3541 if (u->load_state != UNIT_STUB)
3545 /* And now, try looking for it under the suggested (originally linked) path */
3546 if (u->load_state == UNIT_STUB && u->fragment_path) {
3548 r = load_from_path(u, u->fragment_path);
3552 if (u->load_state == UNIT_STUB) {
3553 /* Hmm, this didn't work? Then let's get rid
3554 * of the fragment path stored for us, so that
3555 * we don't point to an invalid location. */
3556 free(u->fragment_path);
3557 u->fragment_path = NULL;
3561 /* Look for a template */
3562 if (u->load_state == UNIT_STUB && u->instance) {
3563 _cleanup_free_ char *k;
3565 k = unit_name_template(u->id);
3569 r = load_from_path(u, k);
3573 if (u->load_state == UNIT_STUB)
3574 SET_FOREACH(t, u->names, i) {
3575 _cleanup_free_ char *z = NULL;
3580 z = unit_name_template(t);
3584 r = load_from_path(u, z);
3588 if (u->load_state != UNIT_STUB)
3596 void unit_dump_config_items(FILE *f) {
3597 static const struct {
3598 const ConfigParserCallback callback;
3601 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3602 { config_parse_warn_compat, "NOTSUPPORTED" },
3604 { config_parse_int, "INTEGER" },
3605 { config_parse_unsigned, "UNSIGNED" },
3606 { config_parse_iec_size, "SIZE" },
3607 { config_parse_iec_off, "SIZE" },
3608 { config_parse_si_size, "SIZE" },
3609 { config_parse_bool, "BOOLEAN" },
3610 { config_parse_string, "STRING" },
3611 { config_parse_path, "PATH" },
3612 { config_parse_unit_path_printf, "PATH" },
3613 { config_parse_strv, "STRING [...]" },
3614 { config_parse_exec_nice, "NICE" },
3615 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3616 { config_parse_exec_io_class, "IOCLASS" },
3617 { config_parse_exec_io_priority, "IOPRIORITY" },
3618 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3619 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3620 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3621 { config_parse_mode, "MODE" },
3622 { config_parse_unit_env_file, "FILE" },
3623 { config_parse_output, "OUTPUT" },
3624 { config_parse_input, "INPUT" },
3625 { config_parse_log_facility, "FACILITY" },
3626 { config_parse_log_level, "LEVEL" },
3627 { config_parse_exec_capabilities, "CAPABILITIES" },
3628 { config_parse_exec_secure_bits, "SECUREBITS" },
3629 { config_parse_bounding_set, "BOUNDINGSET" },
3630 { config_parse_limit, "LIMIT" },
3631 { config_parse_unit_deps, "UNIT [...]" },
3632 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3633 { config_parse_service_type, "SERVICETYPE" },
3634 { config_parse_service_restart, "SERVICERESTART" },
3635 #ifdef HAVE_SYSV_COMPAT
3636 { config_parse_sysv_priority, "SYSVPRIORITY" },
3638 { config_parse_kill_mode, "KILLMODE" },
3639 { config_parse_kill_signal, "SIGNAL" },
3640 { config_parse_socket_listen, "SOCKET [...]" },
3641 { config_parse_socket_bind, "SOCKETBIND" },
3642 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3643 { config_parse_sec, "SECONDS" },
3644 { config_parse_nsec, "NANOSECONDS" },
3645 { config_parse_namespace_path_strv, "PATH [...]" },
3646 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3647 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3648 { config_parse_unit_string_printf, "STRING" },
3649 { config_parse_trigger_unit, "UNIT" },
3650 { config_parse_timer, "TIMER" },
3651 { config_parse_path_spec, "PATH" },
3652 { config_parse_notify_access, "ACCESS" },
3653 { config_parse_ip_tos, "TOS" },
3654 { config_parse_unit_condition_path, "CONDITION" },
3655 { config_parse_unit_condition_string, "CONDITION" },
3656 { config_parse_unit_condition_null, "CONDITION" },
3657 { config_parse_unit_slice, "SLICE" },
3658 { config_parse_documentation, "URL" },
3659 { config_parse_service_timeout, "SECONDS" },
3660 { config_parse_failure_action, "ACTION" },
3661 { config_parse_set_status, "STATUS" },
3662 { config_parse_service_sockets, "SOCKETS" },
3663 { config_parse_environ, "ENVIRON" },
3665 { config_parse_syscall_filter, "SYSCALLS" },
3666 { config_parse_syscall_archs, "ARCHS" },
3667 { config_parse_syscall_errno, "ERRNO" },
3668 { config_parse_address_families, "FAMILIES" },
3670 { config_parse_cpu_shares, "SHARES" },
3671 { config_parse_memory_limit, "LIMIT" },
3672 { config_parse_device_allow, "DEVICE" },
3673 { config_parse_device_policy, "POLICY" },
3674 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3675 { config_parse_blockio_weight, "WEIGHT" },
3676 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3677 { config_parse_long, "LONG" },
3678 { config_parse_socket_service, "SERVICE" },
3680 { config_parse_exec_selinux_context, "LABEL" },
3682 { config_parse_job_mode, "MODE" },
3683 { config_parse_job_mode_isolate, "BOOLEAN" },
3684 { config_parse_personality, "PERSONALITY" },
3687 const char *prev = NULL;
3692 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3693 const char *rvalue = "OTHER", *lvalue;
3697 const ConfigPerfItem *p;
3699 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3701 dot = strchr(i, '.');
3702 lvalue = dot ? dot + 1 : i;
3706 if (!prev || !strneq(prev, i, prefix_len+1)) {
3710 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3713 for (j = 0; j < ELEMENTSOF(table); j++)
3714 if (p->parse == table[j].callback) {
3715 rvalue = table[j].rvalue;
3719 fprintf(f, "%s=%s\n", lvalue, rvalue);