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 CGroupContext *c = data;
2441 if (isempty(rvalue)) {
2442 c->cpu_shares = 1024;
2446 r = safe_atolu(rvalue, &lu);
2447 if (r < 0 || lu <= 0) {
2448 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2449 "CPU shares '%s' invalid. Ignoring.", rvalue);
2457 int config_parse_cpu_quota(
2459 const char *filename,
2461 const char *section,
2462 unsigned section_line,
2469 CGroupContext *c = data;
2476 if (isempty(rvalue)) {
2477 c->cpu_quota_per_sec_usec = (usec_t) -1;
2478 c->cpu_quota_usec = (usec_t) -1;
2482 if (endswith(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);
2491 c->cpu_quota_usec = (usec_t) -1;
2493 r = parse_sec(rvalue, &c->cpu_quota_usec);
2495 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' invalid. Ignoring.", rvalue);
2499 c->cpu_quota_per_sec_usec = (usec_t) -1;
2505 int config_parse_memory_limit(
2507 const char *filename,
2509 const char *section,
2510 unsigned section_line,
2517 CGroupContext *c = data;
2521 if (isempty(rvalue)) {
2522 c->memory_limit = (uint64_t) -1;
2526 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2528 r = parse_size(rvalue, 1024, &bytes);
2530 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
2534 c->memory_limit = (uint64_t) bytes;
2538 int config_parse_device_allow(
2540 const char *filename,
2542 const char *section,
2543 unsigned section_line,
2550 _cleanup_free_ char *path = NULL;
2551 CGroupContext *c = data;
2552 CGroupDeviceAllow *a;
2556 if (isempty(rvalue)) {
2557 while (c->device_allow)
2558 cgroup_context_free_device_allow(c, c->device_allow);
2563 n = strcspn(rvalue, WHITESPACE);
2564 path = strndup(rvalue, n);
2568 if (!startswith(path, "/dev/") &&
2569 !startswith(path, "block-") &&
2570 !startswith(path, "char-")) {
2571 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2575 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2579 if (!in_charset(m, "rwm")) {
2580 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
2584 a = new0(CGroupDeviceAllow, 1);
2590 a->r = !!strchr(m, 'r');
2591 a->w = !!strchr(m, 'w');
2592 a->m = !!strchr(m, 'm');
2594 LIST_PREPEND(device_allow, c->device_allow, a);
2598 int config_parse_blockio_weight(
2600 const char *filename,
2602 const char *section,
2603 unsigned section_line,
2610 CGroupContext *c = data;
2618 if (isempty(rvalue)) {
2619 c->blockio_weight = 1000;
2623 r = safe_atolu(rvalue, &lu);
2624 if (r < 0 || lu < 10 || lu > 1000) {
2625 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2626 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2630 c->blockio_weight = lu;
2635 int config_parse_blockio_device_weight(
2637 const char *filename,
2639 const char *section,
2640 unsigned section_line,
2647 _cleanup_free_ char *path = NULL;
2648 CGroupBlockIODeviceWeight *w;
2649 CGroupContext *c = data;
2659 if (isempty(rvalue)) {
2660 while (c->blockio_device_weights)
2661 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2666 n = strcspn(rvalue, WHITESPACE);
2667 weight = rvalue + n;
2669 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2670 "Expected block device and device weight. Ignoring.");
2674 path = strndup(rvalue, n);
2678 if (!path_startswith(path, "/dev")) {
2679 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2680 "Invalid device node path '%s'. Ignoring.", path);
2684 weight += strspn(weight, WHITESPACE);
2685 r = safe_atolu(weight, &lu);
2686 if (r < 0 || lu < 10 || lu > 1000) {
2687 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2688 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2693 w = new0(CGroupBlockIODeviceWeight, 1);
2702 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2706 int config_parse_blockio_bandwidth(
2708 const char *filename,
2710 const char *section,
2711 unsigned section_line,
2718 _cleanup_free_ char *path = NULL;
2719 CGroupBlockIODeviceBandwidth *b;
2720 CGroupContext *c = data;
2721 const char *bandwidth;
2731 read = streq("BlockIOReadBandwidth", lvalue);
2733 if (isempty(rvalue)) {
2734 CGroupBlockIODeviceBandwidth *next;
2736 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2737 if (b->read == read)
2738 cgroup_context_free_blockio_device_bandwidth(c, b);
2743 n = strcspn(rvalue, WHITESPACE);
2744 bandwidth = rvalue + n;
2745 bandwidth += strspn(bandwidth, WHITESPACE);
2748 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2749 "Expected space separated pair of device node and bandwidth. Ignoring.");
2753 path = strndup(rvalue, n);
2757 if (!path_startswith(path, "/dev")) {
2758 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2759 "Invalid device node path '%s'. Ignoring.", path);
2763 r = parse_size(bandwidth, 1000, &bytes);
2764 if (r < 0 || bytes <= 0) {
2765 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2769 b = new0(CGroupBlockIODeviceBandwidth, 1);
2775 b->bandwidth = (uint64_t) bytes;
2778 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2783 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2785 int config_parse_job_mode_isolate(
2787 const char *filename,
2789 const char *section,
2790 unsigned section_line,
2804 r = parse_boolean(rvalue);
2806 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2810 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2814 int config_parse_personality(
2816 const char *filename,
2818 const char *section,
2819 unsigned section_line,
2826 unsigned long *personality = data, p;
2831 assert(personality);
2833 p = personality_from_string(rvalue);
2834 if (p == 0xffffffffUL) {
2835 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2836 "Failed to parse personality, ignoring: %s", rvalue);
2844 int config_parse_runtime_directory(
2846 const char *filename,
2848 const char *section,
2849 unsigned section_line,
2856 char***rt = data, *w, *state;
2865 if (isempty(rvalue)) {
2866 /* Empty assignment resets the list */
2872 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2873 _cleanup_free_ char *n;
2879 if (!filename_is_safe(n)) {
2880 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2884 r = strv_push(rt, n);
2894 int config_parse_set_status(
2896 const char *filename,
2898 const char *section,
2899 unsigned section_line,
2910 ExitStatusSet *status_set = data;
2917 if (isempty(rvalue)) {
2918 /* Empty assignment resets the list */
2920 set_free(status_set->signal);
2921 set_free(status_set->code);
2923 status_set->signal = status_set->code = NULL;
2927 FOREACH_WORD(w, l, rvalue, state) {
2928 _cleanup_free_ char *temp;
2931 temp = strndup(w, l);
2935 r = safe_atoi(temp, &val);
2937 val = signal_from_string_try_harder(temp);
2940 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
2944 r = set_put(status_set->signal, INT_TO_PTR(val));
2946 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2950 log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", w);
2954 if (val < 0 || val > 255)
2955 log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
2957 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
2961 r = set_put(status_set->code, INT_TO_PTR(val));
2963 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2973 int config_parse_namespace_path_strv(
2975 const char *filename,
2977 const char *section,
2978 unsigned section_line,
2985 char*** sv = data, *w, *state;
2994 if (isempty(rvalue)) {
2995 /* Empty assignment resets the list */
3001 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
3002 _cleanup_free_ char *n;
3009 if (!utf8_is_valid(n)) {
3010 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3014 offset = n[0] == '-';
3015 if (!path_is_absolute(n + offset)) {
3016 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
3020 path_kill_slashes(n);
3022 r = strv_push(sv, n);
3032 int config_parse_no_new_priviliges(
3034 const char *filename,
3036 const char *section,
3037 unsigned section_line,
3044 ExecContext *c = data;
3052 k = parse_boolean(rvalue);
3054 log_syntax(unit, LOG_ERR, filename, line, -k, "Failed to parse boolean value, ignoring: %s", rvalue);
3058 c->no_new_privileges = !!k;
3059 c->no_new_privileges_set = true;
3064 #define FOLLOW_MAX 8
3066 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3077 /* This will update the filename pointer if the loaded file is
3078 * reached by a symlink. The old string will be freed. */
3081 char *target, *name;
3083 if (c++ >= FOLLOW_MAX)
3086 path_kill_slashes(*filename);
3088 /* Add the file name we are currently looking at to
3089 * the names of this unit, but only if it is a valid
3091 name = basename(*filename);
3093 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3095 id = set_get(names, name);
3101 r = set_consume(names, id);
3107 /* Try to open the file name, but don't if its a symlink */
3108 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3115 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3116 r = readlink_and_make_absolute(*filename, &target);
3124 f = fdopen(fd, "re");
3136 static int merge_by_names(Unit **u, Set *names, const char *id) {
3144 /* Let's try to add in all symlink names we found */
3145 while ((k = set_steal_first(names))) {
3147 /* First try to merge in the other name into our
3149 r = unit_merge_by_name(*u, k);
3153 /* Hmm, we couldn't merge the other unit into
3154 * ours? Then let's try it the other way
3157 other = manager_get_unit((*u)->manager, k);
3161 r = unit_merge(other, *u);
3164 return merge_by_names(u, names, NULL);
3172 unit_choose_id(*u, id);
3180 static int load_from_path(Unit *u, const char *path) {
3182 _cleanup_set_free_free_ Set *symlink_names = NULL;
3183 _cleanup_fclose_ FILE *f = NULL;
3184 _cleanup_free_ char *filename = NULL;
3192 symlink_names = set_new(string_hash_func, string_compare_func);
3196 if (path_is_absolute(path)) {
3198 filename = strdup(path);
3202 r = open_follow(&filename, &f, symlink_names, &id);
3214 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3216 /* Instead of opening the path right away, we manually
3217 * follow all symlinks and add their name to our unit
3218 * name set while doing so */
3219 filename = path_make_absolute(path, *p);
3223 if (u->manager->unit_path_cache &&
3224 !set_get(u->manager->unit_path_cache, filename))
3227 r = open_follow(&filename, &f, symlink_names, &id);
3236 /* Empty the symlink names for the next run */
3237 set_clear_free(symlink_names);
3246 /* Hmm, no suitable file found? */
3250 r = merge_by_names(&merged, symlink_names, id);
3255 u->load_state = UNIT_MERGED;
3259 if (fstat(fileno(f), &st) < 0)
3262 if (null_or_empty(&st))
3263 u->load_state = UNIT_MASKED;
3265 u->load_state = UNIT_LOADED;
3267 /* Now, parse the file contents */
3268 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
3269 config_item_perf_lookup,
3270 (void*) load_fragment_gperf_lookup, false, true, u);
3275 free(u->fragment_path);
3276 u->fragment_path = filename;
3279 u->fragment_mtime = timespec_load(&st.st_mtim);
3281 if (u->source_path) {
3282 if (stat(u->source_path, &st) >= 0)
3283 u->source_mtime = timespec_load(&st.st_mtim);
3285 u->source_mtime = 0;
3291 int unit_load_fragment(Unit *u) {
3297 assert(u->load_state == UNIT_STUB);
3300 /* First, try to find the unit under its id. We always look
3301 * for unit files in the default directories, to make it easy
3302 * to override things by placing things in /etc/systemd/system */
3303 r = load_from_path(u, u->id);
3307 /* Try to find an alias we can load this with */
3308 if (u->load_state == UNIT_STUB)
3309 SET_FOREACH(t, u->names, i) {
3314 r = load_from_path(u, t);
3318 if (u->load_state != UNIT_STUB)
3322 /* And now, try looking for it under the suggested (originally linked) path */
3323 if (u->load_state == UNIT_STUB && u->fragment_path) {
3325 r = load_from_path(u, u->fragment_path);
3329 if (u->load_state == UNIT_STUB) {
3330 /* Hmm, this didn't work? Then let's get rid
3331 * of the fragment path stored for us, so that
3332 * we don't point to an invalid location. */
3333 free(u->fragment_path);
3334 u->fragment_path = NULL;
3338 /* Look for a template */
3339 if (u->load_state == UNIT_STUB && u->instance) {
3340 _cleanup_free_ char *k;
3342 k = unit_name_template(u->id);
3346 r = load_from_path(u, k);
3350 if (u->load_state == UNIT_STUB)
3351 SET_FOREACH(t, u->names, i) {
3352 _cleanup_free_ char *z = NULL;
3357 z = unit_name_template(t);
3361 r = load_from_path(u, z);
3365 if (u->load_state != UNIT_STUB)
3373 void unit_dump_config_items(FILE *f) {
3374 static const struct {
3375 const ConfigParserCallback callback;
3378 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3379 { config_parse_warn_compat, "NOTSUPPORTED" },
3381 { config_parse_int, "INTEGER" },
3382 { config_parse_unsigned, "UNSIGNED" },
3383 { config_parse_iec_size, "SIZE" },
3384 { config_parse_iec_off, "SIZE" },
3385 { config_parse_si_size, "SIZE" },
3386 { config_parse_bool, "BOOLEAN" },
3387 { config_parse_string, "STRING" },
3388 { config_parse_path, "PATH" },
3389 { config_parse_unit_path_printf, "PATH" },
3390 { config_parse_strv, "STRING [...]" },
3391 { config_parse_exec_nice, "NICE" },
3392 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3393 { config_parse_exec_io_class, "IOCLASS" },
3394 { config_parse_exec_io_priority, "IOPRIORITY" },
3395 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3396 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3397 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3398 { config_parse_mode, "MODE" },
3399 { config_parse_unit_env_file, "FILE" },
3400 { config_parse_output, "OUTPUT" },
3401 { config_parse_input, "INPUT" },
3402 { config_parse_log_facility, "FACILITY" },
3403 { config_parse_log_level, "LEVEL" },
3404 { config_parse_exec_capabilities, "CAPABILITIES" },
3405 { config_parse_exec_secure_bits, "SECUREBITS" },
3406 { config_parse_bounding_set, "BOUNDINGSET" },
3407 { config_parse_limit, "LIMIT" },
3408 { config_parse_unit_deps, "UNIT [...]" },
3409 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3410 { config_parse_service_type, "SERVICETYPE" },
3411 { config_parse_service_restart, "SERVICERESTART" },
3412 #ifdef HAVE_SYSV_COMPAT
3413 { config_parse_sysv_priority, "SYSVPRIORITY" },
3415 { config_parse_kill_mode, "KILLMODE" },
3416 { config_parse_kill_signal, "SIGNAL" },
3417 { config_parse_socket_listen, "SOCKET [...]" },
3418 { config_parse_socket_bind, "SOCKETBIND" },
3419 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3420 { config_parse_sec, "SECONDS" },
3421 { config_parse_nsec, "NANOSECONDS" },
3422 { config_parse_namespace_path_strv, "PATH [...]" },
3423 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3424 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3425 { config_parse_unit_string_printf, "STRING" },
3426 { config_parse_trigger_unit, "UNIT" },
3427 { config_parse_timer, "TIMER" },
3428 { config_parse_path_spec, "PATH" },
3429 { config_parse_notify_access, "ACCESS" },
3430 { config_parse_ip_tos, "TOS" },
3431 { config_parse_unit_condition_path, "CONDITION" },
3432 { config_parse_unit_condition_string, "CONDITION" },
3433 { config_parse_unit_condition_null, "CONDITION" },
3434 { config_parse_unit_slice, "SLICE" },
3435 { config_parse_documentation, "URL" },
3436 { config_parse_service_timeout, "SECONDS" },
3437 { config_parse_failure_action, "ACTION" },
3438 { config_parse_set_status, "STATUS" },
3439 { config_parse_service_sockets, "SOCKETS" },
3440 { config_parse_environ, "ENVIRON" },
3442 { config_parse_syscall_filter, "SYSCALLS" },
3443 { config_parse_syscall_archs, "ARCHS" },
3444 { config_parse_syscall_errno, "ERRNO" },
3445 { config_parse_address_families, "FAMILIES" },
3447 { config_parse_cpu_shares, "SHARES" },
3448 { config_parse_memory_limit, "LIMIT" },
3449 { config_parse_device_allow, "DEVICE" },
3450 { config_parse_device_policy, "POLICY" },
3451 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3452 { config_parse_blockio_weight, "WEIGHT" },
3453 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3454 { config_parse_long, "LONG" },
3455 { config_parse_socket_service, "SERVICE" },
3457 { config_parse_exec_selinux_context, "LABEL" },
3459 { config_parse_job_mode, "MODE" },
3460 { config_parse_job_mode_isolate, "BOOLEAN" },
3461 { config_parse_personality, "PERSONALITY" },
3464 const char *prev = NULL;
3469 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3470 const char *rvalue = "OTHER", *lvalue;
3474 const ConfigPerfItem *p;
3476 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3478 dot = strchr(i, '.');
3479 lvalue = dot ? dot + 1 : i;
3483 if (!prev || !strneq(prev, i, prefix_len+1)) {
3487 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3490 for (j = 0; j < ELEMENTSOF(table); j++)
3491 if (p->parse == table[j].callback) {
3492 rvalue = table[j].rvalue;
3496 fprintf(f, "%s=%s\n", lvalue, rvalue);