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_exec_smack_process_label(
1318 const char *filename,
1320 const char *section,
1321 unsigned section_line,
1328 ExecContext *c = data;
1339 if (isempty(rvalue)) {
1340 free(c->smack_process_label);
1341 c->smack_process_label = NULL;
1342 c->smack_process_label_ignore = false;
1346 if (rvalue[0] == '-') {
1352 r = unit_name_printf(u, rvalue, &k);
1354 log_syntax(unit, LOG_ERR, filename, line, -r,
1355 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1359 free(c->smack_process_label);
1360 c->smack_process_label = k;
1361 c->smack_process_label_ignore = ignore;
1366 int config_parse_timer(const char *unit,
1367 const char *filename,
1369 const char *section,
1370 unsigned section_line,
1381 CalendarSpec *c = NULL;
1388 if (isempty(rvalue)) {
1389 /* Empty assignment resets list */
1390 timer_free_values(t);
1394 b = timer_base_from_string(lvalue);
1396 log_syntax(unit, LOG_ERR, filename, line, -b,
1397 "Failed to parse timer base, ignoring: %s", lvalue);
1401 if (b == TIMER_CALENDAR) {
1402 if (calendar_spec_from_string(rvalue, &c) < 0) {
1403 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1404 "Failed to parse calendar specification, ignoring: %s",
1409 if (parse_sec(rvalue, &u) < 0) {
1410 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1411 "Failed to parse timer value, ignoring: %s",
1417 v = new0(TimerValue, 1);
1419 calendar_spec_free(c);
1425 v->calendar_spec = c;
1427 LIST_PREPEND(value, t->values, v);
1432 int config_parse_trigger_unit(
1434 const char *filename,
1436 const char *section,
1437 unsigned section_line,
1444 _cleanup_free_ char *p = NULL;
1454 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1455 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1456 "Multiple units to trigger specified, ignoring: %s", rvalue);
1460 r = unit_name_printf(u, rvalue, &p);
1462 log_syntax(unit, LOG_ERR, filename, line, -r,
1463 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1465 type = unit_name_to_type(p ?: rvalue);
1467 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1468 "Unit type not valid, ignoring: %s", rvalue);
1472 if (type == u->type) {
1473 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1474 "Trigger cannot be of same type, ignoring: %s", rvalue);
1478 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1480 log_syntax(unit, LOG_ERR, filename, line, -r,
1481 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1488 int config_parse_path_spec(const char *unit,
1489 const char *filename,
1491 const char *section,
1492 unsigned section_line,
1502 _cleanup_free_ char *k = NULL;
1510 if (isempty(rvalue)) {
1511 /* Empty assignment clears list */
1516 b = path_type_from_string(lvalue);
1518 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1519 "Failed to parse path type, ignoring: %s", lvalue);
1523 r = unit_full_printf(UNIT(p), rvalue, &k);
1529 log_syntax(unit, LOG_ERR, filename, line, -r,
1530 "Failed to resolve unit specifiers on %s. Ignoring.",
1534 if (!path_is_absolute(k)) {
1535 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1536 "Path is not absolute, ignoring: %s", k);
1540 s = new0(PathSpec, 1);
1545 s->path = path_kill_slashes(k);
1550 LIST_PREPEND(spec, p->specs, s);
1555 int config_parse_socket_service(const char *unit,
1556 const char *filename,
1558 const char *section,
1559 unsigned section_line,
1566 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1570 _cleanup_free_ char *p = NULL;
1577 r = unit_name_printf(UNIT(s), rvalue, &p);
1579 log_syntax(unit, LOG_ERR, filename, line, -r,
1580 "Failed to resolve specifiers, ignoring: %s", rvalue);
1584 if (!endswith(p, ".service")) {
1585 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1586 "Unit must be of type service, ignoring: %s", rvalue);
1590 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1592 log_syntax(unit, LOG_ERR, filename, line, -r,
1593 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1597 unit_ref_set(&s->service, x);
1602 int config_parse_service_sockets(const char *unit,
1603 const char *filename,
1605 const char *section,
1606 unsigned section_line,
1615 const char *word, *state;
1623 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1624 _cleanup_free_ char *t = NULL, *k = NULL;
1626 t = strndup(word, l);
1630 r = unit_name_printf(UNIT(s), t, &k);
1632 log_syntax(unit, LOG_ERR, filename, line, -r,
1633 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1635 if (!endswith(k ?: t, ".socket")) {
1636 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1637 "Unit must be of type socket, ignoring: %s", k ?: t);
1641 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1643 log_syntax(unit, LOG_ERR, filename, line, -r,
1644 "Failed to add dependency on %s, ignoring: %s",
1645 k ?: t, strerror(-r));
1647 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1651 if (!isempty(state))
1652 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1653 "Trailing garbage, ignoring.");
1658 int config_parse_service_timeout(const char *unit,
1659 const char *filename,
1661 const char *section,
1662 unsigned section_line,
1669 Service *s = userdata;
1677 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1678 rvalue, data, userdata);
1682 if (streq(lvalue, "TimeoutSec")) {
1683 s->start_timeout_defined = true;
1684 s->timeout_stop_usec = s->timeout_start_usec;
1685 } else if (streq(lvalue, "TimeoutStartSec"))
1686 s->start_timeout_defined = true;
1691 int config_parse_busname_service(
1693 const char *filename,
1695 const char *section,
1696 unsigned section_line,
1703 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1707 _cleanup_free_ char *p = NULL;
1714 r = unit_name_printf(UNIT(n), rvalue, &p);
1716 log_syntax(unit, LOG_ERR, filename, line, -r,
1717 "Failed to resolve specifiers, ignoring: %s", rvalue);
1721 if (!endswith(p, ".service")) {
1722 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1723 "Unit must be of type service, ignoring: %s", rvalue);
1727 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1729 log_syntax(unit, LOG_ERR, filename, line, -r,
1730 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1734 unit_ref_set(&n->service, x);
1739 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1741 int config_parse_bus_policy(
1743 const char *filename,
1745 const char *section,
1746 unsigned section_line,
1753 _cleanup_free_ BusNamePolicy *p = NULL;
1754 _cleanup_free_ char *id_str = NULL;
1755 BusName *busname = data;
1763 p = new0(BusNamePolicy, 1);
1767 if (streq(lvalue, "AllowUser"))
1768 p->type = BUSNAME_POLICY_TYPE_USER;
1769 else if (streq(lvalue, "AllowGroup"))
1770 p->type = BUSNAME_POLICY_TYPE_GROUP;
1772 assert_not_reached("Unknown lvalue");
1774 id_str = strdup(rvalue);
1778 access_str = strpbrk(id_str, WHITESPACE);
1780 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1781 "Invalid busname policy value '%s'", rvalue);
1787 access_str += strspn(access_str, WHITESPACE);
1789 p->access = bus_policy_access_from_string(access_str);
1790 if (p->access < 0) {
1791 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1792 "Invalid busname policy access type '%s'", access_str);
1799 LIST_PREPEND(policy, busname->policy, p);
1805 int config_parse_bus_endpoint_policy(
1807 const char *filename,
1809 const char *section,
1810 unsigned section_line,
1817 _cleanup_free_ char *name = NULL;
1818 BusPolicyAccess access;
1819 ExecContext *c = data;
1828 name = strdup(rvalue);
1832 access_str = strpbrk(name, WHITESPACE);
1834 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1835 "Invalid endpoint policy value '%s'", rvalue);
1841 access_str += strspn(access_str, WHITESPACE);
1843 access = bus_policy_access_from_string(access_str);
1844 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1845 access >= _BUS_POLICY_ACCESS_MAX) {
1846 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1847 "Invalid endpoint policy access type '%s'", access_str);
1851 if (!c->bus_endpoint) {
1852 r = bus_endpoint_new(&c->bus_endpoint);
1858 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1861 int config_parse_unit_env_file(const char *unit,
1862 const char *filename,
1864 const char *section,
1865 unsigned section_line,
1874 _cleanup_free_ char *n = NULL;
1883 if (isempty(rvalue)) {
1884 /* Empty assignment frees the list */
1890 r = unit_full_printf(u, rvalue, &n);
1892 log_syntax(unit, LOG_ERR, filename, line, -r,
1893 "Failed to resolve specifiers, ignoring: %s", rvalue);
1896 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1897 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1898 "Path '%s' is not absolute, ignoring.", s);
1902 r = strv_extend(env, s);
1909 int config_parse_environ(const char *unit,
1910 const char *filename,
1912 const char *section,
1913 unsigned section_line,
1922 const char *word, *state;
1924 _cleanup_free_ char *k = NULL;
1932 if (isempty(rvalue)) {
1933 /* Empty assignment resets the list */
1940 r = unit_full_printf(u, rvalue, &k);
1942 log_syntax(unit, LOG_ERR, filename, line, -r,
1943 "Failed to resolve specifiers, ignoring: %s", rvalue);
1951 FOREACH_WORD_QUOTED(word, l, k, state) {
1952 _cleanup_free_ char *n;
1955 n = cunescape_length(word, l);
1959 if (!env_assignment_is_valid(n)) {
1960 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1961 "Invalid environment assignment, ignoring: %s", rvalue);
1965 x = strv_env_set(*env, n);
1972 if (!isempty(state))
1973 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1974 "Trailing garbage, ignoring.");
1979 int config_parse_ip_tos(const char *unit,
1980 const char *filename,
1982 const char *section,
1983 unsigned section_line,
1990 int *ip_tos = data, x;
1997 x = ip_tos_from_string(rvalue);
1999 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2000 "Failed to parse IP TOS value, ignoring: %s", rvalue);
2008 int config_parse_unit_condition_path(
2010 const char *filename,
2012 const char *section,
2013 unsigned section_line,
2020 _cleanup_free_ char *p = NULL;
2021 Condition **list = data, *c;
2022 ConditionType t = ltype;
2023 bool trigger, negate;
2032 if (isempty(rvalue)) {
2033 /* Empty assignment resets the list */
2034 condition_free_list(*list);
2039 trigger = rvalue[0] == '|';
2043 negate = rvalue[0] == '!';
2047 r = unit_full_printf(u, rvalue, &p);
2049 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2053 if (!path_is_absolute(p)) {
2054 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2058 c = condition_new(t, p, trigger, negate);
2062 LIST_PREPEND(conditions, *list, c);
2066 int config_parse_unit_condition_string(
2068 const char *filename,
2070 const char *section,
2071 unsigned section_line,
2078 _cleanup_free_ char *s = NULL;
2079 Condition **list = data, *c;
2080 ConditionType t = ltype;
2081 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 r = unit_full_printf(u, rvalue, &s);
2107 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2111 c = condition_new(t, s, trigger, negate);
2115 LIST_PREPEND(conditions, *list, c);
2119 int config_parse_unit_condition_null(
2121 const char *filename,
2123 const char *section,
2124 unsigned section_line,
2131 Condition **list = data, *c;
2132 bool trigger, negate;
2140 if (isempty(rvalue)) {
2141 /* Empty assignment resets the list */
2142 condition_free_list(*list);
2147 trigger = rvalue[0] == '|';
2151 negate = rvalue[0] == '!';
2155 b = parse_boolean(rvalue);
2157 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2164 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2168 LIST_PREPEND(conditions, *list, c);
2172 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2173 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2175 int config_parse_unit_requires_mounts_for(
2177 const char *filename,
2179 const char *section,
2180 unsigned section_line,
2188 const char *word, *state;
2196 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2198 _cleanup_free_ char *n;
2200 n = strndup(word, l);
2204 if (!utf8_is_valid(n)) {
2205 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2209 r = unit_require_mounts_for(u, n);
2211 log_syntax(unit, LOG_ERR, filename, line, -r,
2212 "Failed to add required mount for, ignoring: %s", rvalue);
2216 if (!isempty(state))
2217 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2218 "Trailing garbage, ignoring.");
2223 int config_parse_documentation(const char *unit,
2224 const char *filename,
2226 const char *section,
2227 unsigned section_line,
2243 if (isempty(rvalue)) {
2244 /* Empty assignment resets the list */
2245 strv_free(u->documentation);
2246 u->documentation = NULL;
2250 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2251 rvalue, data, userdata);
2255 for (a = b = u->documentation; a && *a; a++) {
2257 if (is_valid_documentation_url(*a))
2260 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2261 "Invalid URL, ignoring: %s", *a);
2272 int config_parse_syscall_filter(
2274 const char *filename,
2276 const char *section,
2277 unsigned section_line,
2284 static const char default_syscalls[] =
2291 ExecContext *c = data;
2293 bool invert = false;
2294 const char *word, *state;
2303 if (isempty(rvalue)) {
2304 /* Empty assignment resets the list */
2305 set_free(c->syscall_filter);
2306 c->syscall_filter = NULL;
2307 c->syscall_whitelist = false;
2311 if (rvalue[0] == '~') {
2316 if (!c->syscall_filter) {
2317 c->syscall_filter = set_new(NULL);
2318 if (!c->syscall_filter)
2322 /* Allow everything but the ones listed */
2323 c->syscall_whitelist = false;
2327 /* Allow nothing but the ones listed */
2328 c->syscall_whitelist = true;
2330 /* Accept default syscalls if we are on a whitelist */
2331 NULSTR_FOREACH(i, default_syscalls) {
2334 id = seccomp_syscall_resolve_name(i);
2338 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2347 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2348 _cleanup_free_ char *t = NULL;
2351 t = strndup(word, l);
2355 id = seccomp_syscall_resolve_name(t);
2357 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2358 "Failed to parse system call, ignoring: %s", t);
2362 /* If we previously wanted to forbid a syscall and now
2363 * we want to allow it, then remove it from the list
2365 if (!invert == c->syscall_whitelist) {
2366 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2372 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2374 if (!isempty(state))
2375 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2376 "Trailing garbage, ignoring.");
2378 /* Turn on NNP, but only if it wasn't configured explicitly
2379 * before, and only if we are in user mode. */
2380 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2381 c->no_new_privileges = true;
2386 int config_parse_syscall_archs(
2388 const char *filename,
2390 const char *section,
2391 unsigned section_line,
2399 const char *word, *state;
2403 if (isempty(rvalue)) {
2409 r = set_ensure_allocated(archs, NULL);
2413 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2414 _cleanup_free_ char *t = NULL;
2417 t = strndup(word, l);
2421 r = seccomp_arch_from_string(t, &a);
2423 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2424 "Failed to parse system call architecture, ignoring: %s", t);
2428 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2434 if (!isempty(state))
2435 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2436 "Trailing garbage, ignoring.");
2441 int config_parse_syscall_errno(
2443 const char *filename,
2445 const char *section,
2446 unsigned section_line,
2453 ExecContext *c = data;
2460 if (isempty(rvalue)) {
2461 /* Empty assignment resets to KILL */
2462 c->syscall_errno = 0;
2466 e = errno_from_name(rvalue);
2468 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2469 "Failed to parse error number, ignoring: %s", rvalue);
2473 c->syscall_errno = e;
2477 int config_parse_address_families(
2479 const char *filename,
2481 const char *section,
2482 unsigned section_line,
2489 ExecContext *c = data;
2490 bool invert = false;
2491 const char *word, *state;
2499 if (isempty(rvalue)) {
2500 /* Empty assignment resets the list */
2501 set_free(c->address_families);
2502 c->address_families = NULL;
2503 c->address_families_whitelist = false;
2507 if (rvalue[0] == '~') {
2512 if (!c->address_families) {
2513 c->address_families = set_new(NULL);
2514 if (!c->address_families)
2517 c->address_families_whitelist = !invert;
2520 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2521 _cleanup_free_ char *t = NULL;
2524 t = strndup(word, l);
2528 af = af_from_name(t);
2530 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2531 "Failed to parse address family, ignoring: %s", t);
2535 /* If we previously wanted to forbid an address family and now
2536 * we want to allow it, then remove it from the list
2538 if (!invert == c->address_families_whitelist) {
2539 r = set_put(c->address_families, INT_TO_PTR(af));
2545 set_remove(c->address_families, INT_TO_PTR(af));
2547 if (!isempty(state))
2548 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2549 "Trailing garbage, ignoring.");
2555 int config_parse_unit_slice(
2557 const char *filename,
2559 const char *section,
2560 unsigned section_line,
2567 _cleanup_free_ char *k = NULL;
2568 Unit *u = userdata, *slice;
2576 r = unit_name_printf(u, rvalue, &k);
2578 log_syntax(unit, LOG_ERR, filename, line, -r,
2579 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2586 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2588 log_syntax(unit, LOG_ERR, filename, line, -r,
2589 "Failed to load slice unit %s. Ignoring.", k);
2593 if (slice->type != UNIT_SLICE) {
2594 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2595 "Slice unit %s is not a slice. Ignoring.", k);
2599 unit_ref_set(&u->slice, slice);
2603 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2605 int config_parse_cpu_shares(
2607 const char *filename,
2609 const char *section,
2610 unsigned section_line,
2617 unsigned long *shares = data, lu;
2624 if (isempty(rvalue)) {
2625 *shares = (unsigned long) -1;
2629 r = safe_atolu(rvalue, &lu);
2630 if (r < 0 || lu <= 0) {
2631 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2632 "CPU shares '%s' invalid. Ignoring.", rvalue);
2640 int config_parse_cpu_quota(
2642 const char *filename,
2644 const char *section,
2645 unsigned section_line,
2652 CGroupContext *c = data;
2659 if (isempty(rvalue)) {
2660 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2664 if (!endswith(rvalue, "%")) {
2666 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2667 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2671 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2672 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2673 "CPU quota '%s' invalid. Ignoring.", rvalue);
2677 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2682 int config_parse_memory_limit(
2684 const char *filename,
2686 const char *section,
2687 unsigned section_line,
2694 CGroupContext *c = data;
2698 if (isempty(rvalue)) {
2699 c->memory_limit = (uint64_t) -1;
2703 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2705 r = parse_size(rvalue, 1024, &bytes);
2707 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2708 "Memory limit '%s' invalid. Ignoring.", rvalue);
2712 c->memory_limit = (uint64_t) bytes;
2716 int config_parse_device_allow(
2718 const char *filename,
2720 const char *section,
2721 unsigned section_line,
2728 _cleanup_free_ char *path = NULL;
2729 CGroupContext *c = data;
2730 CGroupDeviceAllow *a;
2734 if (isempty(rvalue)) {
2735 while (c->device_allow)
2736 cgroup_context_free_device_allow(c, c->device_allow);
2741 n = strcspn(rvalue, WHITESPACE);
2742 path = strndup(rvalue, n);
2746 if (!startswith(path, "/dev/") &&
2747 !startswith(path, "block-") &&
2748 !startswith(path, "char-")) {
2749 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2750 "Invalid device node path '%s'. Ignoring.", path);
2754 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2758 if (!in_charset(m, "rwm")) {
2759 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2760 "Invalid device rights '%s'. Ignoring.", m);
2764 a = new0(CGroupDeviceAllow, 1);
2770 a->r = !!strchr(m, 'r');
2771 a->w = !!strchr(m, 'w');
2772 a->m = !!strchr(m, 'm');
2774 LIST_PREPEND(device_allow, c->device_allow, a);
2778 int config_parse_blockio_weight(
2780 const char *filename,
2782 const char *section,
2783 unsigned section_line,
2790 unsigned long *weight = data, lu;
2797 if (isempty(rvalue)) {
2798 *weight = (unsigned long) -1;
2802 r = safe_atolu(rvalue, &lu);
2803 if (r < 0 || lu < 10 || lu > 1000) {
2804 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2805 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2813 int config_parse_blockio_device_weight(
2815 const char *filename,
2817 const char *section,
2818 unsigned section_line,
2825 _cleanup_free_ char *path = NULL;
2826 CGroupBlockIODeviceWeight *w;
2827 CGroupContext *c = data;
2837 if (isempty(rvalue)) {
2838 while (c->blockio_device_weights)
2839 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2844 n = strcspn(rvalue, WHITESPACE);
2845 weight = rvalue + n;
2847 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2848 "Expected block device and device weight. Ignoring.");
2852 path = strndup(rvalue, n);
2856 if (!path_startswith(path, "/dev")) {
2857 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2858 "Invalid device node path '%s'. Ignoring.", path);
2862 weight += strspn(weight, WHITESPACE);
2863 r = safe_atolu(weight, &lu);
2864 if (r < 0 || lu < 10 || lu > 1000) {
2865 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2866 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2870 w = new0(CGroupBlockIODeviceWeight, 1);
2879 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2883 int config_parse_blockio_bandwidth(
2885 const char *filename,
2887 const char *section,
2888 unsigned section_line,
2895 _cleanup_free_ char *path = NULL;
2896 CGroupBlockIODeviceBandwidth *b;
2897 CGroupContext *c = data;
2898 const char *bandwidth;
2908 read = streq("BlockIOReadBandwidth", lvalue);
2910 if (isempty(rvalue)) {
2911 CGroupBlockIODeviceBandwidth *next;
2913 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2914 if (b->read == read)
2915 cgroup_context_free_blockio_device_bandwidth(c, b);
2920 n = strcspn(rvalue, WHITESPACE);
2921 bandwidth = rvalue + n;
2922 bandwidth += strspn(bandwidth, WHITESPACE);
2925 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2926 "Expected space separated pair of device node and bandwidth. Ignoring.");
2930 path = strndup(rvalue, n);
2934 if (!path_startswith(path, "/dev")) {
2935 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2936 "Invalid device node path '%s'. Ignoring.", path);
2940 r = parse_size(bandwidth, 1000, &bytes);
2941 if (r < 0 || bytes <= 0) {
2942 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2943 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2947 b = new0(CGroupBlockIODeviceBandwidth, 1);
2953 b->bandwidth = (uint64_t) bytes;
2956 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2961 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2963 int config_parse_job_mode_isolate(
2965 const char *filename,
2967 const char *section,
2968 unsigned section_line,
2982 r = parse_boolean(rvalue);
2984 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2985 "Failed to parse boolean, ignoring: %s", rvalue);
2989 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2993 int config_parse_personality(
2995 const char *filename,
2997 const char *section,
2998 unsigned section_line,
3005 unsigned long *personality = data, p;
3010 assert(personality);
3012 p = personality_from_string(rvalue);
3013 if (p == 0xffffffffUL) {
3014 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3015 "Failed to parse personality, ignoring: %s", rvalue);
3023 int config_parse_runtime_directory(
3025 const char *filename,
3027 const char *section,
3028 unsigned section_line,
3036 const char *word, *state;
3045 if (isempty(rvalue)) {
3046 /* Empty assignment resets the list */
3052 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3053 _cleanup_free_ char *n;
3055 n = strndup(word, l);
3059 if (!filename_is_safe(n)) {
3060 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3061 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3065 r = strv_push(rt, n);
3071 if (!isempty(state))
3072 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3073 "Trailing garbage, ignoring.");
3078 int config_parse_set_status(
3080 const char *filename,
3082 const char *section,
3083 unsigned section_line,
3091 const char *word, *state;
3093 ExitStatusSet *status_set = data;
3100 /* Empty assignment resets the list */
3101 if (isempty(rvalue)) {
3102 exit_status_set_free(status_set);
3106 FOREACH_WORD(word, l, rvalue, state) {
3107 _cleanup_free_ char *temp;
3110 temp = strndup(word, l);
3114 r = safe_atoi(temp, &val);
3116 val = signal_from_string_try_harder(temp);
3119 log_syntax(unit, LOG_ERR, filename, line, -val,
3120 "Failed to parse value, ignoring: %s", word);
3124 if (val < 0 || val > 255) {
3125 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3126 "Value %d is outside range 0-255, ignoring", val);
3131 r = set_ensure_allocated(&status_set->status, NULL);
3135 r = set_put(status_set->status, INT_TO_PTR(val));
3137 log_syntax(unit, LOG_ERR, filename, line, -r,
3138 "Unable to store: %s", word);
3142 if (!isempty(state))
3143 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3144 "Trailing garbage, ignoring.");
3149 int config_parse_namespace_path_strv(
3151 const char *filename,
3153 const char *section,
3154 unsigned section_line,
3162 const char *word, *state;
3171 if (isempty(rvalue)) {
3172 /* Empty assignment resets the list */
3178 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3179 _cleanup_free_ char *n;
3182 n = strndup(word, l);
3186 if (!utf8_is_valid(n)) {
3187 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3191 offset = n[0] == '-';
3192 if (!path_is_absolute(n + offset)) {
3193 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3194 "Not an absolute path, ignoring: %s", rvalue);
3198 path_kill_slashes(n);
3200 r = strv_push(sv, n);
3206 if (!isempty(state))
3207 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3208 "Trailing garbage, ignoring.");
3213 int config_parse_no_new_privileges(
3215 const char *filename,
3217 const char *section,
3218 unsigned section_line,
3225 ExecContext *c = data;
3233 k = parse_boolean(rvalue);
3235 log_syntax(unit, LOG_ERR, filename, line, -k,
3236 "Failed to parse boolean value, ignoring: %s", rvalue);
3240 c->no_new_privileges = !!k;
3241 c->no_new_privileges_set = true;
3246 int config_parse_protect_home(
3248 const char *filename,
3250 const char *section,
3251 unsigned section_line,
3258 ExecContext *c = data;
3266 /* Our enum shall be a superset of booleans, hence first try
3267 * to parse as as boolean, and then as enum */
3269 k = parse_boolean(rvalue);
3271 c->protect_home = PROTECT_HOME_YES;
3273 c->protect_home = PROTECT_HOME_NO;
3277 h = protect_home_from_string(rvalue);
3279 log_syntax(unit, LOG_ERR, filename, line, -h,
3280 "Failed to parse protect home value, ignoring: %s", rvalue);
3284 c->protect_home = h;
3290 int config_parse_protect_system(
3292 const char *filename,
3294 const char *section,
3295 unsigned section_line,
3302 ExecContext *c = data;
3310 /* Our enum shall be a superset of booleans, hence first try
3311 * to parse as as boolean, and then as enum */
3313 k = parse_boolean(rvalue);
3315 c->protect_system = PROTECT_SYSTEM_YES;
3317 c->protect_system = PROTECT_SYSTEM_NO;
3321 s = protect_system_from_string(rvalue);
3323 log_syntax(unit, LOG_ERR, filename, line, -s,
3324 "Failed to parse protect system value, ignoring: %s", rvalue);
3328 c->protect_system = s;
3334 #define FOLLOW_MAX 8
3336 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3347 /* This will update the filename pointer if the loaded file is
3348 * reached by a symlink. The old string will be freed. */
3351 char *target, *name;
3353 if (c++ >= FOLLOW_MAX)
3356 path_kill_slashes(*filename);
3358 /* Add the file name we are currently looking at to
3359 * the names of this unit, but only if it is a valid
3361 name = basename(*filename);
3363 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3365 id = set_get(names, name);
3371 r = set_consume(names, id);
3377 /* Try to open the file name, but don't if its a symlink */
3378 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3385 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3386 r = readlink_and_make_absolute(*filename, &target);
3394 f = fdopen(fd, "re");
3406 static int merge_by_names(Unit **u, Set *names, const char *id) {
3414 /* Let's try to add in all symlink names we found */
3415 while ((k = set_steal_first(names))) {
3417 /* First try to merge in the other name into our
3419 r = unit_merge_by_name(*u, k);
3423 /* Hmm, we couldn't merge the other unit into
3424 * ours? Then let's try it the other way
3427 other = manager_get_unit((*u)->manager, k);
3431 r = unit_merge(other, *u);
3434 return merge_by_names(u, names, NULL);
3442 unit_choose_id(*u, id);
3450 static int load_from_path(Unit *u, const char *path) {
3452 _cleanup_set_free_free_ Set *symlink_names = NULL;
3453 _cleanup_fclose_ FILE *f = NULL;
3454 _cleanup_free_ char *filename = NULL;
3462 symlink_names = set_new(&string_hash_ops);
3466 if (path_is_absolute(path)) {
3468 filename = strdup(path);
3472 r = open_follow(&filename, &f, symlink_names, &id);
3484 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3486 /* Instead of opening the path right away, we manually
3487 * follow all symlinks and add their name to our unit
3488 * name set while doing so */
3489 filename = path_make_absolute(path, *p);
3493 if (u->manager->unit_path_cache &&
3494 !set_get(u->manager->unit_path_cache, filename))
3497 r = open_follow(&filename, &f, symlink_names, &id);
3506 /* Empty the symlink names for the next run */
3507 set_clear_free(symlink_names);
3516 /* Hmm, no suitable file found? */
3520 r = merge_by_names(&merged, symlink_names, id);
3525 u->load_state = UNIT_MERGED;
3529 if (fstat(fileno(f), &st) < 0)
3532 if (null_or_empty(&st))
3533 u->load_state = UNIT_MASKED;
3535 u->load_state = UNIT_LOADED;
3537 /* Now, parse the file contents */
3538 r = config_parse(u->id, filename, f,
3539 UNIT_VTABLE(u)->sections,
3540 config_item_perf_lookup, load_fragment_gperf_lookup,
3541 false, true, false, u);
3546 free(u->fragment_path);
3547 u->fragment_path = filename;
3550 u->fragment_mtime = timespec_load(&st.st_mtim);
3552 if (u->source_path) {
3553 if (stat(u->source_path, &st) >= 0)
3554 u->source_mtime = timespec_load(&st.st_mtim);
3556 u->source_mtime = 0;
3562 int unit_load_fragment(Unit *u) {
3568 assert(u->load_state == UNIT_STUB);
3571 /* First, try to find the unit under its id. We always look
3572 * for unit files in the default directories, to make it easy
3573 * to override things by placing things in /etc/systemd/system */
3574 r = load_from_path(u, u->id);
3578 /* Try to find an alias we can load this with */
3579 if (u->load_state == UNIT_STUB)
3580 SET_FOREACH(t, u->names, i) {
3585 r = load_from_path(u, t);
3589 if (u->load_state != UNIT_STUB)
3593 /* And now, try looking for it under the suggested (originally linked) path */
3594 if (u->load_state == UNIT_STUB && u->fragment_path) {
3596 r = load_from_path(u, u->fragment_path);
3600 if (u->load_state == UNIT_STUB) {
3601 /* Hmm, this didn't work? Then let's get rid
3602 * of the fragment path stored for us, so that
3603 * we don't point to an invalid location. */
3604 free(u->fragment_path);
3605 u->fragment_path = NULL;
3609 /* Look for a template */
3610 if (u->load_state == UNIT_STUB && u->instance) {
3611 _cleanup_free_ char *k;
3613 k = unit_name_template(u->id);
3617 r = load_from_path(u, k);
3621 if (u->load_state == UNIT_STUB)
3622 SET_FOREACH(t, u->names, i) {
3623 _cleanup_free_ char *z = NULL;
3628 z = unit_name_template(t);
3632 r = load_from_path(u, z);
3636 if (u->load_state != UNIT_STUB)
3644 void unit_dump_config_items(FILE *f) {
3645 static const struct {
3646 const ConfigParserCallback callback;
3649 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3650 { config_parse_warn_compat, "NOTSUPPORTED" },
3652 { config_parse_int, "INTEGER" },
3653 { config_parse_unsigned, "UNSIGNED" },
3654 { config_parse_iec_size, "SIZE" },
3655 { config_parse_iec_off, "SIZE" },
3656 { config_parse_si_size, "SIZE" },
3657 { config_parse_bool, "BOOLEAN" },
3658 { config_parse_string, "STRING" },
3659 { config_parse_path, "PATH" },
3660 { config_parse_unit_path_printf, "PATH" },
3661 { config_parse_strv, "STRING [...]" },
3662 { config_parse_exec_nice, "NICE" },
3663 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3664 { config_parse_exec_io_class, "IOCLASS" },
3665 { config_parse_exec_io_priority, "IOPRIORITY" },
3666 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3667 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3668 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3669 { config_parse_mode, "MODE" },
3670 { config_parse_unit_env_file, "FILE" },
3671 { config_parse_output, "OUTPUT" },
3672 { config_parse_input, "INPUT" },
3673 { config_parse_log_facility, "FACILITY" },
3674 { config_parse_log_level, "LEVEL" },
3675 { config_parse_exec_capabilities, "CAPABILITIES" },
3676 { config_parse_exec_secure_bits, "SECUREBITS" },
3677 { config_parse_bounding_set, "BOUNDINGSET" },
3678 { config_parse_limit, "LIMIT" },
3679 { config_parse_unit_deps, "UNIT [...]" },
3680 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3681 { config_parse_service_type, "SERVICETYPE" },
3682 { config_parse_service_restart, "SERVICERESTART" },
3683 #ifdef HAVE_SYSV_COMPAT
3684 { config_parse_sysv_priority, "SYSVPRIORITY" },
3686 { config_parse_kill_mode, "KILLMODE" },
3687 { config_parse_kill_signal, "SIGNAL" },
3688 { config_parse_socket_listen, "SOCKET [...]" },
3689 { config_parse_socket_bind, "SOCKETBIND" },
3690 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3691 { config_parse_sec, "SECONDS" },
3692 { config_parse_nsec, "NANOSECONDS" },
3693 { config_parse_namespace_path_strv, "PATH [...]" },
3694 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3695 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3696 { config_parse_unit_string_printf, "STRING" },
3697 { config_parse_trigger_unit, "UNIT" },
3698 { config_parse_timer, "TIMER" },
3699 { config_parse_path_spec, "PATH" },
3700 { config_parse_notify_access, "ACCESS" },
3701 { config_parse_ip_tos, "TOS" },
3702 { config_parse_unit_condition_path, "CONDITION" },
3703 { config_parse_unit_condition_string, "CONDITION" },
3704 { config_parse_unit_condition_null, "CONDITION" },
3705 { config_parse_unit_slice, "SLICE" },
3706 { config_parse_documentation, "URL" },
3707 { config_parse_service_timeout, "SECONDS" },
3708 { config_parse_failure_action, "ACTION" },
3709 { config_parse_set_status, "STATUS" },
3710 { config_parse_service_sockets, "SOCKETS" },
3711 { config_parse_environ, "ENVIRON" },
3713 { config_parse_syscall_filter, "SYSCALLS" },
3714 { config_parse_syscall_archs, "ARCHS" },
3715 { config_parse_syscall_errno, "ERRNO" },
3716 { config_parse_address_families, "FAMILIES" },
3718 { config_parse_cpu_shares, "SHARES" },
3719 { config_parse_memory_limit, "LIMIT" },
3720 { config_parse_device_allow, "DEVICE" },
3721 { config_parse_device_policy, "POLICY" },
3722 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3723 { config_parse_blockio_weight, "WEIGHT" },
3724 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3725 { config_parse_long, "LONG" },
3726 { config_parse_socket_service, "SERVICE" },
3728 { config_parse_exec_selinux_context, "LABEL" },
3730 { config_parse_job_mode, "MODE" },
3731 { config_parse_job_mode_isolate, "BOOLEAN" },
3732 { config_parse_personality, "PERSONALITY" },
3735 const char *prev = NULL;
3740 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3741 const char *rvalue = "OTHER", *lvalue;
3745 const ConfigPerfItem *p;
3747 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3749 dot = strchr(i, '.');
3750 lvalue = dot ? dot + 1 : i;
3754 if (!prev || !strneq(prev, i, prefix_len+1)) {
3758 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3761 for (j = 0; j < ELEMENTSOF(table); j++)
3762 if (p->parse == table[j].callback) {
3763 rvalue = table[j].rvalue;
3767 fprintf(f, "%s=%s\n", lvalue, rvalue);