1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
7 Copyright 2012 Holger Hans Peter Freyther
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <linux/oom.h>
30 #include <sys/prctl.h>
31 #include <sys/mount.h>
35 #include <sys/resource.h>
36 #include <sys/types.h>
43 #include "sd-messages.h"
46 #include "conf-parser.h"
47 #include "load-fragment.h"
50 #include "securebits.h"
52 #include "unit-name.h"
53 #include "unit-printf.h"
55 #include "path-util.h"
59 #include "bus-error.h"
60 #include "errno-list.h"
64 #include "seccomp-util.h"
67 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
68 int config_parse_warn_compat(
73 unsigned section_line,
80 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
81 "Support for option %s= has been disabled at compile time and is ignored",
87 int config_parse_unit_deps(const char* unit,
91 unsigned section_line,
98 UnitDependency d = ltype;
100 const char *word, *state;
107 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
108 _cleanup_free_ char *t = NULL, *k = NULL;
111 t = strndup(word, l);
115 r = unit_name_printf(u, t, &k);
117 log_syntax(unit, LOG_ERR, filename, line, -r,
118 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
122 r = unit_add_dependency_by_name(u, d, k, NULL, true);
124 log_syntax(unit, LOG_ERR, filename, line, -r,
125 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
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,
200 _cleanup_free_ char *k = NULL;
209 r = unit_full_printf(u, rvalue, &k);
211 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
215 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
218 int config_parse_unit_path_strv_printf(
220 const char *filename,
223 unsigned section_line,
231 const char *word, *state;
241 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
242 _cleanup_free_ char *k = NULL;
248 r = unit_full_printf(u, t, &k);
250 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
254 if (!utf8_is_valid(k)) {
255 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
259 if (!path_is_absolute(k)) {
260 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
264 path_kill_slashes(k);
276 int config_parse_socket_listen(const char *unit,
277 const char *filename,
280 unsigned section_line,
287 SocketPort *p, *tail;
298 if (isempty(rvalue)) {
299 /* An empty assignment removes all ports */
300 socket_free_ports(s);
304 p = new0(SocketPort, 1);
308 if (ltype != SOCKET_SOCKET) {
311 r = unit_full_printf(UNIT(s), rvalue, &p->path);
313 p->path = strdup(rvalue);
318 log_syntax(unit, LOG_ERR, filename, line, -r,
319 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
322 path_kill_slashes(p->path);
324 } else if (streq(lvalue, "ListenNetlink")) {
325 _cleanup_free_ char *k = NULL;
327 p->type = SOCKET_SOCKET;
328 r = unit_full_printf(UNIT(s), rvalue, &k);
330 log_syntax(unit, LOG_ERR, filename, line, -r,
331 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
333 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
335 log_syntax(unit, LOG_ERR, filename, line, -r,
336 "Failed to parse address value, ignoring: %s", rvalue);
342 _cleanup_free_ char *k = NULL;
344 p->type = SOCKET_SOCKET;
345 r = unit_full_printf(UNIT(s), rvalue, &k);
347 log_syntax(unit, LOG_ERR, filename, line, -r,
348 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
350 r = socket_address_parse(&p->address, k ? k : rvalue);
352 log_syntax(unit, LOG_ERR, filename, line, -r,
353 "Failed to parse address value, ignoring: %s", rvalue);
358 if (streq(lvalue, "ListenStream"))
359 p->address.type = SOCK_STREAM;
360 else if (streq(lvalue, "ListenDatagram"))
361 p->address.type = SOCK_DGRAM;
363 assert(streq(lvalue, "ListenSequentialPacket"));
364 p->address.type = SOCK_SEQPACKET;
367 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
368 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
369 "Address family not supported, ignoring: %s", rvalue);
379 LIST_FIND_TAIL(port, s->ports, tail);
380 LIST_INSERT_AFTER(port, s->ports, tail, p);
382 LIST_PREPEND(port, s->ports, p);
387 int config_parse_socket_bind(const char *unit,
388 const char *filename,
391 unsigned section_line,
399 SocketAddressBindIPv6Only b;
408 b = socket_address_bind_ipv6_only_from_string(rvalue);
412 r = parse_boolean(rvalue);
414 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
415 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
419 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
421 s->bind_ipv6_only = b;
426 int config_parse_exec_nice(const char *unit,
427 const char *filename,
430 unsigned section_line,
437 ExecContext *c = data;
445 r = safe_atoi(rvalue, &priority);
447 log_syntax(unit, LOG_ERR, filename, line, -r,
448 "Failed to parse nice priority, ignoring: %s. ", rvalue);
452 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
453 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
454 "Nice priority out of range, ignoring: %s", rvalue);
464 int config_parse_exec_oom_score_adjust(const char* unit,
465 const char *filename,
468 unsigned section_line,
475 ExecContext *c = data;
483 r = safe_atoi(rvalue, &oa);
485 log_syntax(unit, LOG_ERR, filename, line, -r,
486 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
490 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
491 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
492 "OOM score adjust value out of range, ignoring: %s", rvalue);
496 c->oom_score_adjust = oa;
497 c->oom_score_adjust_set = true;
502 int config_parse_exec(const char *unit,
503 const char *filename,
506 unsigned section_line,
513 ExecCommand **e = data, *nce;
525 if (isempty(rvalue)) {
526 /* An empty assignment resets the list */
527 exec_command_free_list(*e);
532 /* We accept an absolute path as first argument, or
533 * alternatively an absolute prefixed with @ to allow
534 * overriding of argv[0]. */
537 const char *word, *state;
539 bool honour_argv0 = false, ignore = false;
545 rvalue += strspn(rvalue, WHITESPACE);
550 for (i = 0; i < 2; i++) {
551 if (rvalue[0] == '-' && !ignore) {
556 if (rvalue[0] == '@' && !honour_argv0) {
562 if (*rvalue != '/') {
563 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
564 "Executable path is not absolute, ignoring: %s", rvalue);
569 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
570 if (strneq(word, ";", MAX(l, 1U)))
576 n = new(char*, k + !honour_argv0);
581 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
582 if (strneq(word, ";", MAX(l, 1U)))
584 else if (strneq(word, "\\;", MAX(l, 1U)))
587 if (honour_argv0 && word == rvalue) {
590 path = strndup(word, l);
596 if (!utf8_is_valid(path)) {
597 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
605 c = n[k++] = cunescape_length(word, l);
611 if (!utf8_is_valid(c)) {
612 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
622 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
623 "Invalid command line, ignoring: %s", rvalue);
636 assert(path_is_absolute(path));
638 nce = new0(ExecCommand, 1);
646 nce->ignore = ignore;
648 path_kill_slashes(nce->path);
650 exec_command_append_list(e, nce);
666 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
667 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
669 int config_parse_socket_bindtodevice(const char* unit,
670 const char *filename,
673 unsigned section_line,
688 if (rvalue[0] && !streq(rvalue, "*")) {
695 free(s->bind_to_device);
696 s->bind_to_device = n;
701 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
702 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
704 int config_parse_exec_io_class(const char *unit,
705 const char *filename,
708 unsigned section_line,
715 ExecContext *c = data;
723 x = ioprio_class_from_string(rvalue);
725 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
726 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
730 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
731 c->ioprio_set = true;
736 int config_parse_exec_io_priority(const char *unit,
737 const char *filename,
740 unsigned section_line,
747 ExecContext *c = data;
755 r = safe_atoi(rvalue, &i);
756 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
757 log_syntax(unit, LOG_ERR, filename, line, -r,
758 "Failed to parse IO priority, ignoring: %s", rvalue);
762 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
763 c->ioprio_set = true;
768 int config_parse_exec_cpu_sched_policy(const char *unit,
769 const char *filename,
772 unsigned section_line,
780 ExecContext *c = data;
788 x = sched_policy_from_string(rvalue);
790 log_syntax(unit, LOG_ERR, filename, line, -x,
791 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
795 c->cpu_sched_policy = x;
796 /* Moving to or from real-time policy? We need to adjust the priority */
797 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
798 c->cpu_sched_set = true;
803 int config_parse_exec_cpu_sched_prio(const char *unit,
804 const char *filename,
807 unsigned section_line,
814 ExecContext *c = data;
822 r = safe_atoi(rvalue, &i);
824 log_syntax(unit, LOG_ERR, filename, line, -r,
825 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
829 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
830 min = sched_get_priority_min(c->cpu_sched_policy);
831 max = sched_get_priority_max(c->cpu_sched_policy);
833 if (i < min || i > max) {
834 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
835 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
839 c->cpu_sched_priority = i;
840 c->cpu_sched_set = true;
845 int config_parse_exec_cpu_affinity(const char *unit,
846 const char *filename,
849 unsigned section_line,
856 ExecContext *c = data;
857 const char *word, *state;
865 if (isempty(rvalue)) {
866 /* An empty assignment resets the CPU list */
873 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
874 _cleanup_free_ char *t = NULL;
878 t = strndup(word, l);
882 r = safe_atou(t, &cpu);
885 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
890 if (r < 0 || cpu >= c->cpuset_ncpus) {
891 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
892 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
896 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
902 int config_parse_exec_capabilities(const char *unit,
903 const char *filename,
906 unsigned section_line,
913 ExecContext *c = data;
921 cap = cap_from_text(rvalue);
923 log_syntax(unit, LOG_ERR, filename, line, errno,
924 "Failed to parse capabilities, ignoring: %s", rvalue);
929 cap_free(c->capabilities);
930 c->capabilities = cap;
935 int config_parse_exec_secure_bits(const char *unit,
936 const char *filename,
939 unsigned section_line,
946 ExecContext *c = data;
948 const char *word, *state;
955 if (isempty(rvalue)) {
956 /* An empty assignment resets the field */
961 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
962 if (first_word(word, "keep-caps"))
963 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
964 else if (first_word(word, "keep-caps-locked"))
965 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
966 else if (first_word(word, "no-setuid-fixup"))
967 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
968 else if (first_word(word, "no-setuid-fixup-locked"))
969 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
970 else if (first_word(word, "noroot"))
971 c->secure_bits |= 1<<SECURE_NOROOT;
972 else if (first_word(word, "noroot-locked"))
973 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
975 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
976 "Failed to parse secure bits, ignoring: %s", rvalue);
984 int config_parse_bounding_set(const char *unit,
985 const char *filename,
988 unsigned section_line,
995 uint64_t *capability_bounding_set_drop = data;
996 const char *word, *state;
1006 if (rvalue[0] == '~') {
1011 /* Note that we store this inverted internally, since the
1012 * kernel wants it like this. But we actually expose it
1013 * non-inverted everywhere to have a fully normalized
1016 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1017 _cleanup_free_ char *t = NULL;
1021 t = strndup(word, l);
1025 r = cap_from_name(t, &cap);
1027 log_syntax(unit, LOG_ERR, filename, line, errno,
1028 "Failed to parse capability in bounding set, ignoring: %s", t);
1032 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1036 *capability_bounding_set_drop |= sum;
1038 *capability_bounding_set_drop |= ~sum;
1043 int config_parse_limit(const char *unit,
1044 const char *filename,
1046 const char *section,
1047 unsigned section_line,
1054 struct rlimit **rl = data;
1055 unsigned long long u;
1064 if (streq(rvalue, "infinity"))
1065 u = (unsigned long long) RLIM_INFINITY;
1069 r = safe_atollu(rvalue, &u);
1071 log_syntax(unit, LOG_ERR, filename, line, -r,
1072 "Failed to parse resource value, ignoring: %s", rvalue);
1078 *rl = new(struct rlimit, 1);
1083 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1087 #ifdef HAVE_SYSV_COMPAT
1088 int config_parse_sysv_priority(const char *unit,
1089 const char *filename,
1091 const char *section,
1092 unsigned section_line,
1099 int *priority = data;
1107 r = safe_atoi(rvalue, &i);
1108 if (r < 0 || i < 0) {
1109 log_syntax(unit, LOG_ERR, filename, line, -r,
1110 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1114 *priority = (int) i;
1119 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1121 int config_parse_kill_signal(const char *unit,
1122 const char *filename,
1124 const char *section,
1125 unsigned section_line,
1140 r = signal_from_string_try_harder(rvalue);
1142 log_syntax(unit, LOG_ERR, filename, line, -r,
1143 "Failed to parse kill signal, ignoring: %s", rvalue);
1151 int config_parse_exec_mount_flags(const char *unit,
1152 const char *filename,
1154 const char *section,
1155 unsigned section_line,
1162 ExecContext *c = data;
1163 const char *word, *state;
1165 unsigned long flags = 0;
1172 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1173 _cleanup_free_ char *t;
1175 t = strndup(word, l);
1179 if (streq(t, "shared"))
1181 else if (streq(t, "slave"))
1183 else if (streq(word, "private"))
1186 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1191 c->mount_flags = flags;
1195 int config_parse_exec_selinux_context(
1197 const char *filename,
1199 const char *section,
1200 unsigned section_line,
1207 ExecContext *c = data;
1218 if (isempty(rvalue)) {
1219 free(c->selinux_context);
1220 c->selinux_context = NULL;
1221 c->selinux_context_ignore = false;
1225 if (rvalue[0] == '-') {
1231 r = unit_name_printf(u, rvalue, &k);
1233 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1237 free(c->selinux_context);
1238 c->selinux_context = k;
1239 c->selinux_context_ignore = ignore;
1244 int config_parse_exec_apparmor_profile(
1246 const char *filename,
1248 const char *section,
1249 unsigned section_line,
1256 ExecContext *c = data;
1267 if (isempty(rvalue)) {
1268 free(c->apparmor_profile);
1269 c->apparmor_profile = NULL;
1270 c->apparmor_profile_ignore = false;
1274 if (rvalue[0] == '-') {
1280 r = unit_name_printf(u, rvalue, &k);
1282 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1286 free(c->apparmor_profile);
1287 c->apparmor_profile = k;
1288 c->apparmor_profile_ignore = ignore;
1293 int config_parse_timer(const char *unit,
1294 const char *filename,
1296 const char *section,
1297 unsigned section_line,
1308 CalendarSpec *c = NULL;
1315 if (isempty(rvalue)) {
1316 /* Empty assignment resets list */
1317 timer_free_values(t);
1321 b = timer_base_from_string(lvalue);
1323 log_syntax(unit, LOG_ERR, filename, line, -b,
1324 "Failed to parse timer base, ignoring: %s", lvalue);
1328 if (b == TIMER_CALENDAR) {
1329 if (calendar_spec_from_string(rvalue, &c) < 0) {
1330 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1331 "Failed to parse calendar specification, ignoring: %s",
1336 if (parse_sec(rvalue, &u) < 0) {
1337 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1338 "Failed to parse timer value, ignoring: %s",
1344 v = new0(TimerValue, 1);
1350 v->calendar_spec = c;
1352 LIST_PREPEND(value, t->values, v);
1357 int config_parse_trigger_unit(
1359 const char *filename,
1361 const char *section,
1362 unsigned section_line,
1369 _cleanup_free_ char *p = NULL;
1379 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1380 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1381 "Multiple units to trigger specified, ignoring: %s", rvalue);
1385 r = unit_name_printf(u, rvalue, &p);
1387 log_syntax(unit, LOG_ERR, filename, line, -r,
1388 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1390 type = unit_name_to_type(p ?: rvalue);
1392 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1393 "Unit type not valid, ignoring: %s", rvalue);
1397 if (type == u->type) {
1398 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1399 "Trigger cannot be of same type, ignoring: %s", rvalue);
1403 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1405 log_syntax(unit, LOG_ERR, filename, line, -r,
1406 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1413 int config_parse_path_spec(const char *unit,
1414 const char *filename,
1416 const char *section,
1417 unsigned section_line,
1427 _cleanup_free_ char *k = NULL;
1435 if (isempty(rvalue)) {
1436 /* Empty assignment clears list */
1441 b = path_type_from_string(lvalue);
1443 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1444 "Failed to parse path type, ignoring: %s", lvalue);
1448 r = unit_full_printf(UNIT(p), rvalue, &k);
1454 log_syntax(unit, LOG_ERR, filename, line, -r,
1455 "Failed to resolve unit specifiers on %s. Ignoring.",
1459 if (!path_is_absolute(k)) {
1460 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1461 "Path is not absolute, ignoring: %s", k);
1465 s = new0(PathSpec, 1);
1470 s->path = path_kill_slashes(k);
1475 LIST_PREPEND(spec, p->specs, s);
1480 int config_parse_socket_service(const char *unit,
1481 const char *filename,
1483 const char *section,
1484 unsigned section_line,
1491 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1495 _cleanup_free_ char *p = NULL;
1502 r = unit_name_printf(UNIT(s), rvalue, &p);
1504 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1508 if (!endswith(p, ".service")) {
1509 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1513 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1515 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1519 unit_ref_set(&s->service, x);
1524 int config_parse_service_sockets(const char *unit,
1525 const char *filename,
1527 const char *section,
1528 unsigned section_line,
1537 const char *word, *state;
1545 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1546 _cleanup_free_ char *t = NULL, *k = NULL;
1548 t = strndup(word, l);
1552 r = unit_name_printf(UNIT(s), t, &k);
1554 log_syntax(unit, LOG_ERR, filename, line, -r,
1555 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1557 if (!endswith(k ?: t, ".socket")) {
1558 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1559 "Unit must be of type socket, ignoring: %s", k ?: t);
1563 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1565 log_syntax(unit, LOG_ERR, filename, line, -r,
1566 "Failed to add dependency on %s, ignoring: %s",
1567 k ?: t, strerror(-r));
1569 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1577 int config_parse_service_timeout(const char *unit,
1578 const char *filename,
1580 const char *section,
1581 unsigned section_line,
1588 Service *s = userdata;
1596 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1597 rvalue, data, userdata);
1601 if (streq(lvalue, "TimeoutSec")) {
1602 s->start_timeout_defined = true;
1603 s->timeout_stop_usec = s->timeout_start_usec;
1604 } else if (streq(lvalue, "TimeoutStartSec"))
1605 s->start_timeout_defined = true;
1610 int config_parse_busname_service(
1612 const char *filename,
1614 const char *section,
1615 unsigned section_line,
1622 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1626 _cleanup_free_ char *p = NULL;
1633 r = unit_name_printf(UNIT(n), rvalue, &p);
1635 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1639 if (!endswith(p, ".service")) {
1640 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1644 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1646 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1650 unit_ref_set(&n->service, x);
1655 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, busname_policy_access, BusNamePolicyAccess, "Failed to parse bus name policy access");
1657 int config_parse_bus_policy(
1659 const char *filename,
1661 const char *section,
1662 unsigned section_line,
1669 _cleanup_free_ BusNamePolicy *p = NULL;
1670 _cleanup_free_ char *id_str = NULL;
1671 BusName *busname = data;
1679 p = new0(BusNamePolicy, 1);
1683 if (streq(lvalue, "AllowUser"))
1684 p->type = BUSNAME_POLICY_TYPE_USER;
1685 else if (streq(lvalue, "AllowGroup"))
1686 p->type = BUSNAME_POLICY_TYPE_GROUP;
1688 assert_not_reached("Unknown lvalue");
1690 id_str = strdup(rvalue);
1694 access_str = strpbrk(id_str, WHITESPACE);
1696 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy value '%s'", rvalue);
1702 access_str += strspn(access_str, WHITESPACE);
1704 p->access = busname_policy_access_from_string(access_str);
1705 if (p->access < 0) {
1706 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid busname policy access type '%s'", access_str);
1713 LIST_PREPEND(policy, busname->policy, p);
1719 int config_parse_unit_env_file(const char *unit,
1720 const char *filename,
1722 const char *section,
1723 unsigned section_line,
1732 _cleanup_free_ char *n = NULL;
1741 if (isempty(rvalue)) {
1742 /* Empty assignment frees the list */
1748 r = unit_full_printf(u, rvalue, &n);
1750 log_syntax(unit, LOG_ERR, filename, line, r,
1751 "Failed to resolve specifiers, ignoring: %s", rvalue);
1754 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1755 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1756 "Path '%s' is not absolute, ignoring.", s);
1760 r = strv_extend(env, s);
1767 int config_parse_environ(const char *unit,
1768 const char *filename,
1770 const char *section,
1771 unsigned section_line,
1780 const char *word, *state;
1782 _cleanup_free_ char *k = NULL;
1790 if (isempty(rvalue)) {
1791 /* Empty assignment resets the list */
1798 r = unit_full_printf(u, rvalue, &k);
1800 log_syntax(unit, LOG_ERR, filename, line, -r,
1801 "Failed to resolve specifiers, ignoring: %s", rvalue);
1809 FOREACH_WORD_QUOTED(word, l, k, state) {
1810 _cleanup_free_ char *n;
1813 n = cunescape_length(word, l);
1817 if (!env_assignment_is_valid(n)) {
1818 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1819 "Invalid environment assignment, ignoring: %s", rvalue);
1823 x = strv_env_set(*env, n);
1834 int config_parse_ip_tos(const char *unit,
1835 const char *filename,
1837 const char *section,
1838 unsigned section_line,
1845 int *ip_tos = data, x;
1852 x = ip_tos_from_string(rvalue);
1854 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1855 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1863 int config_parse_unit_condition_path(const char *unit,
1864 const char *filename,
1866 const char *section,
1867 unsigned section_line,
1874 ConditionType cond = ltype;
1876 bool trigger, negate;
1878 _cleanup_free_ char *p = NULL;
1886 if (isempty(rvalue)) {
1887 /* Empty assignment resets the list */
1888 condition_free_list(u->conditions);
1889 u->conditions = NULL;
1893 trigger = rvalue[0] == '|';
1897 negate = rvalue[0] == '!';
1901 r = unit_full_printf(u, rvalue, &p);
1903 log_syntax(unit, LOG_ERR, filename, line, -r,
1904 "Failed to resolve specifiers, ignoring: %s", rvalue);
1911 if (!path_is_absolute(p)) {
1912 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1913 "Path in condition not absolute, ignoring: %s", p);
1917 c = condition_new(cond, p, trigger, negate);
1921 LIST_PREPEND(conditions, u->conditions, c);
1925 int config_parse_unit_condition_string(const char *unit,
1926 const char *filename,
1928 const char *section,
1929 unsigned section_line,
1936 ConditionType cond = ltype;
1938 bool trigger, negate;
1940 _cleanup_free_ char *s = NULL;
1948 if (isempty(rvalue)) {
1949 /* Empty assignment resets the list */
1950 condition_free_list(u->conditions);
1951 u->conditions = NULL;
1955 trigger = rvalue[0] == '|';
1959 negate = rvalue[0] == '!';
1963 r = unit_full_printf(u, rvalue, &s);
1965 log_syntax(unit, LOG_ERR, filename, line, -r,
1966 "Failed to resolve specifiers, ignoring: %s", rvalue);
1973 c = condition_new(cond, s, trigger, negate);
1977 LIST_PREPEND(conditions, u->conditions, c);
1981 int config_parse_unit_condition_null(const char *unit,
1982 const char *filename,
1984 const char *section,
1985 unsigned section_line,
1994 bool trigger, negate;
2002 if (isempty(rvalue)) {
2003 /* Empty assignment resets the list */
2004 condition_free_list(u->conditions);
2005 u->conditions = NULL;
2009 trigger = rvalue[0] == '|';
2013 negate = rvalue[0] == '!';
2017 b = parse_boolean(rvalue);
2019 log_syntax(unit, LOG_ERR, filename, line, -b,
2020 "Failed to parse boolean value in condition, ignoring: %s",
2028 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2032 LIST_PREPEND(conditions, u->conditions, c);
2036 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2037 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2039 int config_parse_unit_requires_mounts_for(
2041 const char *filename,
2043 const char *section,
2044 unsigned section_line,
2052 const char *word, *state;
2060 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2062 _cleanup_free_ char *n;
2064 n = strndup(word, l);
2068 if (!utf8_is_valid(n)) {
2069 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2073 r = unit_require_mounts_for(u, n);
2075 log_syntax(unit, LOG_ERR, filename, line, r,
2076 "Failed to add required mount for, ignoring: %s", rvalue);
2084 int config_parse_documentation(const char *unit,
2085 const char *filename,
2087 const char *section,
2088 unsigned section_line,
2104 if (isempty(rvalue)) {
2105 /* Empty assignment resets the list */
2106 strv_free(u->documentation);
2107 u->documentation = NULL;
2111 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2112 rvalue, data, userdata);
2116 for (a = b = u->documentation; a && *a; a++) {
2118 if (is_valid_documentation_url(*a))
2121 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2122 "Invalid URL, ignoring: %s", *a);
2133 int config_parse_syscall_filter(
2135 const char *filename,
2137 const char *section,
2138 unsigned section_line,
2145 static const char default_syscalls[] =
2152 ExecContext *c = data;
2154 bool invert = false;
2155 const char *word, *state;
2164 if (isempty(rvalue)) {
2165 /* Empty assignment resets the list */
2166 set_free(c->syscall_filter);
2167 c->syscall_filter = NULL;
2168 c->syscall_whitelist = false;
2172 if (rvalue[0] == '~') {
2177 if (!c->syscall_filter) {
2178 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2179 if (!c->syscall_filter)
2183 /* Allow everything but the ones listed */
2184 c->syscall_whitelist = false;
2188 /* Allow nothing but the ones listed */
2189 c->syscall_whitelist = true;
2191 /* Accept default syscalls if we are on a whitelist */
2192 NULSTR_FOREACH(i, default_syscalls) {
2195 id = seccomp_syscall_resolve_name(i);
2199 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2208 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2209 _cleanup_free_ char *t = NULL;
2212 t = strndup(word, l);
2216 id = seccomp_syscall_resolve_name(t);
2218 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2222 /* If we previously wanted to forbid a syscall and now
2223 * we want to allow it, then remove it from the list
2225 if (!invert == c->syscall_whitelist) {
2226 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2232 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2235 /* Turn on NNP, but only if it wasn't configured explicitly
2236 * before, and only if we are in user mode. */
2237 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2238 c->no_new_privileges = true;
2243 int config_parse_syscall_archs(
2245 const char *filename,
2247 const char *section,
2248 unsigned section_line,
2256 const char *word, *state;
2260 if (isempty(rvalue)) {
2266 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2270 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2271 _cleanup_free_ char *t = NULL;
2274 t = strndup(word, l);
2278 r = seccomp_arch_from_string(t, &a);
2280 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2284 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2294 int config_parse_syscall_errno(
2296 const char *filename,
2298 const char *section,
2299 unsigned section_line,
2306 ExecContext *c = data;
2313 if (isempty(rvalue)) {
2314 /* Empty assignment resets to KILL */
2315 c->syscall_errno = 0;
2319 e = errno_from_name(rvalue);
2321 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2325 c->syscall_errno = e;
2329 int config_parse_address_families(
2331 const char *filename,
2333 const char *section,
2334 unsigned section_line,
2341 ExecContext *c = data;
2343 bool invert = false;
2344 const char *word, *state;
2353 if (isempty(rvalue)) {
2354 /* Empty assignment resets the list */
2355 set_free(c->address_families);
2356 c->address_families = NULL;
2357 c->address_families_whitelist = false;
2361 if (rvalue[0] == '~') {
2366 if (!c->address_families) {
2367 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2368 if (!c->address_families)
2371 c->address_families_whitelist = !invert;
2374 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2375 _cleanup_free_ char *t = NULL;
2378 t = strndup(word, l);
2382 af = af_from_name(t);
2384 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
2388 /* If we previously wanted to forbid an address family and now
2389 * we want to allow it, then remove it from the list
2391 if (!invert == c->address_families_whitelist) {
2392 r = set_put(c->address_families, INT_TO_PTR(af));
2398 set_remove(c->address_families, INT_TO_PTR(af));
2405 int config_parse_unit_slice(
2407 const char *filename,
2409 const char *section,
2410 unsigned section_line,
2417 _cleanup_free_ char *k = NULL;
2418 Unit *u = userdata, *slice;
2426 r = unit_name_printf(u, rvalue, &k);
2428 log_syntax(unit, LOG_ERR, filename, line, -r,
2429 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2436 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2438 log_syntax(unit, LOG_ERR, filename, line, -r,
2439 "Failed to load slice unit %s. Ignoring.", k);
2443 if (slice->type != UNIT_SLICE) {
2444 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2445 "Slice unit %s is not a slice. Ignoring.", k);
2449 unit_ref_set(&u->slice, slice);
2453 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2455 int config_parse_cpu_shares(
2457 const char *filename,
2459 const char *section,
2460 unsigned section_line,
2467 unsigned long *shares = data, lu;
2474 if (isempty(rvalue)) {
2475 *shares = (unsigned long) -1;
2479 r = safe_atolu(rvalue, &lu);
2480 if (r < 0 || lu <= 0) {
2481 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU shares '%s' invalid. Ignoring.", rvalue);
2489 int config_parse_cpu_quota(
2491 const char *filename,
2493 const char *section,
2494 unsigned section_line,
2501 CGroupContext *c = data;
2508 if (isempty(rvalue)) {
2509 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2513 if (!endswith(rvalue, "%")) {
2515 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2519 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2520 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU quota '%s' invalid. Ignoring.", rvalue);
2524 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2529 int config_parse_memory_limit(
2531 const char *filename,
2533 const char *section,
2534 unsigned section_line,
2541 CGroupContext *c = data;
2545 if (isempty(rvalue)) {
2546 c->memory_limit = (uint64_t) -1;
2550 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2552 r = parse_size(rvalue, 1024, &bytes);
2554 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
2558 c->memory_limit = (uint64_t) bytes;
2562 int config_parse_device_allow(
2564 const char *filename,
2566 const char *section,
2567 unsigned section_line,
2574 _cleanup_free_ char *path = NULL;
2575 CGroupContext *c = data;
2576 CGroupDeviceAllow *a;
2580 if (isempty(rvalue)) {
2581 while (c->device_allow)
2582 cgroup_context_free_device_allow(c, c->device_allow);
2587 n = strcspn(rvalue, WHITESPACE);
2588 path = strndup(rvalue, n);
2592 if (!startswith(path, "/dev/") &&
2593 !startswith(path, "block-") &&
2594 !startswith(path, "char-")) {
2595 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2599 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2603 if (!in_charset(m, "rwm")) {
2604 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
2608 a = new0(CGroupDeviceAllow, 1);
2614 a->r = !!strchr(m, 'r');
2615 a->w = !!strchr(m, 'w');
2616 a->m = !!strchr(m, 'm');
2618 LIST_PREPEND(device_allow, c->device_allow, a);
2622 int config_parse_blockio_weight(
2624 const char *filename,
2626 const char *section,
2627 unsigned section_line,
2634 unsigned long *weight = data, lu;
2641 if (isempty(rvalue)) {
2642 *weight = (unsigned long) -1;
2646 r = safe_atolu(rvalue, &lu);
2647 if (r < 0 || lu < 10 || lu > 1000) {
2648 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
2656 int config_parse_blockio_device_weight(
2658 const char *filename,
2660 const char *section,
2661 unsigned section_line,
2668 _cleanup_free_ char *path = NULL;
2669 CGroupBlockIODeviceWeight *w;
2670 CGroupContext *c = data;
2680 if (isempty(rvalue)) {
2681 while (c->blockio_device_weights)
2682 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2687 n = strcspn(rvalue, WHITESPACE);
2688 weight = rvalue + n;
2690 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Expected block device and device weight. Ignoring.");
2694 path = strndup(rvalue, n);
2698 if (!path_startswith(path, "/dev")) {
2699 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2703 weight += strspn(weight, WHITESPACE);
2704 r = safe_atolu(weight, &lu);
2705 if (r < 0 || lu < 10 || lu > 1000) {
2706 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO weight '%s' invalid. Ignoring.", rvalue);
2710 w = new0(CGroupBlockIODeviceWeight, 1);
2719 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2723 int config_parse_blockio_bandwidth(
2725 const char *filename,
2727 const char *section,
2728 unsigned section_line,
2735 _cleanup_free_ char *path = NULL;
2736 CGroupBlockIODeviceBandwidth *b;
2737 CGroupContext *c = data;
2738 const char *bandwidth;
2748 read = streq("BlockIOReadBandwidth", lvalue);
2750 if (isempty(rvalue)) {
2751 CGroupBlockIODeviceBandwidth *next;
2753 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2754 if (b->read == read)
2755 cgroup_context_free_blockio_device_bandwidth(c, b);
2760 n = strcspn(rvalue, WHITESPACE);
2761 bandwidth = rvalue + n;
2762 bandwidth += strspn(bandwidth, WHITESPACE);
2765 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2766 "Expected space separated pair of device node and bandwidth. Ignoring.");
2770 path = strndup(rvalue, n);
2774 if (!path_startswith(path, "/dev")) {
2775 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2776 "Invalid device node path '%s'. Ignoring.", path);
2780 r = parse_size(bandwidth, 1000, &bytes);
2781 if (r < 0 || bytes <= 0) {
2782 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2786 b = new0(CGroupBlockIODeviceBandwidth, 1);
2792 b->bandwidth = (uint64_t) bytes;
2795 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2800 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2802 int config_parse_job_mode_isolate(
2804 const char *filename,
2806 const char *section,
2807 unsigned section_line,
2821 r = parse_boolean(rvalue);
2823 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2827 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2831 int config_parse_personality(
2833 const char *filename,
2835 const char *section,
2836 unsigned section_line,
2843 unsigned long *personality = data, p;
2848 assert(personality);
2850 p = personality_from_string(rvalue);
2851 if (p == 0xffffffffUL) {
2852 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2853 "Failed to parse personality, ignoring: %s", rvalue);
2861 int config_parse_runtime_directory(
2863 const char *filename,
2865 const char *section,
2866 unsigned section_line,
2874 const char *word, *state;
2883 if (isempty(rvalue)) {
2884 /* Empty assignment resets the list */
2890 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2891 _cleanup_free_ char *n;
2893 n = strndup(word, l);
2897 if (!filename_is_safe(n)) {
2898 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2902 r = strv_push(rt, n);
2912 int config_parse_set_status(
2914 const char *filename,
2916 const char *section,
2917 unsigned section_line,
2925 const char *word, *state;
2927 ExitStatusSet *status_set = data;
2934 /* Empty assignment resets the list */
2935 if (isempty(rvalue)) {
2936 exit_status_set_free(status_set);
2940 FOREACH_WORD(word, l, rvalue, state) {
2941 _cleanup_free_ char *temp;
2944 temp = strndup(word, l);
2948 r = safe_atoi(temp, &val);
2950 val = signal_from_string_try_harder(temp);
2953 r = set_ensure_allocated(&status_set->signal, NULL, NULL);
2957 r = set_put(status_set->signal, INT_TO_PTR(val));
2959 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", word);
2963 log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", word);
2967 if (val < 0 || val > 255)
2968 log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
2970 r = set_ensure_allocated(&status_set->status, NULL, NULL);
2974 r = set_put(status_set->status, INT_TO_PTR(val));
2976 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", word);
2986 int config_parse_namespace_path_strv(
2988 const char *filename,
2990 const char *section,
2991 unsigned section_line,
2999 const char *word, *state;
3008 if (isempty(rvalue)) {
3009 /* Empty assignment resets the list */
3015 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3016 _cleanup_free_ char *n;
3019 n = strndup(word, l);
3023 if (!utf8_is_valid(n)) {
3024 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3028 offset = n[0] == '-';
3029 if (!path_is_absolute(n + offset)) {
3030 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
3034 path_kill_slashes(n);
3036 r = strv_push(sv, n);
3046 int config_parse_no_new_privileges(
3048 const char *filename,
3050 const char *section,
3051 unsigned section_line,
3058 ExecContext *c = data;
3066 k = parse_boolean(rvalue);
3068 log_syntax(unit, LOG_ERR, filename, line, -k, "Failed to parse boolean value, ignoring: %s", rvalue);
3072 c->no_new_privileges = !!k;
3073 c->no_new_privileges_set = true;
3078 int config_parse_protect_home(
3080 const char *filename,
3082 const char *section,
3083 unsigned section_line,
3090 ExecContext *c = data;
3098 /* Our enum shall be a superset of booleans, hence first try
3099 * to parse as as boolean, and then as enum */
3101 k = parse_boolean(rvalue);
3103 c->protect_home = PROTECT_HOME_YES;
3105 c->protect_home = PROTECT_HOME_NO;
3109 h = protect_home_from_string(rvalue);
3111 log_syntax(unit, LOG_ERR, filename, line, -h, "Failed to parse protect home value, ignoring: %s", rvalue);
3115 c->protect_home = h;
3121 int config_parse_protect_system(
3123 const char *filename,
3125 const char *section,
3126 unsigned section_line,
3133 ExecContext *c = data;
3141 /* Our enum shall be a superset of booleans, hence first try
3142 * to parse as as boolean, and then as enum */
3144 k = parse_boolean(rvalue);
3146 c->protect_system = PROTECT_SYSTEM_YES;
3148 c->protect_system = PROTECT_SYSTEM_NO;
3152 s = protect_system_from_string(rvalue);
3154 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse protect system value, ignoring: %s", rvalue);
3158 c->protect_system = s;
3164 #define FOLLOW_MAX 8
3166 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3177 /* This will update the filename pointer if the loaded file is
3178 * reached by a symlink. The old string will be freed. */
3181 char *target, *name;
3183 if (c++ >= FOLLOW_MAX)
3186 path_kill_slashes(*filename);
3188 /* Add the file name we are currently looking at to
3189 * the names of this unit, but only if it is a valid
3191 name = basename(*filename);
3193 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3195 id = set_get(names, name);
3201 r = set_consume(names, id);
3207 /* Try to open the file name, but don't if its a symlink */
3208 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3215 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3216 r = readlink_and_make_absolute(*filename, &target);
3224 f = fdopen(fd, "re");
3236 static int merge_by_names(Unit **u, Set *names, const char *id) {
3244 /* Let's try to add in all symlink names we found */
3245 while ((k = set_steal_first(names))) {
3247 /* First try to merge in the other name into our
3249 r = unit_merge_by_name(*u, k);
3253 /* Hmm, we couldn't merge the other unit into
3254 * ours? Then let's try it the other way
3257 other = manager_get_unit((*u)->manager, k);
3261 r = unit_merge(other, *u);
3264 return merge_by_names(u, names, NULL);
3272 unit_choose_id(*u, id);
3280 static int load_from_path(Unit *u, const char *path) {
3282 _cleanup_set_free_free_ Set *symlink_names = NULL;
3283 _cleanup_fclose_ FILE *f = NULL;
3284 _cleanup_free_ char *filename = NULL;
3292 symlink_names = set_new(string_hash_func, string_compare_func);
3296 if (path_is_absolute(path)) {
3298 filename = strdup(path);
3302 r = open_follow(&filename, &f, symlink_names, &id);
3314 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3316 /* Instead of opening the path right away, we manually
3317 * follow all symlinks and add their name to our unit
3318 * name set while doing so */
3319 filename = path_make_absolute(path, *p);
3323 if (u->manager->unit_path_cache &&
3324 !set_get(u->manager->unit_path_cache, filename))
3327 r = open_follow(&filename, &f, symlink_names, &id);
3336 /* Empty the symlink names for the next run */
3337 set_clear_free(symlink_names);
3346 /* Hmm, no suitable file found? */
3350 r = merge_by_names(&merged, symlink_names, id);
3355 u->load_state = UNIT_MERGED;
3359 if (fstat(fileno(f), &st) < 0)
3362 if (null_or_empty(&st))
3363 u->load_state = UNIT_MASKED;
3365 u->load_state = UNIT_LOADED;
3367 /* Now, parse the file contents */
3368 r = config_parse(u->id, filename, f,
3369 UNIT_VTABLE(u)->sections,
3370 config_item_perf_lookup, load_fragment_gperf_lookup,
3371 false, true, false, u);
3376 free(u->fragment_path);
3377 u->fragment_path = filename;
3380 u->fragment_mtime = timespec_load(&st.st_mtim);
3382 if (u->source_path) {
3383 if (stat(u->source_path, &st) >= 0)
3384 u->source_mtime = timespec_load(&st.st_mtim);
3386 u->source_mtime = 0;
3392 int unit_load_fragment(Unit *u) {
3398 assert(u->load_state == UNIT_STUB);
3401 /* First, try to find the unit under its id. We always look
3402 * for unit files in the default directories, to make it easy
3403 * to override things by placing things in /etc/systemd/system */
3404 r = load_from_path(u, u->id);
3408 /* Try to find an alias we can load this with */
3409 if (u->load_state == UNIT_STUB)
3410 SET_FOREACH(t, u->names, i) {
3415 r = load_from_path(u, t);
3419 if (u->load_state != UNIT_STUB)
3423 /* And now, try looking for it under the suggested (originally linked) path */
3424 if (u->load_state == UNIT_STUB && u->fragment_path) {
3426 r = load_from_path(u, u->fragment_path);
3430 if (u->load_state == UNIT_STUB) {
3431 /* Hmm, this didn't work? Then let's get rid
3432 * of the fragment path stored for us, so that
3433 * we don't point to an invalid location. */
3434 free(u->fragment_path);
3435 u->fragment_path = NULL;
3439 /* Look for a template */
3440 if (u->load_state == UNIT_STUB && u->instance) {
3441 _cleanup_free_ char *k;
3443 k = unit_name_template(u->id);
3447 r = load_from_path(u, k);
3451 if (u->load_state == UNIT_STUB)
3452 SET_FOREACH(t, u->names, i) {
3453 _cleanup_free_ char *z = NULL;
3458 z = unit_name_template(t);
3462 r = load_from_path(u, z);
3466 if (u->load_state != UNIT_STUB)
3474 void unit_dump_config_items(FILE *f) {
3475 static const struct {
3476 const ConfigParserCallback callback;
3479 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3480 { config_parse_warn_compat, "NOTSUPPORTED" },
3482 { config_parse_int, "INTEGER" },
3483 { config_parse_unsigned, "UNSIGNED" },
3484 { config_parse_iec_size, "SIZE" },
3485 { config_parse_iec_off, "SIZE" },
3486 { config_parse_si_size, "SIZE" },
3487 { config_parse_bool, "BOOLEAN" },
3488 { config_parse_string, "STRING" },
3489 { config_parse_path, "PATH" },
3490 { config_parse_unit_path_printf, "PATH" },
3491 { config_parse_strv, "STRING [...]" },
3492 { config_parse_exec_nice, "NICE" },
3493 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3494 { config_parse_exec_io_class, "IOCLASS" },
3495 { config_parse_exec_io_priority, "IOPRIORITY" },
3496 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3497 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3498 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3499 { config_parse_mode, "MODE" },
3500 { config_parse_unit_env_file, "FILE" },
3501 { config_parse_output, "OUTPUT" },
3502 { config_parse_input, "INPUT" },
3503 { config_parse_log_facility, "FACILITY" },
3504 { config_parse_log_level, "LEVEL" },
3505 { config_parse_exec_capabilities, "CAPABILITIES" },
3506 { config_parse_exec_secure_bits, "SECUREBITS" },
3507 { config_parse_bounding_set, "BOUNDINGSET" },
3508 { config_parse_limit, "LIMIT" },
3509 { config_parse_unit_deps, "UNIT [...]" },
3510 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3511 { config_parse_service_type, "SERVICETYPE" },
3512 { config_parse_service_restart, "SERVICERESTART" },
3513 #ifdef HAVE_SYSV_COMPAT
3514 { config_parse_sysv_priority, "SYSVPRIORITY" },
3516 { config_parse_kill_mode, "KILLMODE" },
3517 { config_parse_kill_signal, "SIGNAL" },
3518 { config_parse_socket_listen, "SOCKET [...]" },
3519 { config_parse_socket_bind, "SOCKETBIND" },
3520 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3521 { config_parse_sec, "SECONDS" },
3522 { config_parse_nsec, "NANOSECONDS" },
3523 { config_parse_namespace_path_strv, "PATH [...]" },
3524 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3525 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3526 { config_parse_unit_string_printf, "STRING" },
3527 { config_parse_trigger_unit, "UNIT" },
3528 { config_parse_timer, "TIMER" },
3529 { config_parse_path_spec, "PATH" },
3530 { config_parse_notify_access, "ACCESS" },
3531 { config_parse_ip_tos, "TOS" },
3532 { config_parse_unit_condition_path, "CONDITION" },
3533 { config_parse_unit_condition_string, "CONDITION" },
3534 { config_parse_unit_condition_null, "CONDITION" },
3535 { config_parse_unit_slice, "SLICE" },
3536 { config_parse_documentation, "URL" },
3537 { config_parse_service_timeout, "SECONDS" },
3538 { config_parse_failure_action, "ACTION" },
3539 { config_parse_set_status, "STATUS" },
3540 { config_parse_service_sockets, "SOCKETS" },
3541 { config_parse_environ, "ENVIRON" },
3543 { config_parse_syscall_filter, "SYSCALLS" },
3544 { config_parse_syscall_archs, "ARCHS" },
3545 { config_parse_syscall_errno, "ERRNO" },
3546 { config_parse_address_families, "FAMILIES" },
3548 { config_parse_cpu_shares, "SHARES" },
3549 { config_parse_memory_limit, "LIMIT" },
3550 { config_parse_device_allow, "DEVICE" },
3551 { config_parse_device_policy, "POLICY" },
3552 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3553 { config_parse_blockio_weight, "WEIGHT" },
3554 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3555 { config_parse_long, "LONG" },
3556 { config_parse_socket_service, "SERVICE" },
3558 { config_parse_exec_selinux_context, "LABEL" },
3560 { config_parse_job_mode, "MODE" },
3561 { config_parse_job_mode_isolate, "BOOLEAN" },
3562 { config_parse_personality, "PERSONALITY" },
3565 const char *prev = NULL;
3570 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3571 const char *rvalue = "OTHER", *lvalue;
3575 const ConfigPerfItem *p;
3577 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3579 dot = strchr(i, '.');
3580 lvalue = dot ? dot + 1 : i;
3584 if (!prev || !strneq(prev, i, prefix_len+1)) {
3588 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3591 for (j = 0; j < ELEMENTSOF(table); j++)
3592 if (p->parse == table[j].callback) {
3593 rvalue = table[j].rvalue;
3597 fprintf(f, "%s=%s\n", lvalue, rvalue);