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"
63 #include "bus-internal.h"
66 #include "seccomp-util.h"
69 int config_parse_warn_compat(
74 unsigned section_line,
80 Disabled reason = ltype;
83 case DISABLED_CONFIGURATION:
84 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
85 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
88 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
89 "Support for option %s= has been removed and it is ignored", lvalue);
91 case DISABLED_EXPERIMENTAL:
92 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
93 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
100 int config_parse_unit_deps(const char *unit,
101 const char *filename,
104 unsigned section_line,
111 UnitDependency d = ltype;
113 const char *word, *state;
120 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
121 _cleanup_free_ char *t = NULL, *k = NULL;
124 t = strndup(word, l);
128 r = unit_name_printf(u, t, &k);
130 log_syntax(unit, LOG_ERR, filename, line, -r,
131 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
135 r = unit_add_dependency_by_name(u, d, k, NULL, true);
137 log_syntax(unit, LOG_ERR, filename, line, -r,
138 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
141 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
146 int config_parse_unit_string_printf(
148 const char *filename,
151 unsigned section_line,
158 _cleanup_free_ char *k = NULL;
167 r = unit_full_printf(u, rvalue, &k);
169 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
173 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
176 int config_parse_unit_strv_printf(const char *unit,
177 const char *filename,
180 unsigned section_line,
188 _cleanup_free_ char *k = NULL;
196 r = unit_full_printf(u, rvalue, &k);
198 log_syntax(unit, LOG_ERR, filename, line, -r,
199 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
201 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
202 k ? k : rvalue, data, userdata);
205 int config_parse_unit_path_printf(const char *unit,
206 const char *filename,
209 unsigned section_line,
216 _cleanup_free_ char *k = NULL;
225 r = unit_full_printf(u, rvalue, &k);
227 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
231 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
234 int config_parse_unit_path_strv_printf(
236 const char *filename,
239 unsigned section_line,
247 const char *word, *state;
257 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
258 _cleanup_free_ char *k = NULL;
264 r = unit_full_printf(u, t, &k);
266 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
270 if (!utf8_is_valid(k)) {
271 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
275 if (!path_is_absolute(k)) {
276 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
280 path_kill_slashes(k);
289 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
294 int config_parse_socket_listen(const char *unit,
295 const char *filename,
298 unsigned section_line,
305 _cleanup_free_ SocketPort *p = NULL;
317 if (isempty(rvalue)) {
318 /* An empty assignment removes all ports */
319 socket_free_ports(s);
323 p = new0(SocketPort, 1);
327 if (ltype != SOCKET_SOCKET) {
330 r = unit_full_printf(UNIT(s), rvalue, &p->path);
332 p->path = strdup(rvalue);
336 log_syntax(unit, LOG_ERR, filename, line, -r,
337 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
340 path_kill_slashes(p->path);
342 } else if (streq(lvalue, "ListenNetlink")) {
343 _cleanup_free_ char *k = NULL;
345 p->type = SOCKET_SOCKET;
346 r = unit_full_printf(UNIT(s), rvalue, &k);
348 log_syntax(unit, LOG_ERR, filename, line, -r,
349 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
351 r = socket_address_parse_netlink(&p->address, k ?: rvalue);
353 log_syntax(unit, LOG_ERR, filename, line, -r,
354 "Failed to parse address value, ignoring: %s", rvalue);
359 _cleanup_free_ char *k = NULL;
361 p->type = SOCKET_SOCKET;
362 r = unit_full_printf(UNIT(s), rvalue, &k);
364 log_syntax(unit, LOG_ERR, filename, line, -r,
365 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
367 r = socket_address_parse(&p->address, k ? k : rvalue);
369 log_syntax(unit, LOG_ERR, filename, line, -r,
370 "Failed to parse address value, ignoring: %s", rvalue);
374 if (streq(lvalue, "ListenStream"))
375 p->address.type = SOCK_STREAM;
376 else if (streq(lvalue, "ListenDatagram"))
377 p->address.type = SOCK_DGRAM;
379 assert(streq(lvalue, "ListenSequentialPacket"));
380 p->address.type = SOCK_SEQPACKET;
383 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
384 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
385 "Address family not supported, ignoring: %s", rvalue);
394 LIST_FIND_TAIL(port, s->ports, tail);
395 LIST_INSERT_AFTER(port, s->ports, tail, p);
397 LIST_PREPEND(port, s->ports, p);
403 int config_parse_socket_bind(const char *unit,
404 const char *filename,
407 unsigned section_line,
415 SocketAddressBindIPv6Only b;
424 b = socket_address_bind_ipv6_only_from_string(rvalue);
428 r = parse_boolean(rvalue);
430 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
431 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
435 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
437 s->bind_ipv6_only = b;
442 int config_parse_exec_nice(const char *unit,
443 const char *filename,
446 unsigned section_line,
453 ExecContext *c = data;
461 r = safe_atoi(rvalue, &priority);
463 log_syntax(unit, LOG_ERR, filename, line, -r,
464 "Failed to parse nice priority, ignoring: %s. ", rvalue);
468 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
469 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
470 "Nice priority out of range, ignoring: %s", rvalue);
480 int config_parse_exec_oom_score_adjust(const char* unit,
481 const char *filename,
484 unsigned section_line,
491 ExecContext *c = data;
499 r = safe_atoi(rvalue, &oa);
501 log_syntax(unit, LOG_ERR, filename, line, -r,
502 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
506 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
507 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
508 "OOM score adjust value out of range, ignoring: %s", rvalue);
512 c->oom_score_adjust = oa;
513 c->oom_score_adjust_set = true;
518 int config_parse_exec(const char *unit,
519 const char *filename,
522 unsigned section_line,
529 ExecCommand **e = data, *nce;
541 if (isempty(rvalue)) {
542 /* An empty assignment resets the list */
543 *e = exec_command_free_list(*e);
547 /* We accept an absolute path as first argument, or
548 * alternatively an absolute prefixed with @ to allow
549 * overriding of argv[0]. */
552 const char *word, *state, *reason;
554 bool separate_argv0 = false, ignore = false;
560 rvalue += strspn(rvalue, WHITESPACE);
566 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
568 for (i = 0; i < 2; i++) {
569 if (*word == '-' && !ignore) {
574 if (*word == '@' && !separate_argv0) {
575 separate_argv0 = true;
580 if (strneq(word, ";", MAX(l, 1U)))
585 if (!isempty(state)) {
586 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
587 "Trailing garbage, ignoring.");
592 /* If seperate_argv0, we'll move first element to path variable */
593 n = new(char*, MAX(k + !separate_argv0, 1u));
598 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
602 if (separate_argv0 ? path == NULL : k == 0) {
603 /* first word, very special */
604 skip = separate_argv0 + ignore;
606 /* skip special chars in the beginning */
609 } else if (strneq(word, ";", MAX(l, 1U)))
610 /* new commandline */
614 skip = strneq(word, "\\;", MAX(l, 1U));
616 c = cunescape_length(word + skip, l - skip);
622 if (!utf8_is_valid(c)) {
623 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
628 /* where to stuff this? */
629 if (separate_argv0 && path == NULL)
637 log_debug("path: %s", path ?: n[0]);
640 reason = "Empty executable name or zeroeth argument";
641 else if (!string_is_safe(path ?: n[0]))
642 reason = "Executable path contains special characters";
643 else if (!path_is_absolute(path ?: n[0]))
644 reason = "Executable path is not absolute";
645 else if (endswith(path ?: n[0], "/"))
646 reason = "Executable path specifies a directory";
650 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
651 "%s, ignoring: %s", reason, rvalue);
664 nce = new0(ExecCommand, 1);
672 nce->ignore = ignore;
674 path_kill_slashes(nce->path);
676 exec_command_append_list(e, nce);
692 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
693 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
695 int config_parse_socket_bindtodevice(const char* unit,
696 const char *filename,
699 unsigned section_line,
714 if (rvalue[0] && !streq(rvalue, "*")) {
721 free(s->bind_to_device);
722 s->bind_to_device = n;
727 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
728 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
730 int config_parse_exec_io_class(const char *unit,
731 const char *filename,
734 unsigned section_line,
741 ExecContext *c = data;
749 x = ioprio_class_from_string(rvalue);
751 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
752 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
756 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
757 c->ioprio_set = true;
762 int config_parse_exec_io_priority(const char *unit,
763 const char *filename,
766 unsigned section_line,
773 ExecContext *c = data;
781 r = safe_atoi(rvalue, &i);
782 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
783 log_syntax(unit, LOG_ERR, filename, line, -r,
784 "Failed to parse IO priority, ignoring: %s", rvalue);
788 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
789 c->ioprio_set = true;
794 int config_parse_exec_cpu_sched_policy(const char *unit,
795 const char *filename,
798 unsigned section_line,
806 ExecContext *c = data;
814 x = sched_policy_from_string(rvalue);
816 log_syntax(unit, LOG_ERR, filename, line, -x,
817 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
821 c->cpu_sched_policy = x;
822 /* Moving to or from real-time policy? We need to adjust the priority */
823 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
824 c->cpu_sched_set = true;
829 int config_parse_exec_cpu_sched_prio(const char *unit,
830 const char *filename,
833 unsigned section_line,
840 ExecContext *c = data;
848 r = safe_atoi(rvalue, &i);
850 log_syntax(unit, LOG_ERR, filename, line, -r,
851 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
855 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
856 min = sched_get_priority_min(c->cpu_sched_policy);
857 max = sched_get_priority_max(c->cpu_sched_policy);
859 if (i < min || i > max) {
860 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
861 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
865 c->cpu_sched_priority = i;
866 c->cpu_sched_set = true;
871 int config_parse_exec_cpu_affinity(const char *unit,
872 const char *filename,
875 unsigned section_line,
882 ExecContext *c = data;
883 const char *word, *state;
891 if (isempty(rvalue)) {
892 /* An empty assignment resets the CPU list */
899 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
900 _cleanup_free_ char *t = NULL;
904 t = strndup(word, l);
908 r = safe_atou(t, &cpu);
911 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
916 if (r < 0 || cpu >= c->cpuset_ncpus) {
917 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
918 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
922 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
925 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
926 "Trailing garbage, ignoring.");
931 int config_parse_exec_capabilities(const char *unit,
932 const char *filename,
935 unsigned section_line,
942 ExecContext *c = data;
950 cap = cap_from_text(rvalue);
952 log_syntax(unit, LOG_ERR, filename, line, errno,
953 "Failed to parse capabilities, ignoring: %s", rvalue);
958 cap_free(c->capabilities);
959 c->capabilities = cap;
964 int config_parse_exec_secure_bits(const char *unit,
965 const char *filename,
968 unsigned section_line,
975 ExecContext *c = data;
977 const char *word, *state;
984 if (isempty(rvalue)) {
985 /* An empty assignment resets the field */
990 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
991 if (first_word(word, "keep-caps"))
992 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
993 else if (first_word(word, "keep-caps-locked"))
994 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
995 else if (first_word(word, "no-setuid-fixup"))
996 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
997 else if (first_word(word, "no-setuid-fixup-locked"))
998 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
999 else if (first_word(word, "noroot"))
1000 c->secure_bits |= 1<<SECURE_NOROOT;
1001 else if (first_word(word, "noroot-locked"))
1002 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
1004 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1005 "Failed to parse secure bits, ignoring: %s", rvalue);
1009 if (!isempty(state))
1010 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1011 "Invalid syntax, garbage at the end, ignoring.");
1016 int config_parse_bounding_set(const char *unit,
1017 const char *filename,
1019 const char *section,
1020 unsigned section_line,
1027 uint64_t *capability_bounding_set_drop = data;
1028 const char *word, *state;
1030 bool invert = false;
1038 if (rvalue[0] == '~') {
1043 /* Note that we store this inverted internally, since the
1044 * kernel wants it like this. But we actually expose it
1045 * non-inverted everywhere to have a fully normalized
1048 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1049 _cleanup_free_ char *t = NULL;
1052 t = strndup(word, l);
1056 cap = capability_from_name(t);
1058 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
1062 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1064 if (!isempty(state))
1065 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1066 "Trailing garbage, ignoring.");
1069 *capability_bounding_set_drop |= sum;
1071 *capability_bounding_set_drop |= ~sum;
1076 int config_parse_limit(const char *unit,
1077 const char *filename,
1079 const char *section,
1080 unsigned section_line,
1087 struct rlimit **rl = data;
1088 unsigned long long u;
1097 if (streq(rvalue, "infinity"))
1098 u = (unsigned long long) RLIM_INFINITY;
1102 r = safe_atollu(rvalue, &u);
1104 log_syntax(unit, LOG_ERR, filename, line, -r,
1105 "Failed to parse resource value, ignoring: %s", rvalue);
1111 *rl = new(struct rlimit, 1);
1116 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1120 #ifdef HAVE_SYSV_COMPAT
1121 int config_parse_sysv_priority(const char *unit,
1122 const char *filename,
1124 const char *section,
1125 unsigned section_line,
1132 int *priority = data;
1140 r = safe_atoi(rvalue, &i);
1141 if (r < 0 || i < 0) {
1142 log_syntax(unit, LOG_ERR, filename, line, -r,
1143 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1147 *priority = (int) i;
1152 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1154 int config_parse_kill_signal(const char *unit,
1155 const char *filename,
1157 const char *section,
1158 unsigned section_line,
1173 r = signal_from_string_try_harder(rvalue);
1175 log_syntax(unit, LOG_ERR, filename, line, -r,
1176 "Failed to parse kill signal, ignoring: %s", rvalue);
1184 int config_parse_exec_mount_flags(const char *unit,
1185 const char *filename,
1187 const char *section,
1188 unsigned section_line,
1195 ExecContext *c = data;
1196 const char *word, *state;
1198 unsigned long flags = 0;
1205 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1206 _cleanup_free_ char *t;
1208 t = strndup(word, l);
1212 if (streq(t, "shared"))
1214 else if (streq(t, "slave"))
1216 else if (streq(word, "private"))
1219 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1220 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1224 if (!isempty(state))
1225 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1226 "Trailing garbage, ignoring.");
1228 c->mount_flags = flags;
1232 int config_parse_exec_selinux_context(
1234 const char *filename,
1236 const char *section,
1237 unsigned section_line,
1244 ExecContext *c = data;
1255 if (isempty(rvalue)) {
1256 free(c->selinux_context);
1257 c->selinux_context = NULL;
1258 c->selinux_context_ignore = false;
1262 if (rvalue[0] == '-') {
1268 r = unit_name_printf(u, rvalue, &k);
1270 log_syntax(unit, LOG_ERR, filename, line, -r,
1271 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1275 free(c->selinux_context);
1276 c->selinux_context = k;
1277 c->selinux_context_ignore = ignore;
1282 int config_parse_exec_apparmor_profile(
1284 const char *filename,
1286 const char *section,
1287 unsigned section_line,
1294 ExecContext *c = data;
1305 if (isempty(rvalue)) {
1306 free(c->apparmor_profile);
1307 c->apparmor_profile = NULL;
1308 c->apparmor_profile_ignore = false;
1312 if (rvalue[0] == '-') {
1318 r = unit_name_printf(u, rvalue, &k);
1320 log_syntax(unit, LOG_ERR, filename, line, -r,
1321 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1325 free(c->apparmor_profile);
1326 c->apparmor_profile = k;
1327 c->apparmor_profile_ignore = ignore;
1332 int config_parse_exec_smack_process_label(
1334 const char *filename,
1336 const char *section,
1337 unsigned section_line,
1344 ExecContext *c = data;
1355 if (isempty(rvalue)) {
1356 free(c->smack_process_label);
1357 c->smack_process_label = NULL;
1358 c->smack_process_label_ignore = false;
1362 if (rvalue[0] == '-') {
1368 r = unit_name_printf(u, rvalue, &k);
1370 log_syntax(unit, LOG_ERR, filename, line, -r,
1371 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1375 free(c->smack_process_label);
1376 c->smack_process_label = k;
1377 c->smack_process_label_ignore = ignore;
1382 int config_parse_timer(const char *unit,
1383 const char *filename,
1385 const char *section,
1386 unsigned section_line,
1397 CalendarSpec *c = NULL;
1404 if (isempty(rvalue)) {
1405 /* Empty assignment resets list */
1406 timer_free_values(t);
1410 b = timer_base_from_string(lvalue);
1412 log_syntax(unit, LOG_ERR, filename, line, -b,
1413 "Failed to parse timer base, ignoring: %s", lvalue);
1417 if (b == TIMER_CALENDAR) {
1418 if (calendar_spec_from_string(rvalue, &c) < 0) {
1419 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1420 "Failed to parse calendar specification, ignoring: %s",
1425 if (parse_sec(rvalue, &u) < 0) {
1426 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1427 "Failed to parse timer value, ignoring: %s",
1433 v = new0(TimerValue, 1);
1435 calendar_spec_free(c);
1441 v->calendar_spec = c;
1443 LIST_PREPEND(value, t->values, v);
1448 int config_parse_trigger_unit(
1450 const char *filename,
1452 const char *section,
1453 unsigned section_line,
1460 _cleanup_free_ char *p = NULL;
1470 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1471 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1472 "Multiple units to trigger specified, ignoring: %s", rvalue);
1476 r = unit_name_printf(u, rvalue, &p);
1478 log_syntax(unit, LOG_ERR, filename, line, -r,
1479 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1481 type = unit_name_to_type(p ?: rvalue);
1483 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1484 "Unit type not valid, ignoring: %s", rvalue);
1488 if (type == u->type) {
1489 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1490 "Trigger cannot be of same type, ignoring: %s", rvalue);
1494 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1496 log_syntax(unit, LOG_ERR, filename, line, -r,
1497 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1504 int config_parse_path_spec(const char *unit,
1505 const char *filename,
1507 const char *section,
1508 unsigned section_line,
1518 _cleanup_free_ char *k = NULL;
1526 if (isempty(rvalue)) {
1527 /* Empty assignment clears list */
1532 b = path_type_from_string(lvalue);
1534 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1535 "Failed to parse path type, ignoring: %s", lvalue);
1539 r = unit_full_printf(UNIT(p), rvalue, &k);
1545 log_syntax(unit, LOG_ERR, filename, line, -r,
1546 "Failed to resolve unit specifiers on %s. Ignoring.",
1550 if (!path_is_absolute(k)) {
1551 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1552 "Path is not absolute, ignoring: %s", k);
1556 s = new0(PathSpec, 1);
1561 s->path = path_kill_slashes(k);
1566 LIST_PREPEND(spec, p->specs, s);
1571 int config_parse_socket_service(
1573 const char *filename,
1575 const char *section,
1576 unsigned section_line,
1583 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1587 _cleanup_free_ char *p = NULL;
1594 r = unit_name_printf(UNIT(s), rvalue, &p);
1596 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1600 if (!endswith(p, ".service")) {
1601 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1605 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1607 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1611 unit_ref_set(&s->service, x);
1616 int config_parse_service_sockets(
1618 const char *filename,
1620 const char *section,
1621 unsigned section_line,
1629 const char *word, *state;
1638 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1639 _cleanup_free_ char *t = NULL, *k = NULL;
1641 t = strndup(word, l);
1645 r = unit_name_printf(UNIT(s), t, &k);
1647 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1651 if (!endswith(k, ".socket")) {
1652 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type socket, ignoring: %s", k);
1656 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1658 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1660 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1662 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1664 if (!isempty(state))
1665 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
1670 int config_parse_bus_name(
1672 const char *filename,
1674 const char *section,
1675 unsigned section_line,
1682 _cleanup_free_ char *k = NULL;
1691 r = unit_full_printf(u, rvalue, &k);
1693 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
1697 if (!service_name_is_valid(k)) {
1698 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bus name %s, ignoring.", k);
1702 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
1705 int config_parse_service_timeout(const char *unit,
1706 const char *filename,
1708 const char *section,
1709 unsigned section_line,
1716 Service *s = userdata;
1724 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1725 rvalue, data, userdata);
1729 if (streq(lvalue, "TimeoutSec")) {
1730 s->start_timeout_defined = true;
1731 s->timeout_stop_usec = s->timeout_start_usec;
1732 } else if (streq(lvalue, "TimeoutStartSec"))
1733 s->start_timeout_defined = true;
1738 int config_parse_busname_service(
1740 const char *filename,
1742 const char *section,
1743 unsigned section_line,
1750 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1754 _cleanup_free_ char *p = NULL;
1761 r = unit_name_printf(UNIT(n), rvalue, &p);
1763 log_syntax(unit, LOG_ERR, filename, line, -r,
1764 "Failed to resolve specifiers, ignoring: %s", rvalue);
1768 if (!endswith(p, ".service")) {
1769 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1770 "Unit must be of type service, ignoring: %s", rvalue);
1774 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1776 log_syntax(unit, LOG_ERR, filename, line, -r,
1777 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1781 unit_ref_set(&n->service, x);
1786 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1788 int config_parse_bus_policy(
1790 const char *filename,
1792 const char *section,
1793 unsigned section_line,
1800 _cleanup_free_ BusNamePolicy *p = NULL;
1801 _cleanup_free_ char *id_str = NULL;
1802 BusName *busname = data;
1810 p = new0(BusNamePolicy, 1);
1814 if (streq(lvalue, "AllowUser"))
1815 p->type = BUSNAME_POLICY_TYPE_USER;
1816 else if (streq(lvalue, "AllowGroup"))
1817 p->type = BUSNAME_POLICY_TYPE_GROUP;
1819 assert_not_reached("Unknown lvalue");
1821 id_str = strdup(rvalue);
1825 access_str = strpbrk(id_str, WHITESPACE);
1827 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1828 "Invalid busname policy value '%s'", rvalue);
1834 access_str += strspn(access_str, WHITESPACE);
1836 p->access = bus_policy_access_from_string(access_str);
1837 if (p->access < 0) {
1838 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1839 "Invalid busname policy access type '%s'", access_str);
1846 LIST_PREPEND(policy, busname->policy, p);
1852 int config_parse_bus_endpoint_policy(
1854 const char *filename,
1856 const char *section,
1857 unsigned section_line,
1864 _cleanup_free_ char *name = NULL;
1865 BusPolicyAccess access;
1866 ExecContext *c = data;
1875 name = strdup(rvalue);
1879 access_str = strpbrk(name, WHITESPACE);
1881 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1882 "Invalid endpoint policy value '%s'", rvalue);
1888 access_str += strspn(access_str, WHITESPACE);
1890 access = bus_policy_access_from_string(access_str);
1891 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1892 access >= _BUS_POLICY_ACCESS_MAX) {
1893 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1894 "Invalid endpoint policy access type '%s'", access_str);
1898 if (!c->bus_endpoint) {
1899 r = bus_endpoint_new(&c->bus_endpoint);
1905 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1908 int config_parse_unit_env_file(const char *unit,
1909 const char *filename,
1911 const char *section,
1912 unsigned section_line,
1921 _cleanup_free_ char *n = NULL;
1930 if (isempty(rvalue)) {
1931 /* Empty assignment frees the list */
1937 r = unit_full_printf(u, rvalue, &n);
1939 log_syntax(unit, LOG_ERR, filename, line, -r,
1940 "Failed to resolve specifiers, ignoring: %s", rvalue);
1943 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1944 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1945 "Path '%s' is not absolute, ignoring.", s);
1949 r = strv_extend(env, s);
1956 int config_parse_environ(const char *unit,
1957 const char *filename,
1959 const char *section,
1960 unsigned section_line,
1969 const char *word, *state;
1971 _cleanup_free_ char *k = NULL;
1979 if (isempty(rvalue)) {
1980 /* Empty assignment resets the list */
1987 r = unit_full_printf(u, rvalue, &k);
1989 log_syntax(unit, LOG_ERR, filename, line, -r,
1990 "Failed to resolve specifiers, ignoring: %s", rvalue);
1998 FOREACH_WORD_QUOTED(word, l, k, state) {
1999 _cleanup_free_ char *n;
2002 n = cunescape_length(word, l);
2006 if (!env_assignment_is_valid(n)) {
2007 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2008 "Invalid environment assignment, ignoring: %s", rvalue);
2012 x = strv_env_set(*env, n);
2019 if (!isempty(state))
2020 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2021 "Trailing garbage, ignoring.");
2026 int config_parse_ip_tos(const char *unit,
2027 const char *filename,
2029 const char *section,
2030 unsigned section_line,
2037 int *ip_tos = data, x;
2044 x = ip_tos_from_string(rvalue);
2046 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2047 "Failed to parse IP TOS value, ignoring: %s", rvalue);
2055 int config_parse_unit_condition_path(
2057 const char *filename,
2059 const char *section,
2060 unsigned section_line,
2067 _cleanup_free_ char *p = NULL;
2068 Condition **list = data, *c;
2069 ConditionType t = ltype;
2070 bool trigger, negate;
2079 if (isempty(rvalue)) {
2080 /* Empty assignment resets the list */
2081 *list = condition_free_list(*list);
2085 trigger = rvalue[0] == '|';
2089 negate = rvalue[0] == '!';
2093 r = unit_full_printf(u, rvalue, &p);
2095 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2099 if (!path_is_absolute(p)) {
2100 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2104 c = condition_new(t, p, trigger, negate);
2108 LIST_PREPEND(conditions, *list, c);
2112 int config_parse_unit_condition_string(
2114 const char *filename,
2116 const char *section,
2117 unsigned section_line,
2124 _cleanup_free_ char *s = NULL;
2125 Condition **list = data, *c;
2126 ConditionType t = ltype;
2127 bool trigger, negate;
2136 if (isempty(rvalue)) {
2137 /* Empty assignment resets the list */
2138 *list = condition_free_list(*list);
2142 trigger = rvalue[0] == '|';
2146 negate = rvalue[0] == '!';
2150 r = unit_full_printf(u, rvalue, &s);
2152 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2156 c = condition_new(t, s, trigger, negate);
2160 LIST_PREPEND(conditions, *list, c);
2164 int config_parse_unit_condition_null(
2166 const char *filename,
2168 const char *section,
2169 unsigned section_line,
2176 Condition **list = data, *c;
2177 bool trigger, negate;
2185 if (isempty(rvalue)) {
2186 /* Empty assignment resets the list */
2187 *list = condition_free_list(*list);
2191 trigger = rvalue[0] == '|';
2195 negate = rvalue[0] == '!';
2199 b = parse_boolean(rvalue);
2201 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2208 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2212 LIST_PREPEND(conditions, *list, c);
2216 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2217 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2219 int config_parse_unit_requires_mounts_for(
2221 const char *filename,
2223 const char *section,
2224 unsigned section_line,
2232 const char *word, *state;
2240 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2242 _cleanup_free_ char *n;
2244 n = strndup(word, l);
2248 if (!utf8_is_valid(n)) {
2249 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2253 r = unit_require_mounts_for(u, n);
2255 log_syntax(unit, LOG_ERR, filename, line, -r,
2256 "Failed to add required mount for, ignoring: %s", rvalue);
2260 if (!isempty(state))
2261 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2262 "Trailing garbage, ignoring.");
2267 int config_parse_documentation(const char *unit,
2268 const char *filename,
2270 const char *section,
2271 unsigned section_line,
2287 if (isempty(rvalue)) {
2288 /* Empty assignment resets the list */
2289 strv_free(u->documentation);
2290 u->documentation = NULL;
2294 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2295 rvalue, data, userdata);
2299 for (a = b = u->documentation; a && *a; a++) {
2301 if (is_valid_documentation_url(*a))
2304 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2305 "Invalid URL, ignoring: %s", *a);
2316 int config_parse_syscall_filter(
2318 const char *filename,
2320 const char *section,
2321 unsigned section_line,
2328 static const char default_syscalls[] =
2335 ExecContext *c = data;
2337 bool invert = false;
2338 const char *word, *state;
2347 if (isempty(rvalue)) {
2348 /* Empty assignment resets the list */
2349 set_free(c->syscall_filter);
2350 c->syscall_filter = NULL;
2351 c->syscall_whitelist = false;
2355 if (rvalue[0] == '~') {
2360 if (!c->syscall_filter) {
2361 c->syscall_filter = set_new(NULL);
2362 if (!c->syscall_filter)
2366 /* Allow everything but the ones listed */
2367 c->syscall_whitelist = false;
2371 /* Allow nothing but the ones listed */
2372 c->syscall_whitelist = true;
2374 /* Accept default syscalls if we are on a whitelist */
2375 NULSTR_FOREACH(i, default_syscalls) {
2378 id = seccomp_syscall_resolve_name(i);
2382 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2391 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2392 _cleanup_free_ char *t = NULL;
2395 t = strndup(word, l);
2399 id = seccomp_syscall_resolve_name(t);
2401 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2402 "Failed to parse system call, ignoring: %s", t);
2406 /* If we previously wanted to forbid a syscall and now
2407 * we want to allow it, then remove it from the list
2409 if (!invert == c->syscall_whitelist) {
2410 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2416 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2418 if (!isempty(state))
2419 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2420 "Trailing garbage, ignoring.");
2422 /* Turn on NNP, but only if it wasn't configured explicitly
2423 * before, and only if we are in user mode. */
2424 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2425 c->no_new_privileges = true;
2430 int config_parse_syscall_archs(
2432 const char *filename,
2434 const char *section,
2435 unsigned section_line,
2443 const char *word, *state;
2447 if (isempty(rvalue)) {
2453 r = set_ensure_allocated(archs, NULL);
2457 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2458 _cleanup_free_ char *t = NULL;
2461 t = strndup(word, l);
2465 r = seccomp_arch_from_string(t, &a);
2467 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2468 "Failed to parse system call architecture, ignoring: %s", t);
2472 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2478 if (!isempty(state))
2479 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2480 "Trailing garbage, ignoring.");
2485 int config_parse_syscall_errno(
2487 const char *filename,
2489 const char *section,
2490 unsigned section_line,
2497 ExecContext *c = data;
2504 if (isempty(rvalue)) {
2505 /* Empty assignment resets to KILL */
2506 c->syscall_errno = 0;
2510 e = errno_from_name(rvalue);
2512 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2513 "Failed to parse error number, ignoring: %s", rvalue);
2517 c->syscall_errno = e;
2521 int config_parse_address_families(
2523 const char *filename,
2525 const char *section,
2526 unsigned section_line,
2533 ExecContext *c = data;
2534 bool invert = false;
2535 const char *word, *state;
2543 if (isempty(rvalue)) {
2544 /* Empty assignment resets the list */
2545 set_free(c->address_families);
2546 c->address_families = NULL;
2547 c->address_families_whitelist = false;
2551 if (rvalue[0] == '~') {
2556 if (!c->address_families) {
2557 c->address_families = set_new(NULL);
2558 if (!c->address_families)
2561 c->address_families_whitelist = !invert;
2564 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2565 _cleanup_free_ char *t = NULL;
2568 t = strndup(word, l);
2572 af = af_from_name(t);
2574 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2575 "Failed to parse address family, ignoring: %s", t);
2579 /* If we previously wanted to forbid an address family and now
2580 * we want to allow it, then remove it from the list
2582 if (!invert == c->address_families_whitelist) {
2583 r = set_put(c->address_families, INT_TO_PTR(af));
2589 set_remove(c->address_families, INT_TO_PTR(af));
2591 if (!isempty(state))
2592 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2593 "Trailing garbage, ignoring.");
2599 int config_parse_unit_slice(
2601 const char *filename,
2603 const char *section,
2604 unsigned section_line,
2611 _cleanup_free_ char *k = NULL;
2612 Unit *u = userdata, *slice;
2620 r = unit_name_printf(u, rvalue, &k);
2622 log_syntax(unit, LOG_ERR, filename, line, -r,
2623 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2630 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2632 log_syntax(unit, LOG_ERR, filename, line, -r,
2633 "Failed to load slice unit %s. Ignoring.", k);
2637 if (slice->type != UNIT_SLICE) {
2638 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2639 "Slice unit %s is not a slice. Ignoring.", k);
2643 unit_ref_set(&u->slice, slice);
2647 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2649 int config_parse_cpu_shares(
2651 const char *filename,
2653 const char *section,
2654 unsigned section_line,
2661 unsigned long *shares = data, lu;
2668 if (isempty(rvalue)) {
2669 *shares = (unsigned long) -1;
2673 r = safe_atolu(rvalue, &lu);
2674 if (r < 0 || lu <= 0) {
2675 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2676 "CPU shares '%s' invalid. Ignoring.", rvalue);
2684 int config_parse_cpu_quota(
2686 const char *filename,
2688 const char *section,
2689 unsigned section_line,
2696 CGroupContext *c = data;
2703 if (isempty(rvalue)) {
2704 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2708 if (!endswith(rvalue, "%")) {
2710 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2711 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2715 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2716 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2717 "CPU quota '%s' invalid. Ignoring.", rvalue);
2721 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2726 int config_parse_memory_limit(
2728 const char *filename,
2730 const char *section,
2731 unsigned section_line,
2738 CGroupContext *c = data;
2742 if (isempty(rvalue)) {
2743 c->memory_limit = (uint64_t) -1;
2747 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2749 r = parse_size(rvalue, 1024, &bytes);
2751 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2752 "Memory limit '%s' invalid. Ignoring.", rvalue);
2756 c->memory_limit = (uint64_t) bytes;
2760 int config_parse_device_allow(
2762 const char *filename,
2764 const char *section,
2765 unsigned section_line,
2772 _cleanup_free_ char *path = NULL;
2773 CGroupContext *c = data;
2774 CGroupDeviceAllow *a;
2778 if (isempty(rvalue)) {
2779 while (c->device_allow)
2780 cgroup_context_free_device_allow(c, c->device_allow);
2785 n = strcspn(rvalue, WHITESPACE);
2786 path = strndup(rvalue, n);
2790 if (!startswith(path, "/dev/") &&
2791 !startswith(path, "block-") &&
2792 !startswith(path, "char-")) {
2793 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2794 "Invalid device node path '%s'. Ignoring.", path);
2798 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2802 if (!in_charset(m, "rwm")) {
2803 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2804 "Invalid device rights '%s'. Ignoring.", m);
2808 a = new0(CGroupDeviceAllow, 1);
2814 a->r = !!strchr(m, 'r');
2815 a->w = !!strchr(m, 'w');
2816 a->m = !!strchr(m, 'm');
2818 LIST_PREPEND(device_allow, c->device_allow, a);
2822 int config_parse_blockio_weight(
2824 const char *filename,
2826 const char *section,
2827 unsigned section_line,
2834 unsigned long *weight = data, lu;
2841 if (isempty(rvalue)) {
2842 *weight = (unsigned long) -1;
2846 r = safe_atolu(rvalue, &lu);
2847 if (r < 0 || lu < 10 || lu > 1000) {
2848 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2849 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2857 int config_parse_blockio_device_weight(
2859 const char *filename,
2861 const char *section,
2862 unsigned section_line,
2869 _cleanup_free_ char *path = NULL;
2870 CGroupBlockIODeviceWeight *w;
2871 CGroupContext *c = data;
2881 if (isempty(rvalue)) {
2882 while (c->blockio_device_weights)
2883 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2888 n = strcspn(rvalue, WHITESPACE);
2889 weight = rvalue + n;
2891 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2892 "Expected block device and device weight. Ignoring.");
2896 path = strndup(rvalue, n);
2900 if (!path_startswith(path, "/dev")) {
2901 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2902 "Invalid device node path '%s'. Ignoring.", path);
2906 weight += strspn(weight, WHITESPACE);
2907 r = safe_atolu(weight, &lu);
2908 if (r < 0 || lu < 10 || lu > 1000) {
2909 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2910 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2914 w = new0(CGroupBlockIODeviceWeight, 1);
2923 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2927 int config_parse_blockio_bandwidth(
2929 const char *filename,
2931 const char *section,
2932 unsigned section_line,
2939 _cleanup_free_ char *path = NULL;
2940 CGroupBlockIODeviceBandwidth *b;
2941 CGroupContext *c = data;
2942 const char *bandwidth;
2952 read = streq("BlockIOReadBandwidth", lvalue);
2954 if (isempty(rvalue)) {
2955 CGroupBlockIODeviceBandwidth *next;
2957 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2958 if (b->read == read)
2959 cgroup_context_free_blockio_device_bandwidth(c, b);
2964 n = strcspn(rvalue, WHITESPACE);
2965 bandwidth = rvalue + n;
2966 bandwidth += strspn(bandwidth, WHITESPACE);
2969 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2970 "Expected space separated pair of device node and bandwidth. Ignoring.");
2974 path = strndup(rvalue, n);
2978 if (!path_startswith(path, "/dev")) {
2979 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2980 "Invalid device node path '%s'. Ignoring.", path);
2984 r = parse_size(bandwidth, 1000, &bytes);
2985 if (r < 0 || bytes <= 0) {
2986 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2987 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2991 b = new0(CGroupBlockIODeviceBandwidth, 1);
2997 b->bandwidth = (uint64_t) bytes;
3000 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
3005 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
3007 int config_parse_job_mode_isolate(
3009 const char *filename,
3011 const char *section,
3012 unsigned section_line,
3026 r = parse_boolean(rvalue);
3028 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3029 "Failed to parse boolean, ignoring: %s", rvalue);
3033 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3037 int config_parse_personality(
3039 const char *filename,
3041 const char *section,
3042 unsigned section_line,
3049 unsigned long *personality = data, p;
3054 assert(personality);
3056 p = personality_from_string(rvalue);
3057 if (p == 0xffffffffUL) {
3058 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3059 "Failed to parse personality, ignoring: %s", rvalue);
3067 int config_parse_runtime_directory(
3069 const char *filename,
3071 const char *section,
3072 unsigned section_line,
3080 const char *word, *state;
3089 if (isempty(rvalue)) {
3090 /* Empty assignment resets the list */
3096 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3097 _cleanup_free_ char *n;
3099 n = strndup(word, l);
3103 if (!filename_is_valid(n)) {
3104 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3105 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3109 r = strv_push(rt, n);
3115 if (!isempty(state))
3116 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3117 "Trailing garbage, ignoring.");
3122 int config_parse_set_status(
3124 const char *filename,
3126 const char *section,
3127 unsigned section_line,
3135 const char *word, *state;
3137 ExitStatusSet *status_set = data;
3144 /* Empty assignment resets the list */
3145 if (isempty(rvalue)) {
3146 exit_status_set_free(status_set);
3150 FOREACH_WORD(word, l, rvalue, state) {
3151 _cleanup_free_ char *temp;
3154 temp = strndup(word, l);
3158 r = safe_atoi(temp, &val);
3160 val = signal_from_string_try_harder(temp);
3163 log_syntax(unit, LOG_ERR, filename, line, -val,
3164 "Failed to parse value, ignoring: %s", word);
3168 if (val < 0 || val > 255) {
3169 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3170 "Value %d is outside range 0-255, ignoring", val);
3175 r = set_ensure_allocated(&status_set->status, NULL);
3179 r = set_put(status_set->status, INT_TO_PTR(val));
3181 log_syntax(unit, LOG_ERR, filename, line, -r,
3182 "Unable to store: %s", word);
3186 if (!isempty(state))
3187 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3188 "Trailing garbage, ignoring.");
3193 int config_parse_namespace_path_strv(
3195 const char *filename,
3197 const char *section,
3198 unsigned section_line,
3206 const char *word, *state;
3215 if (isempty(rvalue)) {
3216 /* Empty assignment resets the list */
3222 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3223 _cleanup_free_ char *n;
3226 n = strndup(word, l);
3230 if (!utf8_is_valid(n)) {
3231 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3235 offset = n[0] == '-';
3236 if (!path_is_absolute(n + offset)) {
3237 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3238 "Not an absolute path, ignoring: %s", rvalue);
3242 path_kill_slashes(n);
3244 r = strv_push(sv, n);
3250 if (!isempty(state))
3251 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3252 "Trailing garbage, ignoring.");
3257 int config_parse_no_new_privileges(
3259 const char *filename,
3261 const char *section,
3262 unsigned section_line,
3269 ExecContext *c = data;
3277 k = parse_boolean(rvalue);
3279 log_syntax(unit, LOG_ERR, filename, line, -k,
3280 "Failed to parse boolean value, ignoring: %s", rvalue);
3284 c->no_new_privileges = !!k;
3285 c->no_new_privileges_set = true;
3290 int config_parse_protect_home(
3292 const char *filename,
3294 const char *section,
3295 unsigned section_line,
3302 ExecContext *c = data;
3310 /* Our enum shall be a superset of booleans, hence first try
3311 * to parse as as boolean, and then as enum */
3313 k = parse_boolean(rvalue);
3315 c->protect_home = PROTECT_HOME_YES;
3317 c->protect_home = PROTECT_HOME_NO;
3321 h = protect_home_from_string(rvalue);
3323 log_syntax(unit, LOG_ERR, filename, line, -h,
3324 "Failed to parse protect home value, ignoring: %s", rvalue);
3328 c->protect_home = h;
3334 int config_parse_protect_system(
3336 const char *filename,
3338 const char *section,
3339 unsigned section_line,
3346 ExecContext *c = data;
3354 /* Our enum shall be a superset of booleans, hence first try
3355 * to parse as as boolean, and then as enum */
3357 k = parse_boolean(rvalue);
3359 c->protect_system = PROTECT_SYSTEM_YES;
3361 c->protect_system = PROTECT_SYSTEM_NO;
3365 s = protect_system_from_string(rvalue);
3367 log_syntax(unit, LOG_ERR, filename, line, -s,
3368 "Failed to parse protect system value, ignoring: %s", rvalue);
3372 c->protect_system = s;
3378 #define FOLLOW_MAX 8
3380 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3391 /* This will update the filename pointer if the loaded file is
3392 * reached by a symlink. The old string will be freed. */
3395 char *target, *name;
3397 if (c++ >= FOLLOW_MAX)
3400 path_kill_slashes(*filename);
3402 /* Add the file name we are currently looking at to
3403 * the names of this unit, but only if it is a valid
3405 name = basename(*filename);
3407 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3409 id = set_get(names, name);
3415 r = set_consume(names, id);
3421 /* Try to open the file name, but don't if its a symlink */
3422 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3429 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3430 r = readlink_and_make_absolute(*filename, &target);
3438 f = fdopen(fd, "re");
3450 static int merge_by_names(Unit **u, Set *names, const char *id) {
3458 /* Let's try to add in all symlink names we found */
3459 while ((k = set_steal_first(names))) {
3461 /* First try to merge in the other name into our
3463 r = unit_merge_by_name(*u, k);
3467 /* Hmm, we couldn't merge the other unit into
3468 * ours? Then let's try it the other way
3471 other = manager_get_unit((*u)->manager, k);
3475 r = unit_merge(other, *u);
3478 return merge_by_names(u, names, NULL);
3486 unit_choose_id(*u, id);
3494 static int load_from_path(Unit *u, const char *path) {
3496 _cleanup_set_free_free_ Set *symlink_names = NULL;
3497 _cleanup_fclose_ FILE *f = NULL;
3498 _cleanup_free_ char *filename = NULL;
3506 symlink_names = set_new(&string_hash_ops);
3510 if (path_is_absolute(path)) {
3512 filename = strdup(path);
3516 r = open_follow(&filename, &f, symlink_names, &id);
3528 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3530 /* Instead of opening the path right away, we manually
3531 * follow all symlinks and add their name to our unit
3532 * name set while doing so */
3533 filename = path_make_absolute(path, *p);
3537 if (u->manager->unit_path_cache &&
3538 !set_get(u->manager->unit_path_cache, filename))
3541 r = open_follow(&filename, &f, symlink_names, &id);
3550 /* Empty the symlink names for the next run */
3551 set_clear_free(symlink_names);
3560 /* Hmm, no suitable file found? */
3564 r = merge_by_names(&merged, symlink_names, id);
3569 u->load_state = UNIT_MERGED;
3573 if (fstat(fileno(f), &st) < 0)
3576 if (null_or_empty(&st))
3577 u->load_state = UNIT_MASKED;
3579 u->load_state = UNIT_LOADED;
3581 /* Now, parse the file contents */
3582 r = config_parse(u->id, filename, f,
3583 UNIT_VTABLE(u)->sections,
3584 config_item_perf_lookup, load_fragment_gperf_lookup,
3585 false, true, false, u);
3590 free(u->fragment_path);
3591 u->fragment_path = filename;
3594 u->fragment_mtime = timespec_load(&st.st_mtim);
3596 if (u->source_path) {
3597 if (stat(u->source_path, &st) >= 0)
3598 u->source_mtime = timespec_load(&st.st_mtim);
3600 u->source_mtime = 0;
3606 int unit_load_fragment(Unit *u) {
3612 assert(u->load_state == UNIT_STUB);
3615 /* First, try to find the unit under its id. We always look
3616 * for unit files in the default directories, to make it easy
3617 * to override things by placing things in /etc/systemd/system */
3618 r = load_from_path(u, u->id);
3622 /* Try to find an alias we can load this with */
3623 if (u->load_state == UNIT_STUB) {
3624 SET_FOREACH(t, u->names, i) {
3629 r = load_from_path(u, t);
3633 if (u->load_state != UNIT_STUB)
3638 /* And now, try looking for it under the suggested (originally linked) path */
3639 if (u->load_state == UNIT_STUB && u->fragment_path) {
3641 r = load_from_path(u, u->fragment_path);
3645 if (u->load_state == UNIT_STUB) {
3646 /* Hmm, this didn't work? Then let's get rid
3647 * of the fragment path stored for us, so that
3648 * we don't point to an invalid location. */
3649 free(u->fragment_path);
3650 u->fragment_path = NULL;
3654 /* Look for a template */
3655 if (u->load_state == UNIT_STUB && u->instance) {
3656 _cleanup_free_ char *k;
3658 k = unit_name_template(u->id);
3662 r = load_from_path(u, k);
3666 if (u->load_state == UNIT_STUB) {
3667 SET_FOREACH(t, u->names, i) {
3668 _cleanup_free_ char *z = NULL;
3673 z = unit_name_template(t);
3677 r = load_from_path(u, z);
3681 if (u->load_state != UNIT_STUB)
3690 void unit_dump_config_items(FILE *f) {
3691 static const struct {
3692 const ConfigParserCallback callback;
3695 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3696 { config_parse_warn_compat, "NOTSUPPORTED" },
3698 { config_parse_int, "INTEGER" },
3699 { config_parse_unsigned, "UNSIGNED" },
3700 { config_parse_iec_size, "SIZE" },
3701 { config_parse_iec_off, "SIZE" },
3702 { config_parse_si_size, "SIZE" },
3703 { config_parse_bool, "BOOLEAN" },
3704 { config_parse_string, "STRING" },
3705 { config_parse_path, "PATH" },
3706 { config_parse_unit_path_printf, "PATH" },
3707 { config_parse_strv, "STRING [...]" },
3708 { config_parse_exec_nice, "NICE" },
3709 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3710 { config_parse_exec_io_class, "IOCLASS" },
3711 { config_parse_exec_io_priority, "IOPRIORITY" },
3712 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3713 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3714 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3715 { config_parse_mode, "MODE" },
3716 { config_parse_unit_env_file, "FILE" },
3717 { config_parse_output, "OUTPUT" },
3718 { config_parse_input, "INPUT" },
3719 { config_parse_log_facility, "FACILITY" },
3720 { config_parse_log_level, "LEVEL" },
3721 { config_parse_exec_capabilities, "CAPABILITIES" },
3722 { config_parse_exec_secure_bits, "SECUREBITS" },
3723 { config_parse_bounding_set, "BOUNDINGSET" },
3724 { config_parse_limit, "LIMIT" },
3725 { config_parse_unit_deps, "UNIT [...]" },
3726 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3727 { config_parse_service_type, "SERVICETYPE" },
3728 { config_parse_service_restart, "SERVICERESTART" },
3729 #ifdef HAVE_SYSV_COMPAT
3730 { config_parse_sysv_priority, "SYSVPRIORITY" },
3732 { config_parse_kill_mode, "KILLMODE" },
3733 { config_parse_kill_signal, "SIGNAL" },
3734 { config_parse_socket_listen, "SOCKET [...]" },
3735 { config_parse_socket_bind, "SOCKETBIND" },
3736 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3737 { config_parse_sec, "SECONDS" },
3738 { config_parse_nsec, "NANOSECONDS" },
3739 { config_parse_namespace_path_strv, "PATH [...]" },
3740 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3741 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3742 { config_parse_unit_string_printf, "STRING" },
3743 { config_parse_trigger_unit, "UNIT" },
3744 { config_parse_timer, "TIMER" },
3745 { config_parse_path_spec, "PATH" },
3746 { config_parse_notify_access, "ACCESS" },
3747 { config_parse_ip_tos, "TOS" },
3748 { config_parse_unit_condition_path, "CONDITION" },
3749 { config_parse_unit_condition_string, "CONDITION" },
3750 { config_parse_unit_condition_null, "CONDITION" },
3751 { config_parse_unit_slice, "SLICE" },
3752 { config_parse_documentation, "URL" },
3753 { config_parse_service_timeout, "SECONDS" },
3754 { config_parse_failure_action, "ACTION" },
3755 { config_parse_set_status, "STATUS" },
3756 { config_parse_service_sockets, "SOCKETS" },
3757 { config_parse_environ, "ENVIRON" },
3759 { config_parse_syscall_filter, "SYSCALLS" },
3760 { config_parse_syscall_archs, "ARCHS" },
3761 { config_parse_syscall_errno, "ERRNO" },
3762 { config_parse_address_families, "FAMILIES" },
3764 { config_parse_cpu_shares, "SHARES" },
3765 { config_parse_memory_limit, "LIMIT" },
3766 { config_parse_device_allow, "DEVICE" },
3767 { config_parse_device_policy, "POLICY" },
3768 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3769 { config_parse_blockio_weight, "WEIGHT" },
3770 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3771 { config_parse_long, "LONG" },
3772 { config_parse_socket_service, "SERVICE" },
3774 { config_parse_exec_selinux_context, "LABEL" },
3776 { config_parse_job_mode, "MODE" },
3777 { config_parse_job_mode_isolate, "BOOLEAN" },
3778 { config_parse_personality, "PERSONALITY" },
3781 const char *prev = NULL;
3786 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3787 const char *rvalue = "OTHER", *lvalue;
3791 const ConfigPerfItem *p;
3793 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3795 dot = strchr(i, '.');
3796 lvalue = dot ? dot + 1 : i;
3800 if (!prev || !strneq(prev, i, prefix_len+1)) {
3804 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3807 for (j = 0; j < ELEMENTSOF(table); j++)
3808 if (p->parse == table[j].callback) {
3809 rvalue = table[j].rvalue;
3813 fprintf(f, "%s=%s\n", lvalue, rvalue);