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;
107 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
108 _cleanup_free_ char *t = NULL, *k = NULL;
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));
131 int config_parse_unit_string_printf(const char *unit,
132 const char *filename,
135 unsigned section_line,
143 _cleanup_free_ char *k = NULL;
151 r = unit_full_printf(u, rvalue, &k);
153 log_syntax(unit, LOG_ERR, filename, line, -r,
154 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
156 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
157 k ? k : rvalue, data, userdata);
160 int config_parse_unit_strv_printf(const char *unit,
161 const char *filename,
164 unsigned section_line,
172 _cleanup_free_ char *k = NULL;
180 r = unit_full_printf(u, rvalue, &k);
182 log_syntax(unit, LOG_ERR, filename, line, -r,
183 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
185 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
186 k ? k : rvalue, data, userdata);
189 int config_parse_unit_path_printf(const char *unit,
190 const char *filename,
193 unsigned section_line,
201 _cleanup_free_ char *k = NULL;
209 r = unit_full_printf(u, rvalue, &k);
211 log_syntax(unit, LOG_ERR, filename, line, -r,
212 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
214 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype,
215 k ? k : rvalue, data, userdata);
218 int config_parse_socket_listen(const char *unit,
219 const char *filename,
222 unsigned section_line,
229 SocketPort *p, *tail;
240 if (isempty(rvalue)) {
241 /* An empty assignment removes all ports */
242 socket_free_ports(s);
246 p = new0(SocketPort, 1);
250 if (ltype != SOCKET_SOCKET) {
253 r = unit_full_printf(UNIT(s), rvalue, &p->path);
255 p->path = strdup(rvalue);
260 log_syntax(unit, LOG_ERR, filename, line, -r,
261 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
264 path_kill_slashes(p->path);
266 } else if (streq(lvalue, "ListenNetlink")) {
267 _cleanup_free_ char *k = NULL;
269 p->type = SOCKET_SOCKET;
270 r = unit_full_printf(UNIT(s), rvalue, &k);
272 log_syntax(unit, LOG_ERR, filename, line, -r,
273 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
275 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
277 log_syntax(unit, LOG_ERR, filename, line, -r,
278 "Failed to parse address value, ignoring: %s", rvalue);
284 _cleanup_free_ char *k = NULL;
286 p->type = SOCKET_SOCKET;
287 r = unit_full_printf(UNIT(s), rvalue, &k);
289 log_syntax(unit, LOG_ERR, filename, line, -r,
290 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
292 r = socket_address_parse(&p->address, k ? k : rvalue);
294 log_syntax(unit, LOG_ERR, filename, line, -r,
295 "Failed to parse address value, ignoring: %s", rvalue);
300 if (streq(lvalue, "ListenStream"))
301 p->address.type = SOCK_STREAM;
302 else if (streq(lvalue, "ListenDatagram"))
303 p->address.type = SOCK_DGRAM;
305 assert(streq(lvalue, "ListenSequentialPacket"));
306 p->address.type = SOCK_SEQPACKET;
309 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
310 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
311 "Address family not supported, ignoring: %s", rvalue);
321 LIST_FIND_TAIL(port, s->ports, tail);
322 LIST_INSERT_AFTER(port, s->ports, tail, p);
324 LIST_PREPEND(port, s->ports, p);
329 int config_parse_socket_bind(const char *unit,
330 const char *filename,
333 unsigned section_line,
341 SocketAddressBindIPv6Only b;
350 b = socket_address_bind_ipv6_only_from_string(rvalue);
354 r = parse_boolean(rvalue);
356 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
357 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
361 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
363 s->bind_ipv6_only = b;
368 int config_parse_exec_nice(const char *unit,
369 const char *filename,
372 unsigned section_line,
379 ExecContext *c = data;
387 r = safe_atoi(rvalue, &priority);
389 log_syntax(unit, LOG_ERR, filename, line, -r,
390 "Failed to parse nice priority, ignoring: %s. ", rvalue);
394 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
395 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
396 "Nice priority out of range, ignoring: %s", rvalue);
406 int config_parse_exec_oom_score_adjust(const char* unit,
407 const char *filename,
410 unsigned section_line,
417 ExecContext *c = data;
425 r = safe_atoi(rvalue, &oa);
427 log_syntax(unit, LOG_ERR, filename, line, -r,
428 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
432 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
433 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
434 "OOM score adjust value out of range, ignoring: %s", rvalue);
438 c->oom_score_adjust = oa;
439 c->oom_score_adjust_set = true;
444 int config_parse_exec(const char *unit,
445 const char *filename,
448 unsigned section_line,
455 ExecCommand **e = data, *nce;
467 if (isempty(rvalue)) {
468 /* An empty assignment resets the list */
469 exec_command_free_list(*e);
474 /* We accept an absolute path as first argument, or
475 * alternatively an absolute prefixed with @ to allow
476 * overriding of argv[0]. */
482 bool honour_argv0 = false, ignore = false;
488 rvalue += strspn(rvalue, WHITESPACE);
493 for (i = 0; i < 2; i++) {
494 if (rvalue[0] == '-' && !ignore) {
499 if (rvalue[0] == '@' && !honour_argv0) {
505 if (*rvalue != '/') {
506 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
507 "Executable path is not absolute, ignoring: %s", rvalue);
512 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
513 if (strneq(w, ";", MAX(l, 1U)))
519 n = new(char*, k + !honour_argv0);
524 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
525 if (strneq(w, ";", MAX(l, 1U)))
527 else if (strneq(w, "\\;", MAX(l, 1U)))
530 if (honour_argv0 && w == rvalue) {
533 path = strndup(w, l);
539 if (!utf8_is_valid(path)) {
540 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
548 c = n[k++] = cunescape_length(w, l);
554 if (!utf8_is_valid(c)) {
555 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
565 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
566 "Invalid command line, ignoring: %s", rvalue);
579 assert(path_is_absolute(path));
581 nce = new0(ExecCommand, 1);
589 nce->ignore = ignore;
591 path_kill_slashes(nce->path);
593 exec_command_append_list(e, nce);
609 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
610 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
612 int config_parse_socket_bindtodevice(const char* unit,
613 const char *filename,
616 unsigned section_line,
631 if (rvalue[0] && !streq(rvalue, "*")) {
638 free(s->bind_to_device);
639 s->bind_to_device = n;
644 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
645 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
647 int config_parse_exec_io_class(const char *unit,
648 const char *filename,
651 unsigned section_line,
658 ExecContext *c = data;
666 x = ioprio_class_from_string(rvalue);
668 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
669 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
673 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
674 c->ioprio_set = true;
679 int config_parse_exec_io_priority(const char *unit,
680 const char *filename,
683 unsigned section_line,
690 ExecContext *c = data;
698 r = safe_atoi(rvalue, &i);
699 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
700 log_syntax(unit, LOG_ERR, filename, line, -r,
701 "Failed to parse IO priority, ignoring: %s", rvalue);
705 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
706 c->ioprio_set = true;
711 int config_parse_exec_cpu_sched_policy(const char *unit,
712 const char *filename,
715 unsigned section_line,
723 ExecContext *c = data;
731 x = sched_policy_from_string(rvalue);
733 log_syntax(unit, LOG_ERR, filename, line, -x,
734 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
738 c->cpu_sched_policy = x;
739 /* Moving to or from real-time policy? We need to adjust the priority */
740 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
741 c->cpu_sched_set = true;
746 int config_parse_exec_cpu_sched_prio(const char *unit,
747 const char *filename,
750 unsigned section_line,
757 ExecContext *c = data;
765 r = safe_atoi(rvalue, &i);
767 log_syntax(unit, LOG_ERR, filename, line, -r,
768 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
772 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
773 min = sched_get_priority_min(c->cpu_sched_policy);
774 max = sched_get_priority_max(c->cpu_sched_policy);
776 if (i < min || i > max) {
777 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
778 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
782 c->cpu_sched_priority = i;
783 c->cpu_sched_set = true;
788 int config_parse_exec_cpu_affinity(const char *unit,
789 const char *filename,
792 unsigned section_line,
799 ExecContext *c = data;
809 if (isempty(rvalue)) {
810 /* An empty assignment resets the CPU list */
817 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
818 _cleanup_free_ char *t = NULL;
826 r = safe_atou(t, &cpu);
829 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
834 if (r < 0 || cpu >= c->cpuset_ncpus) {
835 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
836 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
840 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
846 int config_parse_exec_capabilities(const char *unit,
847 const char *filename,
850 unsigned section_line,
857 ExecContext *c = data;
865 cap = cap_from_text(rvalue);
867 log_syntax(unit, LOG_ERR, filename, line, errno,
868 "Failed to parse capabilities, ignoring: %s", rvalue);
873 cap_free(c->capabilities);
874 c->capabilities = cap;
879 int config_parse_exec_secure_bits(const char *unit,
880 const char *filename,
883 unsigned section_line,
890 ExecContext *c = data;
900 if (isempty(rvalue)) {
901 /* An empty assignment resets the field */
906 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
907 if (first_word(w, "keep-caps"))
908 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
909 else if (first_word(w, "keep-caps-locked"))
910 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
911 else if (first_word(w, "no-setuid-fixup"))
912 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
913 else if (first_word(w, "no-setuid-fixup-locked"))
914 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
915 else if (first_word(w, "noroot"))
916 c->secure_bits |= 1<<SECURE_NOROOT;
917 else if (first_word(w, "noroot-locked"))
918 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
920 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
921 "Failed to parse secure bits, ignoring: %s", rvalue);
929 int config_parse_bounding_set(const char *unit,
930 const char *filename,
933 unsigned section_line,
940 uint64_t *capability_bounding_set_drop = data;
952 if (rvalue[0] == '~') {
957 /* Note that we store this inverted internally, since the
958 * kernel wants it like this. But we actually expose it
959 * non-inverted everywhere to have a fully normalized
962 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
963 _cleanup_free_ char *t = NULL;
971 r = cap_from_name(t, &cap);
973 log_syntax(unit, LOG_ERR, filename, line, errno,
974 "Failed to parse capability in bounding set, ignoring: %s", t);
978 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
982 *capability_bounding_set_drop |= sum;
984 *capability_bounding_set_drop |= ~sum;
989 int config_parse_limit(const char *unit,
990 const char *filename,
993 unsigned section_line,
1000 struct rlimit **rl = data;
1001 unsigned long long u;
1010 if (streq(rvalue, "infinity"))
1011 u = (unsigned long long) RLIM_INFINITY;
1015 r = safe_atollu(rvalue, &u);
1017 log_syntax(unit, LOG_ERR, filename, line, -r,
1018 "Failed to parse resource value, ignoring: %s", rvalue);
1024 *rl = new(struct rlimit, 1);
1029 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1033 #ifdef HAVE_SYSV_COMPAT
1034 int config_parse_sysv_priority(const char *unit,
1035 const char *filename,
1037 const char *section,
1038 unsigned section_line,
1045 int *priority = data;
1053 r = safe_atoi(rvalue, &i);
1054 if (r < 0 || i < 0) {
1055 log_syntax(unit, LOG_ERR, filename, line, -r,
1056 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1060 *priority = (int) i;
1065 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1067 int config_parse_kill_signal(const char *unit,
1068 const char *filename,
1070 const char *section,
1071 unsigned section_line,
1086 r = signal_from_string_try_harder(rvalue);
1088 log_syntax(unit, LOG_ERR, filename, line, -r,
1089 "Failed to parse kill signal, ignoring: %s", rvalue);
1097 int config_parse_exec_mount_flags(const char *unit,
1098 const char *filename,
1100 const char *section,
1101 unsigned section_line,
1108 ExecContext *c = data;
1112 unsigned long flags = 0;
1119 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1120 _cleanup_free_ char *t;
1126 if (streq(t, "shared"))
1128 else if (streq(t, "slave"))
1130 else if (streq(w, "private"))
1133 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1138 c->mount_flags = flags;
1142 int config_parse_exec_selinux_context(
1144 const char *filename,
1146 const char *section,
1147 unsigned section_line,
1154 ExecContext *c = data;
1165 if (isempty(rvalue)) {
1166 free(c->selinux_context);
1167 c->selinux_context = NULL;
1168 c->selinux_context_ignore = false;
1172 if (rvalue[0] == '-') {
1178 r = unit_name_printf(u, rvalue, &k);
1180 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1184 free(c->selinux_context);
1185 c->selinux_context = k;
1186 c->selinux_context_ignore = ignore;
1191 int config_parse_exec_apparmor_profile(
1193 const char *filename,
1195 const char *section,
1196 unsigned section_line,
1203 ExecContext *c = data;
1214 if (isempty(rvalue)) {
1215 free(c->apparmor_profile);
1216 c->apparmor_profile = NULL;
1217 c->apparmor_profile_ignore = false;
1221 if (rvalue[0] == '-') {
1227 r = unit_name_printf(u, rvalue, &k);
1229 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1233 free(c->apparmor_profile);
1234 c->apparmor_profile = k;
1235 c->apparmor_profile_ignore = ignore;
1240 int config_parse_timer(const char *unit,
1241 const char *filename,
1243 const char *section,
1244 unsigned section_line,
1255 CalendarSpec *c = NULL;
1262 if (isempty(rvalue)) {
1263 /* Empty assignment resets list */
1264 timer_free_values(t);
1268 b = timer_base_from_string(lvalue);
1270 log_syntax(unit, LOG_ERR, filename, line, -b,
1271 "Failed to parse timer base, ignoring: %s", lvalue);
1275 if (b == TIMER_CALENDAR) {
1276 if (calendar_spec_from_string(rvalue, &c) < 0) {
1277 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1278 "Failed to parse calendar specification, ignoring: %s",
1283 if (parse_sec(rvalue, &u) < 0) {
1284 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1285 "Failed to parse timer value, ignoring: %s",
1291 v = new0(TimerValue, 1);
1297 v->calendar_spec = c;
1299 LIST_PREPEND(value, t->values, v);
1304 int config_parse_trigger_unit(
1306 const char *filename,
1308 const char *section,
1309 unsigned section_line,
1316 _cleanup_free_ char *p = NULL;
1326 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1327 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1328 "Multiple units to trigger specified, ignoring: %s", rvalue);
1332 r = unit_name_printf(u, rvalue, &p);
1334 log_syntax(unit, LOG_ERR, filename, line, -r,
1335 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1337 type = unit_name_to_type(p ?: rvalue);
1339 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1340 "Unit type not valid, ignoring: %s", rvalue);
1344 if (type == u->type) {
1345 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1346 "Trigger cannot be of same type, ignoring: %s", rvalue);
1350 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1352 log_syntax(unit, LOG_ERR, filename, line, -r,
1353 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1360 int config_parse_path_spec(const char *unit,
1361 const char *filename,
1363 const char *section,
1364 unsigned section_line,
1374 _cleanup_free_ char *k = NULL;
1382 if (isempty(rvalue)) {
1383 /* Empty assignment clears list */
1388 b = path_type_from_string(lvalue);
1390 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1391 "Failed to parse path type, ignoring: %s", lvalue);
1395 r = unit_full_printf(UNIT(p), rvalue, &k);
1401 log_syntax(unit, LOG_ERR, filename, line, -r,
1402 "Failed to resolve unit specifiers on %s. Ignoring.",
1406 if (!path_is_absolute(k)) {
1407 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1408 "Path is not absolute, ignoring: %s", k);
1412 s = new0(PathSpec, 1);
1417 s->path = path_kill_slashes(k);
1422 LIST_PREPEND(spec, p->specs, s);
1427 int config_parse_socket_service(const char *unit,
1428 const char *filename,
1430 const char *section,
1431 unsigned section_line,
1438 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1442 _cleanup_free_ char *p = NULL;
1449 r = unit_name_printf(UNIT(s), rvalue, &p);
1451 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1455 if (!endswith(p, ".service")) {
1456 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1460 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1462 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1466 unit_ref_set(&s->service, x);
1471 int config_parse_service_sockets(const char *unit,
1472 const char *filename,
1474 const char *section,
1475 unsigned section_line,
1492 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1493 _cleanup_free_ char *t = NULL, *k = NULL;
1499 r = unit_name_printf(UNIT(s), t, &k);
1501 log_syntax(unit, LOG_ERR, filename, line, -r,
1502 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1504 if (!endswith(k ?: t, ".socket")) {
1505 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1506 "Unit must be of type socket, ignoring: %s", k ?: t);
1510 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1512 log_syntax(unit, LOG_ERR, filename, line, -r,
1513 "Failed to add dependency on %s, ignoring: %s",
1514 k ?: t, strerror(-r));
1516 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1524 int config_parse_service_timeout(const char *unit,
1525 const char *filename,
1527 const char *section,
1528 unsigned section_line,
1535 Service *s = userdata;
1543 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1544 rvalue, data, userdata);
1548 if (streq(lvalue, "TimeoutSec")) {
1549 s->start_timeout_defined = true;
1550 s->timeout_stop_usec = s->timeout_start_usec;
1551 } else if (streq(lvalue, "TimeoutStartSec"))
1552 s->start_timeout_defined = true;
1557 int config_parse_busname_service(
1559 const char *filename,
1561 const char *section,
1562 unsigned section_line,
1569 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1573 _cleanup_free_ char *p = NULL;
1580 r = unit_name_printf(UNIT(n), rvalue, &p);
1582 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1586 if (!endswith(p, ".service")) {
1587 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1591 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1593 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1597 unit_ref_set(&n->service, x);
1602 int config_parse_bus_policy(
1604 const char *filename,
1606 const char *section,
1607 unsigned section_line,
1614 _cleanup_free_ BusNamePolicy *p = NULL;
1615 _cleanup_free_ char *id_str = NULL;
1616 BusName *busname = data;
1625 p = new0(BusNamePolicy, 1);
1629 if (streq(lvalue, "AllowUser"))
1630 p->type = BUSNAME_POLICY_TYPE_USER;
1631 else if (streq(lvalue, "AllowGroup"))
1632 p->type = BUSNAME_POLICY_TYPE_GROUP;
1633 else if (streq(lvalue, "AllowWorld"))
1634 p->type = BUSNAME_POLICY_TYPE_WORLD;
1636 assert_not_reached("Unknown lvalue");
1638 id_str = strdup(rvalue);
1642 if (p->type != BUSNAME_POLICY_TYPE_WORLD) {
1643 access_str = strchr(id_str, ' ');
1645 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy value '%s'", rvalue);
1652 if (p->type == BUSNAME_POLICY_TYPE_USER) {
1653 const char *user = id_str;
1655 r = get_user_creds(&user, &p->uid, NULL, NULL, NULL);
1657 log_syntax(unit, LOG_ERR, filename, line, r, "Unable to parse uid from '%s'", id_str);
1661 const char *group = id_str;
1663 r = get_group_creds(&group, &p->gid);
1665 log_syntax(unit, LOG_ERR, filename, line, -errno, "Unable to parse gid from '%s'", id_str);
1670 access_str = id_str;
1673 p->access = busname_policy_access_from_string(access_str);
1674 if (p->access < 0) {
1675 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy access type '%s'", access_str);
1679 LIST_PREPEND(policy, busname->policy, p);
1685 int config_parse_unit_env_file(const char *unit,
1686 const char *filename,
1688 const char *section,
1689 unsigned section_line,
1698 _cleanup_free_ char *n = NULL;
1707 if (isempty(rvalue)) {
1708 /* Empty assignment frees the list */
1714 r = unit_full_printf(u, rvalue, &n);
1716 log_syntax(unit, LOG_ERR, filename, line, r,
1717 "Failed to resolve specifiers, ignoring: %s", rvalue);
1720 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1721 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1722 "Path '%s' is not absolute, ignoring.", s);
1726 r = strv_extend(env, s);
1733 int config_parse_environ(const char *unit,
1734 const char *filename,
1736 const char *section,
1737 unsigned section_line,
1745 char*** env = data, *w, *state;
1747 _cleanup_free_ char *k = NULL;
1755 if (isempty(rvalue)) {
1756 /* Empty assignment resets the list */
1763 r = unit_full_printf(u, rvalue, &k);
1765 log_syntax(unit, LOG_ERR, filename, line, -r,
1766 "Failed to resolve specifiers, ignoring: %s", rvalue);
1774 FOREACH_WORD_QUOTED(w, l, k, state) {
1775 _cleanup_free_ char *n;
1778 n = cunescape_length(w, l);
1782 if (!env_assignment_is_valid(n)) {
1783 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1784 "Invalid environment assignment, ignoring: %s", rvalue);
1788 x = strv_env_set(*env, n);
1799 int config_parse_ip_tos(const char *unit,
1800 const char *filename,
1802 const char *section,
1803 unsigned section_line,
1810 int *ip_tos = data, x;
1817 x = ip_tos_from_string(rvalue);
1819 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1820 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1828 int config_parse_unit_condition_path(const char *unit,
1829 const char *filename,
1831 const char *section,
1832 unsigned section_line,
1839 ConditionType cond = ltype;
1841 bool trigger, negate;
1843 _cleanup_free_ char *p = NULL;
1851 if (isempty(rvalue)) {
1852 /* Empty assignment resets the list */
1853 condition_free_list(u->conditions);
1854 u->conditions = NULL;
1858 trigger = rvalue[0] == '|';
1862 negate = rvalue[0] == '!';
1866 r = unit_full_printf(u, rvalue, &p);
1868 log_syntax(unit, LOG_ERR, filename, line, -r,
1869 "Failed to resolve specifiers, ignoring: %s", rvalue);
1876 if (!path_is_absolute(p)) {
1877 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1878 "Path in condition not absolute, ignoring: %s", p);
1882 c = condition_new(cond, p, trigger, negate);
1886 LIST_PREPEND(conditions, u->conditions, c);
1890 int config_parse_unit_condition_string(const char *unit,
1891 const char *filename,
1893 const char *section,
1894 unsigned section_line,
1901 ConditionType cond = ltype;
1903 bool trigger, negate;
1905 _cleanup_free_ char *s = NULL;
1913 if (isempty(rvalue)) {
1914 /* Empty assignment resets the list */
1915 condition_free_list(u->conditions);
1916 u->conditions = NULL;
1920 trigger = rvalue[0] == '|';
1924 negate = rvalue[0] == '!';
1928 r = unit_full_printf(u, rvalue, &s);
1930 log_syntax(unit, LOG_ERR, filename, line, -r,
1931 "Failed to resolve specifiers, ignoring: %s", rvalue);
1938 c = condition_new(cond, s, trigger, negate);
1942 LIST_PREPEND(conditions, u->conditions, c);
1946 int config_parse_unit_condition_null(const char *unit,
1947 const char *filename,
1949 const char *section,
1950 unsigned section_line,
1959 bool trigger, negate;
1967 if (isempty(rvalue)) {
1968 /* Empty assignment resets the list */
1969 condition_free_list(u->conditions);
1970 u->conditions = NULL;
1974 trigger = rvalue[0] == '|';
1978 negate = rvalue[0] == '!';
1982 b = parse_boolean(rvalue);
1984 log_syntax(unit, LOG_ERR, filename, line, -b,
1985 "Failed to parse boolean value in condition, ignoring: %s",
1993 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1997 LIST_PREPEND(conditions, u->conditions, c);
2001 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2002 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2004 int config_parse_unit_requires_mounts_for(
2006 const char *filename,
2008 const char *section,
2009 unsigned section_line,
2026 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2028 _cleanup_free_ char *n;
2034 if (!utf8_is_valid(n)) {
2035 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2039 r = unit_require_mounts_for(u, n);
2041 log_syntax(unit, LOG_ERR, filename, line, r,
2042 "Failed to add required mount for, ignoring: %s", rvalue);
2050 int config_parse_documentation(const char *unit,
2051 const char *filename,
2053 const char *section,
2054 unsigned section_line,
2070 if (isempty(rvalue)) {
2071 /* Empty assignment resets the list */
2072 strv_free(u->documentation);
2073 u->documentation = NULL;
2077 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2078 rvalue, data, userdata);
2082 for (a = b = u->documentation; a && *a; a++) {
2084 if (is_valid_documentation_url(*a))
2087 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2088 "Invalid URL, ignoring: %s", *a);
2099 int config_parse_syscall_filter(
2101 const char *filename,
2103 const char *section,
2104 unsigned section_line,
2111 static const char default_syscalls[] =
2118 ExecContext *c = data;
2120 bool invert = false;
2130 if (isempty(rvalue)) {
2131 /* Empty assignment resets the list */
2132 set_free(c->syscall_filter);
2133 c->syscall_filter = NULL;
2134 c->syscall_whitelist = false;
2138 if (rvalue[0] == '~') {
2143 if (!c->syscall_filter) {
2144 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2145 if (!c->syscall_filter)
2149 /* Allow everything but the ones listed */
2150 c->syscall_whitelist = false;
2154 /* Allow nothing but the ones listed */
2155 c->syscall_whitelist = true;
2157 /* Accept default syscalls if we are on a whitelist */
2158 NULSTR_FOREACH(i, default_syscalls) {
2161 id = seccomp_syscall_resolve_name(i);
2165 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2174 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2175 _cleanup_free_ char *t = NULL;
2182 id = seccomp_syscall_resolve_name(t);
2184 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2188 /* If we previously wanted to forbid a syscall and now
2189 * we want to allow it, then remove it from the list
2191 if (!invert == c->syscall_whitelist) {
2192 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2198 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2201 /* Turn on NNP, but only if it wasn't configured explicitly
2202 * before, and only if we are in user mode. */
2203 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2204 c->no_new_privileges = true;
2209 int config_parse_syscall_archs(
2211 const char *filename,
2213 const char *section,
2214 unsigned section_line,
2226 if (isempty(rvalue)) {
2232 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2236 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2237 _cleanup_free_ char *t = NULL;
2244 r = seccomp_arch_from_string(t, &a);
2246 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2250 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2260 int config_parse_syscall_errno(
2262 const char *filename,
2264 const char *section,
2265 unsigned section_line,
2272 ExecContext *c = data;
2279 if (isempty(rvalue)) {
2280 /* Empty assignment resets to KILL */
2281 c->syscall_errno = 0;
2285 e = errno_from_name(rvalue);
2287 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2291 c->syscall_errno = e;
2295 int config_parse_address_families(
2297 const char *filename,
2299 const char *section,
2300 unsigned section_line,
2307 ExecContext *c = data;
2309 bool invert = false;
2319 if (isempty(rvalue)) {
2320 /* Empty assignment resets the list */
2321 set_free(c->address_families);
2322 c->address_families = NULL;
2323 c->address_families_whitelist = false;
2327 if (rvalue[0] == '~') {
2332 if (!c->address_families) {
2333 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2334 if (!c->address_families)
2337 c->address_families_whitelist = !invert;
2340 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2341 _cleanup_free_ char *t = NULL;
2348 af = af_from_name(t);
2350 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
2354 /* If we previously wanted to forbid an address family and now
2355 * we want to allow it, then remove it from the list
2357 if (!invert == c->address_families_whitelist) {
2358 r = set_put(c->address_families, INT_TO_PTR(af));
2364 set_remove(c->address_families, INT_TO_PTR(af));
2371 int config_parse_unit_slice(
2373 const char *filename,
2375 const char *section,
2376 unsigned section_line,
2383 _cleanup_free_ char *k = NULL;
2384 Unit *u = userdata, *slice;
2392 r = unit_name_printf(u, rvalue, &k);
2394 log_syntax(unit, LOG_ERR, filename, line, -r,
2395 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2402 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2404 log_syntax(unit, LOG_ERR, filename, line, -r,
2405 "Failed to load slice unit %s. Ignoring.", k);
2409 if (slice->type != UNIT_SLICE) {
2410 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2411 "Slice unit %s is not a slice. Ignoring.", k);
2415 unit_ref_set(&u->slice, slice);
2419 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2421 int config_parse_cpu_shares(
2423 const char *filename,
2425 const char *section,
2426 unsigned section_line,
2433 unsigned long *shares = data, lu;
2440 if (isempty(rvalue)) {
2441 *shares = (unsigned long) -1;
2445 r = safe_atolu(rvalue, &lu);
2446 if (r < 0 || lu <= 0) {
2447 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU shares '%s' invalid. Ignoring.", rvalue);
2455 int config_parse_cpu_quota(
2457 const char *filename,
2459 const char *section,
2460 unsigned section_line,
2467 CGroupContext *c = data;
2474 if (isempty(rvalue)) {
2475 c->cpu_quota_per_sec_usec = (usec_t) -1;
2479 if (!endswith(rvalue, "%")) {
2481 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2485 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2486 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' invalid. Ignoring.", rvalue);
2490 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2495 int config_parse_memory_limit(
2497 const char *filename,
2499 const char *section,
2500 unsigned section_line,
2507 CGroupContext *c = data;
2511 if (isempty(rvalue)) {
2512 c->memory_limit = (uint64_t) -1;
2516 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2518 r = parse_size(rvalue, 1024, &bytes);
2520 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
2524 c->memory_limit = (uint64_t) bytes;
2528 int config_parse_device_allow(
2530 const char *filename,
2532 const char *section,
2533 unsigned section_line,
2540 _cleanup_free_ char *path = NULL;
2541 CGroupContext *c = data;
2542 CGroupDeviceAllow *a;
2546 if (isempty(rvalue)) {
2547 while (c->device_allow)
2548 cgroup_context_free_device_allow(c, c->device_allow);
2553 n = strcspn(rvalue, WHITESPACE);
2554 path = strndup(rvalue, n);
2558 if (!startswith(path, "/dev/") &&
2559 !startswith(path, "block-") &&
2560 !startswith(path, "char-")) {
2561 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2565 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2569 if (!in_charset(m, "rwm")) {
2570 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
2574 a = new0(CGroupDeviceAllow, 1);
2580 a->r = !!strchr(m, 'r');
2581 a->w = !!strchr(m, 'w');
2582 a->m = !!strchr(m, 'm');
2584 LIST_PREPEND(device_allow, c->device_allow, a);
2588 int config_parse_blockio_weight(
2590 const char *filename,
2592 const char *section,
2593 unsigned section_line,
2600 unsigned long *weight = data, lu;
2607 if (isempty(rvalue)) {
2608 *weight = (unsigned long) -1;
2612 r = safe_atolu(rvalue, &lu);
2613 if (r < 0 || lu < 10 || lu > 1000) {
2614 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
2622 int config_parse_blockio_device_weight(
2624 const char *filename,
2626 const char *section,
2627 unsigned section_line,
2634 _cleanup_free_ char *path = NULL;
2635 CGroupBlockIODeviceWeight *w;
2636 CGroupContext *c = data;
2646 if (isempty(rvalue)) {
2647 while (c->blockio_device_weights)
2648 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2653 n = strcspn(rvalue, WHITESPACE);
2654 weight = rvalue + n;
2656 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Expected block device and device weight. Ignoring.");
2660 path = strndup(rvalue, n);
2664 if (!path_startswith(path, "/dev")) {
2665 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2669 weight += strspn(weight, WHITESPACE);
2670 r = safe_atolu(weight, &lu);
2671 if (r < 0 || lu < 10 || lu > 1000) {
2672 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
2676 w = new0(CGroupBlockIODeviceWeight, 1);
2685 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2689 int config_parse_blockio_bandwidth(
2691 const char *filename,
2693 const char *section,
2694 unsigned section_line,
2701 _cleanup_free_ char *path = NULL;
2702 CGroupBlockIODeviceBandwidth *b;
2703 CGroupContext *c = data;
2704 const char *bandwidth;
2714 read = streq("BlockIOReadBandwidth", lvalue);
2716 if (isempty(rvalue)) {
2717 CGroupBlockIODeviceBandwidth *next;
2719 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2720 if (b->read == read)
2721 cgroup_context_free_blockio_device_bandwidth(c, b);
2726 n = strcspn(rvalue, WHITESPACE);
2727 bandwidth = rvalue + n;
2728 bandwidth += strspn(bandwidth, WHITESPACE);
2731 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2732 "Expected space separated pair of device node and bandwidth. Ignoring.");
2736 path = strndup(rvalue, n);
2740 if (!path_startswith(path, "/dev")) {
2741 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2742 "Invalid device node path '%s'. Ignoring.", path);
2746 r = parse_size(bandwidth, 1000, &bytes);
2747 if (r < 0 || bytes <= 0) {
2748 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2752 b = new0(CGroupBlockIODeviceBandwidth, 1);
2758 b->bandwidth = (uint64_t) bytes;
2761 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2766 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2768 int config_parse_job_mode_isolate(
2770 const char *filename,
2772 const char *section,
2773 unsigned section_line,
2787 r = parse_boolean(rvalue);
2789 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2793 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2797 int config_parse_personality(
2799 const char *filename,
2801 const char *section,
2802 unsigned section_line,
2809 unsigned long *personality = data, p;
2814 assert(personality);
2816 p = personality_from_string(rvalue);
2817 if (p == 0xffffffffUL) {
2818 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2819 "Failed to parse personality, ignoring: %s", rvalue);
2827 int config_parse_runtime_directory(
2829 const char *filename,
2831 const char *section,
2832 unsigned section_line,
2839 char***rt = data, *w, *state;
2848 if (isempty(rvalue)) {
2849 /* Empty assignment resets the list */
2855 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2856 _cleanup_free_ char *n;
2862 if (!filename_is_safe(n)) {
2863 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2867 r = strv_push(rt, n);
2877 int config_parse_set_status(
2879 const char *filename,
2881 const char *section,
2882 unsigned section_line,
2893 ExitStatusSet *status_set = data;
2900 if (isempty(rvalue)) {
2901 /* Empty assignment resets the list */
2903 set_free(status_set->signal);
2904 set_free(status_set->code);
2906 status_set->signal = status_set->code = NULL;
2910 FOREACH_WORD(w, l, rvalue, state) {
2911 _cleanup_free_ char *temp;
2914 temp = strndup(w, l);
2918 r = safe_atoi(temp, &val);
2920 val = signal_from_string_try_harder(temp);
2923 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
2927 r = set_put(status_set->signal, INT_TO_PTR(val));
2929 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2933 log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", w);
2937 if (val < 0 || val > 255)
2938 log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
2940 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
2944 r = set_put(status_set->code, INT_TO_PTR(val));
2946 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2956 int config_parse_namespace_path_strv(
2958 const char *filename,
2960 const char *section,
2961 unsigned section_line,
2968 char*** sv = data, *w, *state;
2977 if (isempty(rvalue)) {
2978 /* Empty assignment resets the list */
2984 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2985 _cleanup_free_ char *n;
2992 if (!utf8_is_valid(n)) {
2993 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2997 offset = n[0] == '-';
2998 if (!path_is_absolute(n + offset)) {
2999 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
3003 path_kill_slashes(n);
3005 r = strv_push(sv, n);
3015 int config_parse_no_new_privileges(
3017 const char *filename,
3019 const char *section,
3020 unsigned section_line,
3027 ExecContext *c = data;
3035 k = parse_boolean(rvalue);
3037 log_syntax(unit, LOG_ERR, filename, line, -k, "Failed to parse boolean value, ignoring: %s", rvalue);
3041 c->no_new_privileges = !!k;
3042 c->no_new_privileges_set = true;
3047 #define FOLLOW_MAX 8
3049 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3060 /* This will update the filename pointer if the loaded file is
3061 * reached by a symlink. The old string will be freed. */
3064 char *target, *name;
3066 if (c++ >= FOLLOW_MAX)
3069 path_kill_slashes(*filename);
3071 /* Add the file name we are currently looking at to
3072 * the names of this unit, but only if it is a valid
3074 name = basename(*filename);
3076 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3078 id = set_get(names, name);
3084 r = set_consume(names, id);
3090 /* Try to open the file name, but don't if its a symlink */
3091 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3098 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3099 r = readlink_and_make_absolute(*filename, &target);
3107 f = fdopen(fd, "re");
3119 static int merge_by_names(Unit **u, Set *names, const char *id) {
3127 /* Let's try to add in all symlink names we found */
3128 while ((k = set_steal_first(names))) {
3130 /* First try to merge in the other name into our
3132 r = unit_merge_by_name(*u, k);
3136 /* Hmm, we couldn't merge the other unit into
3137 * ours? Then let's try it the other way
3140 other = manager_get_unit((*u)->manager, k);
3144 r = unit_merge(other, *u);
3147 return merge_by_names(u, names, NULL);
3155 unit_choose_id(*u, id);
3163 static int load_from_path(Unit *u, const char *path) {
3165 _cleanup_set_free_free_ Set *symlink_names = NULL;
3166 _cleanup_fclose_ FILE *f = NULL;
3167 _cleanup_free_ char *filename = NULL;
3175 symlink_names = set_new(string_hash_func, string_compare_func);
3179 if (path_is_absolute(path)) {
3181 filename = strdup(path);
3185 r = open_follow(&filename, &f, symlink_names, &id);
3197 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3199 /* Instead of opening the path right away, we manually
3200 * follow all symlinks and add their name to our unit
3201 * name set while doing so */
3202 filename = path_make_absolute(path, *p);
3206 if (u->manager->unit_path_cache &&
3207 !set_get(u->manager->unit_path_cache, filename))
3210 r = open_follow(&filename, &f, symlink_names, &id);
3219 /* Empty the symlink names for the next run */
3220 set_clear_free(symlink_names);
3229 /* Hmm, no suitable file found? */
3233 r = merge_by_names(&merged, symlink_names, id);
3238 u->load_state = UNIT_MERGED;
3242 if (fstat(fileno(f), &st) < 0)
3245 if (null_or_empty(&st))
3246 u->load_state = UNIT_MASKED;
3248 u->load_state = UNIT_LOADED;
3250 /* Now, parse the file contents */
3251 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
3252 config_item_perf_lookup,
3253 (void*) load_fragment_gperf_lookup, false, true, u);
3258 free(u->fragment_path);
3259 u->fragment_path = filename;
3262 u->fragment_mtime = timespec_load(&st.st_mtim);
3264 if (u->source_path) {
3265 if (stat(u->source_path, &st) >= 0)
3266 u->source_mtime = timespec_load(&st.st_mtim);
3268 u->source_mtime = 0;
3274 int unit_load_fragment(Unit *u) {
3280 assert(u->load_state == UNIT_STUB);
3283 /* First, try to find the unit under its id. We always look
3284 * for unit files in the default directories, to make it easy
3285 * to override things by placing things in /etc/systemd/system */
3286 r = load_from_path(u, u->id);
3290 /* Try to find an alias we can load this with */
3291 if (u->load_state == UNIT_STUB)
3292 SET_FOREACH(t, u->names, i) {
3297 r = load_from_path(u, t);
3301 if (u->load_state != UNIT_STUB)
3305 /* And now, try looking for it under the suggested (originally linked) path */
3306 if (u->load_state == UNIT_STUB && u->fragment_path) {
3308 r = load_from_path(u, u->fragment_path);
3312 if (u->load_state == UNIT_STUB) {
3313 /* Hmm, this didn't work? Then let's get rid
3314 * of the fragment path stored for us, so that
3315 * we don't point to an invalid location. */
3316 free(u->fragment_path);
3317 u->fragment_path = NULL;
3321 /* Look for a template */
3322 if (u->load_state == UNIT_STUB && u->instance) {
3323 _cleanup_free_ char *k;
3325 k = unit_name_template(u->id);
3329 r = load_from_path(u, k);
3333 if (u->load_state == UNIT_STUB)
3334 SET_FOREACH(t, u->names, i) {
3335 _cleanup_free_ char *z = NULL;
3340 z = unit_name_template(t);
3344 r = load_from_path(u, z);
3348 if (u->load_state != UNIT_STUB)
3356 void unit_dump_config_items(FILE *f) {
3357 static const struct {
3358 const ConfigParserCallback callback;
3361 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3362 { config_parse_warn_compat, "NOTSUPPORTED" },
3364 { config_parse_int, "INTEGER" },
3365 { config_parse_unsigned, "UNSIGNED" },
3366 { config_parse_iec_size, "SIZE" },
3367 { config_parse_iec_off, "SIZE" },
3368 { config_parse_si_size, "SIZE" },
3369 { config_parse_bool, "BOOLEAN" },
3370 { config_parse_string, "STRING" },
3371 { config_parse_path, "PATH" },
3372 { config_parse_unit_path_printf, "PATH" },
3373 { config_parse_strv, "STRING [...]" },
3374 { config_parse_exec_nice, "NICE" },
3375 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3376 { config_parse_exec_io_class, "IOCLASS" },
3377 { config_parse_exec_io_priority, "IOPRIORITY" },
3378 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3379 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3380 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3381 { config_parse_mode, "MODE" },
3382 { config_parse_unit_env_file, "FILE" },
3383 { config_parse_output, "OUTPUT" },
3384 { config_parse_input, "INPUT" },
3385 { config_parse_log_facility, "FACILITY" },
3386 { config_parse_log_level, "LEVEL" },
3387 { config_parse_exec_capabilities, "CAPABILITIES" },
3388 { config_parse_exec_secure_bits, "SECUREBITS" },
3389 { config_parse_bounding_set, "BOUNDINGSET" },
3390 { config_parse_limit, "LIMIT" },
3391 { config_parse_unit_deps, "UNIT [...]" },
3392 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3393 { config_parse_service_type, "SERVICETYPE" },
3394 { config_parse_service_restart, "SERVICERESTART" },
3395 #ifdef HAVE_SYSV_COMPAT
3396 { config_parse_sysv_priority, "SYSVPRIORITY" },
3398 { config_parse_kill_mode, "KILLMODE" },
3399 { config_parse_kill_signal, "SIGNAL" },
3400 { config_parse_socket_listen, "SOCKET [...]" },
3401 { config_parse_socket_bind, "SOCKETBIND" },
3402 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3403 { config_parse_sec, "SECONDS" },
3404 { config_parse_nsec, "NANOSECONDS" },
3405 { config_parse_namespace_path_strv, "PATH [...]" },
3406 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3407 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3408 { config_parse_unit_string_printf, "STRING" },
3409 { config_parse_trigger_unit, "UNIT" },
3410 { config_parse_timer, "TIMER" },
3411 { config_parse_path_spec, "PATH" },
3412 { config_parse_notify_access, "ACCESS" },
3413 { config_parse_ip_tos, "TOS" },
3414 { config_parse_unit_condition_path, "CONDITION" },
3415 { config_parse_unit_condition_string, "CONDITION" },
3416 { config_parse_unit_condition_null, "CONDITION" },
3417 { config_parse_unit_slice, "SLICE" },
3418 { config_parse_documentation, "URL" },
3419 { config_parse_service_timeout, "SECONDS" },
3420 { config_parse_failure_action, "ACTION" },
3421 { config_parse_set_status, "STATUS" },
3422 { config_parse_service_sockets, "SOCKETS" },
3423 { config_parse_environ, "ENVIRON" },
3425 { config_parse_syscall_filter, "SYSCALLS" },
3426 { config_parse_syscall_archs, "ARCHS" },
3427 { config_parse_syscall_errno, "ERRNO" },
3428 { config_parse_address_families, "FAMILIES" },
3430 { config_parse_cpu_shares, "SHARES" },
3431 { config_parse_memory_limit, "LIMIT" },
3432 { config_parse_device_allow, "DEVICE" },
3433 { config_parse_device_policy, "POLICY" },
3434 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3435 { config_parse_blockio_weight, "WEIGHT" },
3436 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3437 { config_parse_long, "LONG" },
3438 { config_parse_socket_service, "SERVICE" },
3440 { config_parse_exec_selinux_context, "LABEL" },
3442 { config_parse_job_mode, "MODE" },
3443 { config_parse_job_mode_isolate, "BOOLEAN" },
3444 { config_parse_personality, "PERSONALITY" },
3447 const char *prev = NULL;
3452 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3453 const char *rvalue = "OTHER", *lvalue;
3457 const ConfigPerfItem *p;
3459 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3461 dot = strchr(i, '.');
3462 lvalue = dot ? dot + 1 : i;
3466 if (!prev || !strneq(prev, i, prefix_len+1)) {
3470 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3473 for (j = 0; j < ELEMENTSOF(table); j++)
3474 if (p->parse == table[j].callback) {
3475 rvalue = table[j].rvalue;
3479 fprintf(f, "%s=%s\n", lvalue, rvalue);