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;
2491 bool invert = false;
2492 const char *word, *state;
2501 if (isempty(rvalue)) {
2502 /* Empty assignment resets the list */
2503 set_free(c->address_families);
2504 c->address_families = NULL;
2505 c->address_families_whitelist = false;
2509 if (rvalue[0] == '~') {
2514 if (!c->address_families) {
2515 c->address_families = set_new(NULL);
2516 if (!c->address_families)
2519 c->address_families_whitelist = !invert;
2522 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2523 _cleanup_free_ char *t = NULL;
2526 t = strndup(word, l);
2530 af = af_from_name(t);
2532 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2533 "Failed to parse address family, ignoring: %s", t);
2537 /* If we previously wanted to forbid an address family and now
2538 * we want to allow it, then remove it from the list
2540 if (!invert == c->address_families_whitelist) {
2541 r = set_put(c->address_families, INT_TO_PTR(af));
2547 set_remove(c->address_families, INT_TO_PTR(af));
2549 if (!isempty(state))
2550 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2551 "Trailing garbage, ignoring.");
2557 int config_parse_unit_slice(
2559 const char *filename,
2561 const char *section,
2562 unsigned section_line,
2569 _cleanup_free_ char *k = NULL;
2570 Unit *u = userdata, *slice;
2578 r = unit_name_printf(u, rvalue, &k);
2580 log_syntax(unit, LOG_ERR, filename, line, -r,
2581 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2588 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2590 log_syntax(unit, LOG_ERR, filename, line, -r,
2591 "Failed to load slice unit %s. Ignoring.", k);
2595 if (slice->type != UNIT_SLICE) {
2596 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2597 "Slice unit %s is not a slice. Ignoring.", k);
2601 unit_ref_set(&u->slice, slice);
2605 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2607 int config_parse_cpu_shares(
2609 const char *filename,
2611 const char *section,
2612 unsigned section_line,
2619 unsigned long *shares = data, lu;
2626 if (isempty(rvalue)) {
2627 *shares = (unsigned long) -1;
2631 r = safe_atolu(rvalue, &lu);
2632 if (r < 0 || lu <= 0) {
2633 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2634 "CPU shares '%s' invalid. Ignoring.", rvalue);
2642 int config_parse_cpu_quota(
2644 const char *filename,
2646 const char *section,
2647 unsigned section_line,
2654 CGroupContext *c = data;
2661 if (isempty(rvalue)) {
2662 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2666 if (!endswith(rvalue, "%")) {
2668 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2669 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2673 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2674 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2675 "CPU quota '%s' invalid. Ignoring.", rvalue);
2679 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2684 int config_parse_memory_limit(
2686 const char *filename,
2688 const char *section,
2689 unsigned section_line,
2696 CGroupContext *c = data;
2700 if (isempty(rvalue)) {
2701 c->memory_limit = (uint64_t) -1;
2705 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2707 r = parse_size(rvalue, 1024, &bytes);
2709 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2710 "Memory limit '%s' invalid. Ignoring.", rvalue);
2714 c->memory_limit = (uint64_t) bytes;
2718 int config_parse_device_allow(
2720 const char *filename,
2722 const char *section,
2723 unsigned section_line,
2730 _cleanup_free_ char *path = NULL;
2731 CGroupContext *c = data;
2732 CGroupDeviceAllow *a;
2736 if (isempty(rvalue)) {
2737 while (c->device_allow)
2738 cgroup_context_free_device_allow(c, c->device_allow);
2743 n = strcspn(rvalue, WHITESPACE);
2744 path = strndup(rvalue, n);
2748 if (!startswith(path, "/dev/") &&
2749 !startswith(path, "block-") &&
2750 !startswith(path, "char-")) {
2751 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2752 "Invalid device node path '%s'. Ignoring.", path);
2756 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2760 if (!in_charset(m, "rwm")) {
2761 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2762 "Invalid device rights '%s'. Ignoring.", m);
2766 a = new0(CGroupDeviceAllow, 1);
2772 a->r = !!strchr(m, 'r');
2773 a->w = !!strchr(m, 'w');
2774 a->m = !!strchr(m, 'm');
2776 LIST_PREPEND(device_allow, c->device_allow, a);
2780 int config_parse_blockio_weight(
2782 const char *filename,
2784 const char *section,
2785 unsigned section_line,
2792 unsigned long *weight = data, lu;
2799 if (isempty(rvalue)) {
2800 *weight = (unsigned long) -1;
2804 r = safe_atolu(rvalue, &lu);
2805 if (r < 0 || lu < 10 || lu > 1000) {
2806 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2807 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2815 int config_parse_blockio_device_weight(
2817 const char *filename,
2819 const char *section,
2820 unsigned section_line,
2827 _cleanup_free_ char *path = NULL;
2828 CGroupBlockIODeviceWeight *w;
2829 CGroupContext *c = data;
2839 if (isempty(rvalue)) {
2840 while (c->blockio_device_weights)
2841 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2846 n = strcspn(rvalue, WHITESPACE);
2847 weight = rvalue + n;
2849 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2850 "Expected block device and device weight. Ignoring.");
2854 path = strndup(rvalue, n);
2858 if (!path_startswith(path, "/dev")) {
2859 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2860 "Invalid device node path '%s'. Ignoring.", path);
2864 weight += strspn(weight, WHITESPACE);
2865 r = safe_atolu(weight, &lu);
2866 if (r < 0 || lu < 10 || lu > 1000) {
2867 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2868 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2872 w = new0(CGroupBlockIODeviceWeight, 1);
2881 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2885 int config_parse_blockio_bandwidth(
2887 const char *filename,
2889 const char *section,
2890 unsigned section_line,
2897 _cleanup_free_ char *path = NULL;
2898 CGroupBlockIODeviceBandwidth *b;
2899 CGroupContext *c = data;
2900 const char *bandwidth;
2910 read = streq("BlockIOReadBandwidth", lvalue);
2912 if (isempty(rvalue)) {
2913 CGroupBlockIODeviceBandwidth *next;
2915 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2916 if (b->read == read)
2917 cgroup_context_free_blockio_device_bandwidth(c, b);
2922 n = strcspn(rvalue, WHITESPACE);
2923 bandwidth = rvalue + n;
2924 bandwidth += strspn(bandwidth, WHITESPACE);
2927 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2928 "Expected space separated pair of device node and bandwidth. Ignoring.");
2932 path = strndup(rvalue, n);
2936 if (!path_startswith(path, "/dev")) {
2937 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2938 "Invalid device node path '%s'. Ignoring.", path);
2942 r = parse_size(bandwidth, 1000, &bytes);
2943 if (r < 0 || bytes <= 0) {
2944 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2945 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2949 b = new0(CGroupBlockIODeviceBandwidth, 1);
2955 b->bandwidth = (uint64_t) bytes;
2958 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2963 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2965 int config_parse_job_mode_isolate(
2967 const char *filename,
2969 const char *section,
2970 unsigned section_line,
2984 r = parse_boolean(rvalue);
2986 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2987 "Failed to parse boolean, ignoring: %s", rvalue);
2991 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2995 int config_parse_personality(
2997 const char *filename,
2999 const char *section,
3000 unsigned section_line,
3007 unsigned long *personality = data, p;
3012 assert(personality);
3014 p = personality_from_string(rvalue);
3015 if (p == 0xffffffffUL) {
3016 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3017 "Failed to parse personality, ignoring: %s", rvalue);
3025 int config_parse_runtime_directory(
3027 const char *filename,
3029 const char *section,
3030 unsigned section_line,
3038 const char *word, *state;
3047 if (isempty(rvalue)) {
3048 /* Empty assignment resets the list */
3054 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3055 _cleanup_free_ char *n;
3057 n = strndup(word, l);
3061 if (!filename_is_safe(n)) {
3062 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3063 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3067 r = strv_push(rt, n);
3073 if (!isempty(state))
3074 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3075 "Trailing garbage, ignoring.");
3080 int config_parse_set_status(
3082 const char *filename,
3084 const char *section,
3085 unsigned section_line,
3093 const char *word, *state;
3095 ExitStatusSet *status_set = data;
3102 /* Empty assignment resets the list */
3103 if (isempty(rvalue)) {
3104 exit_status_set_free(status_set);
3108 FOREACH_WORD(word, l, rvalue, state) {
3109 _cleanup_free_ char *temp;
3112 temp = strndup(word, l);
3116 r = safe_atoi(temp, &val);
3118 val = signal_from_string_try_harder(temp);
3121 log_syntax(unit, LOG_ERR, filename, line, -val,
3122 "Failed to parse value, ignoring: %s", word);
3126 if (val < 0 || val > 255) {
3127 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3128 "Value %d is outside range 0-255, ignoring", val);
3133 r = set_ensure_allocated(&status_set->status, NULL);
3137 r = set_put(status_set->status, INT_TO_PTR(val));
3139 log_syntax(unit, LOG_ERR, filename, line, -r,
3140 "Unable to store: %s", word);
3144 if (!isempty(state))
3145 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3146 "Trailing garbage, ignoring.");
3151 int config_parse_namespace_path_strv(
3153 const char *filename,
3155 const char *section,
3156 unsigned section_line,
3164 const char *word, *state;
3173 if (isempty(rvalue)) {
3174 /* Empty assignment resets the list */
3180 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3181 _cleanup_free_ char *n;
3184 n = strndup(word, l);
3188 if (!utf8_is_valid(n)) {
3189 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3193 offset = n[0] == '-';
3194 if (!path_is_absolute(n + offset)) {
3195 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3196 "Not an absolute path, ignoring: %s", rvalue);
3200 path_kill_slashes(n);
3202 r = strv_push(sv, n);
3208 if (!isempty(state))
3209 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3210 "Trailing garbage, ignoring.");
3215 int config_parse_no_new_privileges(
3217 const char *filename,
3219 const char *section,
3220 unsigned section_line,
3227 ExecContext *c = data;
3235 k = parse_boolean(rvalue);
3237 log_syntax(unit, LOG_ERR, filename, line, -k,
3238 "Failed to parse boolean value, ignoring: %s", rvalue);
3242 c->no_new_privileges = !!k;
3243 c->no_new_privileges_set = true;
3248 int config_parse_protect_home(
3250 const char *filename,
3252 const char *section,
3253 unsigned section_line,
3260 ExecContext *c = data;
3268 /* Our enum shall be a superset of booleans, hence first try
3269 * to parse as as boolean, and then as enum */
3271 k = parse_boolean(rvalue);
3273 c->protect_home = PROTECT_HOME_YES;
3275 c->protect_home = PROTECT_HOME_NO;
3279 h = protect_home_from_string(rvalue);
3281 log_syntax(unit, LOG_ERR, filename, line, -h,
3282 "Failed to parse protect home value, ignoring: %s", rvalue);
3286 c->protect_home = h;
3292 int config_parse_protect_system(
3294 const char *filename,
3296 const char *section,
3297 unsigned section_line,
3304 ExecContext *c = data;
3312 /* Our enum shall be a superset of booleans, hence first try
3313 * to parse as as boolean, and then as enum */
3315 k = parse_boolean(rvalue);
3317 c->protect_system = PROTECT_SYSTEM_YES;
3319 c->protect_system = PROTECT_SYSTEM_NO;
3323 s = protect_system_from_string(rvalue);
3325 log_syntax(unit, LOG_ERR, filename, line, -s,
3326 "Failed to parse protect system value, ignoring: %s", rvalue);
3330 c->protect_system = s;
3336 #define FOLLOW_MAX 8
3338 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3349 /* This will update the filename pointer if the loaded file is
3350 * reached by a symlink. The old string will be freed. */
3353 char *target, *name;
3355 if (c++ >= FOLLOW_MAX)
3358 path_kill_slashes(*filename);
3360 /* Add the file name we are currently looking at to
3361 * the names of this unit, but only if it is a valid
3363 name = basename(*filename);
3365 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3367 id = set_get(names, name);
3373 r = set_consume(names, id);
3379 /* Try to open the file name, but don't if its a symlink */
3380 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3387 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3388 r = readlink_and_make_absolute(*filename, &target);
3396 f = fdopen(fd, "re");
3408 static int merge_by_names(Unit **u, Set *names, const char *id) {
3416 /* Let's try to add in all symlink names we found */
3417 while ((k = set_steal_first(names))) {
3419 /* First try to merge in the other name into our
3421 r = unit_merge_by_name(*u, k);
3425 /* Hmm, we couldn't merge the other unit into
3426 * ours? Then let's try it the other way
3429 other = manager_get_unit((*u)->manager, k);
3433 r = unit_merge(other, *u);
3436 return merge_by_names(u, names, NULL);
3444 unit_choose_id(*u, id);
3452 static int load_from_path(Unit *u, const char *path) {
3454 _cleanup_set_free_free_ Set *symlink_names = NULL;
3455 _cleanup_fclose_ FILE *f = NULL;
3456 _cleanup_free_ char *filename = NULL;
3464 symlink_names = set_new(&string_hash_ops);
3468 if (path_is_absolute(path)) {
3470 filename = strdup(path);
3474 r = open_follow(&filename, &f, symlink_names, &id);
3486 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3488 /* Instead of opening the path right away, we manually
3489 * follow all symlinks and add their name to our unit
3490 * name set while doing so */
3491 filename = path_make_absolute(path, *p);
3495 if (u->manager->unit_path_cache &&
3496 !set_get(u->manager->unit_path_cache, filename))
3499 r = open_follow(&filename, &f, symlink_names, &id);
3508 /* Empty the symlink names for the next run */
3509 set_clear_free(symlink_names);
3518 /* Hmm, no suitable file found? */
3522 r = merge_by_names(&merged, symlink_names, id);
3527 u->load_state = UNIT_MERGED;
3531 if (fstat(fileno(f), &st) < 0)
3534 if (null_or_empty(&st))
3535 u->load_state = UNIT_MASKED;
3537 u->load_state = UNIT_LOADED;
3539 /* Now, parse the file contents */
3540 r = config_parse(u->id, filename, f,
3541 UNIT_VTABLE(u)->sections,
3542 config_item_perf_lookup, load_fragment_gperf_lookup,
3543 false, true, false, u);
3548 free(u->fragment_path);
3549 u->fragment_path = filename;
3552 u->fragment_mtime = timespec_load(&st.st_mtim);
3554 if (u->source_path) {
3555 if (stat(u->source_path, &st) >= 0)
3556 u->source_mtime = timespec_load(&st.st_mtim);
3558 u->source_mtime = 0;
3564 int unit_load_fragment(Unit *u) {
3570 assert(u->load_state == UNIT_STUB);
3573 /* First, try to find the unit under its id. We always look
3574 * for unit files in the default directories, to make it easy
3575 * to override things by placing things in /etc/systemd/system */
3576 r = load_from_path(u, u->id);
3580 /* Try to find an alias we can load this with */
3581 if (u->load_state == UNIT_STUB)
3582 SET_FOREACH(t, u->names, i) {
3587 r = load_from_path(u, t);
3591 if (u->load_state != UNIT_STUB)
3595 /* And now, try looking for it under the suggested (originally linked) path */
3596 if (u->load_state == UNIT_STUB && u->fragment_path) {
3598 r = load_from_path(u, u->fragment_path);
3602 if (u->load_state == UNIT_STUB) {
3603 /* Hmm, this didn't work? Then let's get rid
3604 * of the fragment path stored for us, so that
3605 * we don't point to an invalid location. */
3606 free(u->fragment_path);
3607 u->fragment_path = NULL;
3611 /* Look for a template */
3612 if (u->load_state == UNIT_STUB && u->instance) {
3613 _cleanup_free_ char *k;
3615 k = unit_name_template(u->id);
3619 r = load_from_path(u, k);
3623 if (u->load_state == UNIT_STUB)
3624 SET_FOREACH(t, u->names, i) {
3625 _cleanup_free_ char *z = NULL;
3630 z = unit_name_template(t);
3634 r = load_from_path(u, z);
3638 if (u->load_state != UNIT_STUB)
3646 void unit_dump_config_items(FILE *f) {
3647 static const struct {
3648 const ConfigParserCallback callback;
3651 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3652 { config_parse_warn_compat, "NOTSUPPORTED" },
3654 { config_parse_int, "INTEGER" },
3655 { config_parse_unsigned, "UNSIGNED" },
3656 { config_parse_iec_size, "SIZE" },
3657 { config_parse_iec_off, "SIZE" },
3658 { config_parse_si_size, "SIZE" },
3659 { config_parse_bool, "BOOLEAN" },
3660 { config_parse_string, "STRING" },
3661 { config_parse_path, "PATH" },
3662 { config_parse_unit_path_printf, "PATH" },
3663 { config_parse_strv, "STRING [...]" },
3664 { config_parse_exec_nice, "NICE" },
3665 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3666 { config_parse_exec_io_class, "IOCLASS" },
3667 { config_parse_exec_io_priority, "IOPRIORITY" },
3668 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3669 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3670 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3671 { config_parse_mode, "MODE" },
3672 { config_parse_unit_env_file, "FILE" },
3673 { config_parse_output, "OUTPUT" },
3674 { config_parse_input, "INPUT" },
3675 { config_parse_log_facility, "FACILITY" },
3676 { config_parse_log_level, "LEVEL" },
3677 { config_parse_exec_capabilities, "CAPABILITIES" },
3678 { config_parse_exec_secure_bits, "SECUREBITS" },
3679 { config_parse_bounding_set, "BOUNDINGSET" },
3680 { config_parse_limit, "LIMIT" },
3681 { config_parse_unit_deps, "UNIT [...]" },
3682 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3683 { config_parse_service_type, "SERVICETYPE" },
3684 { config_parse_service_restart, "SERVICERESTART" },
3685 #ifdef HAVE_SYSV_COMPAT
3686 { config_parse_sysv_priority, "SYSVPRIORITY" },
3688 { config_parse_kill_mode, "KILLMODE" },
3689 { config_parse_kill_signal, "SIGNAL" },
3690 { config_parse_socket_listen, "SOCKET [...]" },
3691 { config_parse_socket_bind, "SOCKETBIND" },
3692 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3693 { config_parse_sec, "SECONDS" },
3694 { config_parse_nsec, "NANOSECONDS" },
3695 { config_parse_namespace_path_strv, "PATH [...]" },
3696 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3697 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3698 { config_parse_unit_string_printf, "STRING" },
3699 { config_parse_trigger_unit, "UNIT" },
3700 { config_parse_timer, "TIMER" },
3701 { config_parse_path_spec, "PATH" },
3702 { config_parse_notify_access, "ACCESS" },
3703 { config_parse_ip_tos, "TOS" },
3704 { config_parse_unit_condition_path, "CONDITION" },
3705 { config_parse_unit_condition_string, "CONDITION" },
3706 { config_parse_unit_condition_null, "CONDITION" },
3707 { config_parse_unit_slice, "SLICE" },
3708 { config_parse_documentation, "URL" },
3709 { config_parse_service_timeout, "SECONDS" },
3710 { config_parse_failure_action, "ACTION" },
3711 { config_parse_set_status, "STATUS" },
3712 { config_parse_service_sockets, "SOCKETS" },
3713 { config_parse_environ, "ENVIRON" },
3715 { config_parse_syscall_filter, "SYSCALLS" },
3716 { config_parse_syscall_archs, "ARCHS" },
3717 { config_parse_syscall_errno, "ERRNO" },
3718 { config_parse_address_families, "FAMILIES" },
3720 { config_parse_cpu_shares, "SHARES" },
3721 { config_parse_memory_limit, "LIMIT" },
3722 { config_parse_device_allow, "DEVICE" },
3723 { config_parse_device_policy, "POLICY" },
3724 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3725 { config_parse_blockio_weight, "WEIGHT" },
3726 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3727 { config_parse_long, "LONG" },
3728 { config_parse_socket_service, "SERVICE" },
3730 { config_parse_exec_selinux_context, "LABEL" },
3732 { config_parse_job_mode, "MODE" },
3733 { config_parse_job_mode_isolate, "BOOLEAN" },
3734 { config_parse_personality, "PERSONALITY" },
3737 const char *prev = NULL;
3742 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3743 const char *rvalue = "OTHER", *lvalue;
3747 const ConfigPerfItem *p;
3749 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3751 dot = strchr(i, '.');
3752 lvalue = dot ? dot + 1 : i;
3756 if (!prev || !strneq(prev, i, prefix_len+1)) {
3760 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3763 for (j = 0; j < ELEMENTSOF(table); j++)
3764 if (p->parse == table[j].callback) {
3765 rvalue = table[j].rvalue;
3769 fprintf(f, "%s=%s\n", lvalue, rvalue);