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 n = new(char*, k + !separate_argv0);
597 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
601 if (separate_argv0 ? path == NULL : k == 0) {
602 /* first word, very special */
603 skip = separate_argv0 + ignore;
605 /* skip special chars in the beginning */
608 } else if (strneq(word, ";", MAX(l, 1U)))
609 /* new commandline */
613 skip = strneq(word, "\\;", MAX(l, 1U));
615 c = cunescape_length(word + skip, l - skip);
621 if (!utf8_is_valid(c)) {
622 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
627 /* where to stuff this? */
628 if (separate_argv0 && path == NULL)
636 log_debug("path: %s", path ?: n[0]);
639 reason = "Empty executable name or zeroeth argument";
640 else if (!string_is_safe(path ?: n[0]))
641 reason = "Executable path contains special characters";
642 else if (!path_is_absolute(path ?: n[0]))
643 reason = "Executable path is not absolute";
644 else if (endswith(path ?: n[0], "/"))
645 reason = "Executable path specifies a directory";
649 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
650 "%s, ignoring: %s", reason, rvalue);
663 nce = new0(ExecCommand, 1);
671 nce->ignore = ignore;
673 path_kill_slashes(nce->path);
675 exec_command_append_list(e, nce);
691 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
692 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
694 int config_parse_socket_bindtodevice(const char* unit,
695 const char *filename,
698 unsigned section_line,
713 if (rvalue[0] && !streq(rvalue, "*")) {
720 free(s->bind_to_device);
721 s->bind_to_device = n;
726 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
727 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
729 int config_parse_exec_io_class(const char *unit,
730 const char *filename,
733 unsigned section_line,
740 ExecContext *c = data;
748 x = ioprio_class_from_string(rvalue);
750 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
751 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
755 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
756 c->ioprio_set = true;
761 int config_parse_exec_io_priority(const char *unit,
762 const char *filename,
765 unsigned section_line,
772 ExecContext *c = data;
780 r = safe_atoi(rvalue, &i);
781 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
782 log_syntax(unit, LOG_ERR, filename, line, -r,
783 "Failed to parse IO priority, ignoring: %s", rvalue);
787 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
788 c->ioprio_set = true;
793 int config_parse_exec_cpu_sched_policy(const char *unit,
794 const char *filename,
797 unsigned section_line,
805 ExecContext *c = data;
813 x = sched_policy_from_string(rvalue);
815 log_syntax(unit, LOG_ERR, filename, line, -x,
816 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
820 c->cpu_sched_policy = x;
821 /* Moving to or from real-time policy? We need to adjust the priority */
822 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
823 c->cpu_sched_set = true;
828 int config_parse_exec_cpu_sched_prio(const char *unit,
829 const char *filename,
832 unsigned section_line,
839 ExecContext *c = data;
847 r = safe_atoi(rvalue, &i);
849 log_syntax(unit, LOG_ERR, filename, line, -r,
850 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
854 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
855 min = sched_get_priority_min(c->cpu_sched_policy);
856 max = sched_get_priority_max(c->cpu_sched_policy);
858 if (i < min || i > max) {
859 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
860 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
864 c->cpu_sched_priority = i;
865 c->cpu_sched_set = true;
870 int config_parse_exec_cpu_affinity(const char *unit,
871 const char *filename,
874 unsigned section_line,
881 ExecContext *c = data;
882 const char *word, *state;
890 if (isempty(rvalue)) {
891 /* An empty assignment resets the CPU list */
898 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
899 _cleanup_free_ char *t = NULL;
903 t = strndup(word, l);
907 r = safe_atou(t, &cpu);
910 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
915 if (r < 0 || cpu >= c->cpuset_ncpus) {
916 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
917 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
921 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
924 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
925 "Trailing garbage, ignoring.");
930 int config_parse_exec_capabilities(const char *unit,
931 const char *filename,
934 unsigned section_line,
941 ExecContext *c = data;
949 cap = cap_from_text(rvalue);
951 log_syntax(unit, LOG_ERR, filename, line, errno,
952 "Failed to parse capabilities, ignoring: %s", rvalue);
957 cap_free(c->capabilities);
958 c->capabilities = cap;
963 int config_parse_exec_secure_bits(const char *unit,
964 const char *filename,
967 unsigned section_line,
974 ExecContext *c = data;
976 const char *word, *state;
983 if (isempty(rvalue)) {
984 /* An empty assignment resets the field */
989 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
990 if (first_word(word, "keep-caps"))
991 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
992 else if (first_word(word, "keep-caps-locked"))
993 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
994 else if (first_word(word, "no-setuid-fixup"))
995 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
996 else if (first_word(word, "no-setuid-fixup-locked"))
997 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
998 else if (first_word(word, "noroot"))
999 c->secure_bits |= 1<<SECURE_NOROOT;
1000 else if (first_word(word, "noroot-locked"))
1001 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
1003 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1004 "Failed to parse secure bits, ignoring: %s", rvalue);
1008 if (!isempty(state))
1009 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1010 "Invalid syntax, garbage at the end, ignoring.");
1015 int config_parse_bounding_set(const char *unit,
1016 const char *filename,
1018 const char *section,
1019 unsigned section_line,
1026 uint64_t *capability_bounding_set_drop = data;
1027 const char *word, *state;
1029 bool invert = false;
1037 if (rvalue[0] == '~') {
1042 /* Note that we store this inverted internally, since the
1043 * kernel wants it like this. But we actually expose it
1044 * non-inverted everywhere to have a fully normalized
1047 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1048 _cleanup_free_ char *t = NULL;
1051 t = strndup(word, l);
1055 cap = capability_from_name(t);
1057 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
1061 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1063 if (!isempty(state))
1064 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1065 "Trailing garbage, ignoring.");
1068 *capability_bounding_set_drop |= sum;
1070 *capability_bounding_set_drop |= ~sum;
1075 int config_parse_limit(const char *unit,
1076 const char *filename,
1078 const char *section,
1079 unsigned section_line,
1086 struct rlimit **rl = data;
1087 unsigned long long u;
1096 if (streq(rvalue, "infinity"))
1097 u = (unsigned long long) RLIM_INFINITY;
1101 r = safe_atollu(rvalue, &u);
1103 log_syntax(unit, LOG_ERR, filename, line, -r,
1104 "Failed to parse resource value, ignoring: %s", rvalue);
1110 *rl = new(struct rlimit, 1);
1115 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1119 #ifdef HAVE_SYSV_COMPAT
1120 int config_parse_sysv_priority(const char *unit,
1121 const char *filename,
1123 const char *section,
1124 unsigned section_line,
1131 int *priority = data;
1139 r = safe_atoi(rvalue, &i);
1140 if (r < 0 || i < 0) {
1141 log_syntax(unit, LOG_ERR, filename, line, -r,
1142 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1146 *priority = (int) i;
1151 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1153 int config_parse_kill_signal(const char *unit,
1154 const char *filename,
1156 const char *section,
1157 unsigned section_line,
1172 r = signal_from_string_try_harder(rvalue);
1174 log_syntax(unit, LOG_ERR, filename, line, -r,
1175 "Failed to parse kill signal, ignoring: %s", rvalue);
1183 int config_parse_exec_mount_flags(const char *unit,
1184 const char *filename,
1186 const char *section,
1187 unsigned section_line,
1194 ExecContext *c = data;
1195 const char *word, *state;
1197 unsigned long flags = 0;
1204 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1205 _cleanup_free_ char *t;
1207 t = strndup(word, l);
1211 if (streq(t, "shared"))
1213 else if (streq(t, "slave"))
1215 else if (streq(word, "private"))
1218 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1219 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1223 if (!isempty(state))
1224 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1225 "Trailing garbage, ignoring.");
1227 c->mount_flags = flags;
1231 int config_parse_exec_selinux_context(
1233 const char *filename,
1235 const char *section,
1236 unsigned section_line,
1243 ExecContext *c = data;
1254 if (isempty(rvalue)) {
1255 free(c->selinux_context);
1256 c->selinux_context = NULL;
1257 c->selinux_context_ignore = false;
1261 if (rvalue[0] == '-') {
1267 r = unit_name_printf(u, rvalue, &k);
1269 log_syntax(unit, LOG_ERR, filename, line, -r,
1270 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1274 free(c->selinux_context);
1275 c->selinux_context = k;
1276 c->selinux_context_ignore = ignore;
1281 int config_parse_exec_apparmor_profile(
1283 const char *filename,
1285 const char *section,
1286 unsigned section_line,
1293 ExecContext *c = data;
1304 if (isempty(rvalue)) {
1305 free(c->apparmor_profile);
1306 c->apparmor_profile = NULL;
1307 c->apparmor_profile_ignore = false;
1311 if (rvalue[0] == '-') {
1317 r = unit_name_printf(u, rvalue, &k);
1319 log_syntax(unit, LOG_ERR, filename, line, -r,
1320 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1324 free(c->apparmor_profile);
1325 c->apparmor_profile = k;
1326 c->apparmor_profile_ignore = ignore;
1331 int config_parse_exec_smack_process_label(
1333 const char *filename,
1335 const char *section,
1336 unsigned section_line,
1343 ExecContext *c = data;
1354 if (isempty(rvalue)) {
1355 free(c->smack_process_label);
1356 c->smack_process_label = NULL;
1357 c->smack_process_label_ignore = false;
1361 if (rvalue[0] == '-') {
1367 r = unit_name_printf(u, rvalue, &k);
1369 log_syntax(unit, LOG_ERR, filename, line, -r,
1370 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1374 free(c->smack_process_label);
1375 c->smack_process_label = k;
1376 c->smack_process_label_ignore = ignore;
1381 int config_parse_timer(const char *unit,
1382 const char *filename,
1384 const char *section,
1385 unsigned section_line,
1396 CalendarSpec *c = NULL;
1403 if (isempty(rvalue)) {
1404 /* Empty assignment resets list */
1405 timer_free_values(t);
1409 b = timer_base_from_string(lvalue);
1411 log_syntax(unit, LOG_ERR, filename, line, -b,
1412 "Failed to parse timer base, ignoring: %s", lvalue);
1416 if (b == TIMER_CALENDAR) {
1417 if (calendar_spec_from_string(rvalue, &c) < 0) {
1418 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1419 "Failed to parse calendar specification, ignoring: %s",
1424 if (parse_sec(rvalue, &u) < 0) {
1425 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1426 "Failed to parse timer value, ignoring: %s",
1432 v = new0(TimerValue, 1);
1434 calendar_spec_free(c);
1440 v->calendar_spec = c;
1442 LIST_PREPEND(value, t->values, v);
1447 int config_parse_trigger_unit(
1449 const char *filename,
1451 const char *section,
1452 unsigned section_line,
1459 _cleanup_free_ char *p = NULL;
1469 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1470 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1471 "Multiple units to trigger specified, ignoring: %s", rvalue);
1475 r = unit_name_printf(u, rvalue, &p);
1477 log_syntax(unit, LOG_ERR, filename, line, -r,
1478 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1480 type = unit_name_to_type(p ?: rvalue);
1482 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1483 "Unit type not valid, ignoring: %s", rvalue);
1487 if (type == u->type) {
1488 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1489 "Trigger cannot be of same type, ignoring: %s", rvalue);
1493 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1495 log_syntax(unit, LOG_ERR, filename, line, -r,
1496 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1503 int config_parse_path_spec(const char *unit,
1504 const char *filename,
1506 const char *section,
1507 unsigned section_line,
1517 _cleanup_free_ char *k = NULL;
1525 if (isempty(rvalue)) {
1526 /* Empty assignment clears list */
1531 b = path_type_from_string(lvalue);
1533 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1534 "Failed to parse path type, ignoring: %s", lvalue);
1538 r = unit_full_printf(UNIT(p), rvalue, &k);
1544 log_syntax(unit, LOG_ERR, filename, line, -r,
1545 "Failed to resolve unit specifiers on %s. Ignoring.",
1549 if (!path_is_absolute(k)) {
1550 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1551 "Path is not absolute, ignoring: %s", k);
1555 s = new0(PathSpec, 1);
1560 s->path = path_kill_slashes(k);
1565 LIST_PREPEND(spec, p->specs, s);
1570 int config_parse_socket_service(
1572 const char *filename,
1574 const char *section,
1575 unsigned section_line,
1582 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1586 _cleanup_free_ char *p = NULL;
1593 r = unit_name_printf(UNIT(s), rvalue, &p);
1595 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1599 if (!endswith(p, ".service")) {
1600 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1604 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1606 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1610 unit_ref_set(&s->service, x);
1615 int config_parse_service_sockets(
1617 const char *filename,
1619 const char *section,
1620 unsigned section_line,
1628 const char *word, *state;
1637 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1638 _cleanup_free_ char *t = NULL, *k = NULL;
1640 t = strndup(word, l);
1644 r = unit_name_printf(UNIT(s), t, &k);
1646 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1650 if (!endswith(k, ".socket")) {
1651 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type socket, ignoring: %s", k);
1655 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1657 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1659 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1661 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1663 if (!isempty(state))
1664 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
1669 int config_parse_bus_name(
1671 const char *filename,
1673 const char *section,
1674 unsigned section_line,
1681 _cleanup_free_ char *k = NULL;
1690 r = unit_full_printf(u, rvalue, &k);
1692 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
1696 if (!service_name_is_valid(k)) {
1697 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bus name %s, ignoring.", k);
1701 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
1704 int config_parse_service_timeout(const char *unit,
1705 const char *filename,
1707 const char *section,
1708 unsigned section_line,
1715 Service *s = userdata;
1723 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1724 rvalue, data, userdata);
1728 if (streq(lvalue, "TimeoutSec")) {
1729 s->start_timeout_defined = true;
1730 s->timeout_stop_usec = s->timeout_start_usec;
1731 } else if (streq(lvalue, "TimeoutStartSec"))
1732 s->start_timeout_defined = true;
1737 int config_parse_busname_service(
1739 const char *filename,
1741 const char *section,
1742 unsigned section_line,
1749 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1753 _cleanup_free_ char *p = NULL;
1760 r = unit_name_printf(UNIT(n), rvalue, &p);
1762 log_syntax(unit, LOG_ERR, filename, line, -r,
1763 "Failed to resolve specifiers, ignoring: %s", rvalue);
1767 if (!endswith(p, ".service")) {
1768 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1769 "Unit must be of type service, ignoring: %s", rvalue);
1773 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1775 log_syntax(unit, LOG_ERR, filename, line, -r,
1776 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1780 unit_ref_set(&n->service, x);
1785 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1787 int config_parse_bus_policy(
1789 const char *filename,
1791 const char *section,
1792 unsigned section_line,
1799 _cleanup_free_ BusNamePolicy *p = NULL;
1800 _cleanup_free_ char *id_str = NULL;
1801 BusName *busname = data;
1809 p = new0(BusNamePolicy, 1);
1813 if (streq(lvalue, "AllowUser"))
1814 p->type = BUSNAME_POLICY_TYPE_USER;
1815 else if (streq(lvalue, "AllowGroup"))
1816 p->type = BUSNAME_POLICY_TYPE_GROUP;
1818 assert_not_reached("Unknown lvalue");
1820 id_str = strdup(rvalue);
1824 access_str = strpbrk(id_str, WHITESPACE);
1826 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1827 "Invalid busname policy value '%s'", rvalue);
1833 access_str += strspn(access_str, WHITESPACE);
1835 p->access = bus_policy_access_from_string(access_str);
1836 if (p->access < 0) {
1837 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1838 "Invalid busname policy access type '%s'", access_str);
1845 LIST_PREPEND(policy, busname->policy, p);
1851 int config_parse_bus_endpoint_policy(
1853 const char *filename,
1855 const char *section,
1856 unsigned section_line,
1863 _cleanup_free_ char *name = NULL;
1864 BusPolicyAccess access;
1865 ExecContext *c = data;
1874 name = strdup(rvalue);
1878 access_str = strpbrk(name, WHITESPACE);
1880 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1881 "Invalid endpoint policy value '%s'", rvalue);
1887 access_str += strspn(access_str, WHITESPACE);
1889 access = bus_policy_access_from_string(access_str);
1890 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1891 access >= _BUS_POLICY_ACCESS_MAX) {
1892 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1893 "Invalid endpoint policy access type '%s'", access_str);
1897 if (!c->bus_endpoint) {
1898 r = bus_endpoint_new(&c->bus_endpoint);
1904 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1907 int config_parse_unit_env_file(const char *unit,
1908 const char *filename,
1910 const char *section,
1911 unsigned section_line,
1920 _cleanup_free_ char *n = NULL;
1929 if (isempty(rvalue)) {
1930 /* Empty assignment frees the list */
1936 r = unit_full_printf(u, rvalue, &n);
1938 log_syntax(unit, LOG_ERR, filename, line, -r,
1939 "Failed to resolve specifiers, ignoring: %s", rvalue);
1942 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1943 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1944 "Path '%s' is not absolute, ignoring.", s);
1948 r = strv_extend(env, s);
1955 int config_parse_environ(const char *unit,
1956 const char *filename,
1958 const char *section,
1959 unsigned section_line,
1968 const char *word, *state;
1970 _cleanup_free_ char *k = NULL;
1978 if (isempty(rvalue)) {
1979 /* Empty assignment resets the list */
1986 r = unit_full_printf(u, rvalue, &k);
1988 log_syntax(unit, LOG_ERR, filename, line, -r,
1989 "Failed to resolve specifiers, ignoring: %s", rvalue);
1997 FOREACH_WORD_QUOTED(word, l, k, state) {
1998 _cleanup_free_ char *n;
2001 n = cunescape_length(word, l);
2005 if (!env_assignment_is_valid(n)) {
2006 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2007 "Invalid environment assignment, ignoring: %s", rvalue);
2011 x = strv_env_set(*env, n);
2018 if (!isempty(state))
2019 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2020 "Trailing garbage, ignoring.");
2025 int config_parse_ip_tos(const char *unit,
2026 const char *filename,
2028 const char *section,
2029 unsigned section_line,
2036 int *ip_tos = data, x;
2043 x = ip_tos_from_string(rvalue);
2045 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2046 "Failed to parse IP TOS value, ignoring: %s", rvalue);
2054 int config_parse_unit_condition_path(
2056 const char *filename,
2058 const char *section,
2059 unsigned section_line,
2066 _cleanup_free_ char *p = NULL;
2067 Condition **list = data, *c;
2068 ConditionType t = ltype;
2069 bool trigger, negate;
2078 if (isempty(rvalue)) {
2079 /* Empty assignment resets the list */
2080 *list = condition_free_list(*list);
2084 trigger = rvalue[0] == '|';
2088 negate = rvalue[0] == '!';
2092 r = unit_full_printf(u, rvalue, &p);
2094 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2098 if (!path_is_absolute(p)) {
2099 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2103 c = condition_new(t, p, trigger, negate);
2107 LIST_PREPEND(conditions, *list, c);
2111 int config_parse_unit_condition_string(
2113 const char *filename,
2115 const char *section,
2116 unsigned section_line,
2123 _cleanup_free_ char *s = NULL;
2124 Condition **list = data, *c;
2125 ConditionType t = ltype;
2126 bool trigger, negate;
2135 if (isempty(rvalue)) {
2136 /* Empty assignment resets the list */
2137 *list = condition_free_list(*list);
2141 trigger = rvalue[0] == '|';
2145 negate = rvalue[0] == '!';
2149 r = unit_full_printf(u, rvalue, &s);
2151 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2155 c = condition_new(t, s, trigger, negate);
2159 LIST_PREPEND(conditions, *list, c);
2163 int config_parse_unit_condition_null(
2165 const char *filename,
2167 const char *section,
2168 unsigned section_line,
2175 Condition **list = data, *c;
2176 bool trigger, negate;
2184 if (isempty(rvalue)) {
2185 /* Empty assignment resets the list */
2186 *list = condition_free_list(*list);
2190 trigger = rvalue[0] == '|';
2194 negate = rvalue[0] == '!';
2198 b = parse_boolean(rvalue);
2200 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2207 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2211 LIST_PREPEND(conditions, *list, c);
2215 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2216 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2218 int config_parse_unit_requires_mounts_for(
2220 const char *filename,
2222 const char *section,
2223 unsigned section_line,
2231 const char *word, *state;
2239 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2241 _cleanup_free_ char *n;
2243 n = strndup(word, l);
2247 if (!utf8_is_valid(n)) {
2248 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2252 r = unit_require_mounts_for(u, n);
2254 log_syntax(unit, LOG_ERR, filename, line, -r,
2255 "Failed to add required mount for, ignoring: %s", rvalue);
2259 if (!isempty(state))
2260 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2261 "Trailing garbage, ignoring.");
2266 int config_parse_documentation(const char *unit,
2267 const char *filename,
2269 const char *section,
2270 unsigned section_line,
2286 if (isempty(rvalue)) {
2287 /* Empty assignment resets the list */
2288 strv_free(u->documentation);
2289 u->documentation = NULL;
2293 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2294 rvalue, data, userdata);
2298 for (a = b = u->documentation; a && *a; a++) {
2300 if (is_valid_documentation_url(*a))
2303 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2304 "Invalid URL, ignoring: %s", *a);
2315 int config_parse_syscall_filter(
2317 const char *filename,
2319 const char *section,
2320 unsigned section_line,
2327 static const char default_syscalls[] =
2334 ExecContext *c = data;
2336 bool invert = false;
2337 const char *word, *state;
2346 if (isempty(rvalue)) {
2347 /* Empty assignment resets the list */
2348 set_free(c->syscall_filter);
2349 c->syscall_filter = NULL;
2350 c->syscall_whitelist = false;
2354 if (rvalue[0] == '~') {
2359 if (!c->syscall_filter) {
2360 c->syscall_filter = set_new(NULL);
2361 if (!c->syscall_filter)
2365 /* Allow everything but the ones listed */
2366 c->syscall_whitelist = false;
2370 /* Allow nothing but the ones listed */
2371 c->syscall_whitelist = true;
2373 /* Accept default syscalls if we are on a whitelist */
2374 NULSTR_FOREACH(i, default_syscalls) {
2377 id = seccomp_syscall_resolve_name(i);
2381 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2390 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2391 _cleanup_free_ char *t = NULL;
2394 t = strndup(word, l);
2398 id = seccomp_syscall_resolve_name(t);
2400 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2401 "Failed to parse system call, ignoring: %s", t);
2405 /* If we previously wanted to forbid a syscall and now
2406 * we want to allow it, then remove it from the list
2408 if (!invert == c->syscall_whitelist) {
2409 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2415 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2417 if (!isempty(state))
2418 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2419 "Trailing garbage, ignoring.");
2421 /* Turn on NNP, but only if it wasn't configured explicitly
2422 * before, and only if we are in user mode. */
2423 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2424 c->no_new_privileges = true;
2429 int config_parse_syscall_archs(
2431 const char *filename,
2433 const char *section,
2434 unsigned section_line,
2442 const char *word, *state;
2446 if (isempty(rvalue)) {
2452 r = set_ensure_allocated(archs, NULL);
2456 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2457 _cleanup_free_ char *t = NULL;
2460 t = strndup(word, l);
2464 r = seccomp_arch_from_string(t, &a);
2466 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2467 "Failed to parse system call architecture, ignoring: %s", t);
2471 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2477 if (!isempty(state))
2478 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2479 "Trailing garbage, ignoring.");
2484 int config_parse_syscall_errno(
2486 const char *filename,
2488 const char *section,
2489 unsigned section_line,
2496 ExecContext *c = data;
2503 if (isempty(rvalue)) {
2504 /* Empty assignment resets to KILL */
2505 c->syscall_errno = 0;
2509 e = errno_from_name(rvalue);
2511 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2512 "Failed to parse error number, ignoring: %s", rvalue);
2516 c->syscall_errno = e;
2520 int config_parse_address_families(
2522 const char *filename,
2524 const char *section,
2525 unsigned section_line,
2532 ExecContext *c = data;
2533 bool invert = false;
2534 const char *word, *state;
2542 if (isempty(rvalue)) {
2543 /* Empty assignment resets the list */
2544 set_free(c->address_families);
2545 c->address_families = NULL;
2546 c->address_families_whitelist = false;
2550 if (rvalue[0] == '~') {
2555 if (!c->address_families) {
2556 c->address_families = set_new(NULL);
2557 if (!c->address_families)
2560 c->address_families_whitelist = !invert;
2563 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2564 _cleanup_free_ char *t = NULL;
2567 t = strndup(word, l);
2571 af = af_from_name(t);
2573 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2574 "Failed to parse address family, ignoring: %s", t);
2578 /* If we previously wanted to forbid an address family and now
2579 * we want to allow it, then remove it from the list
2581 if (!invert == c->address_families_whitelist) {
2582 r = set_put(c->address_families, INT_TO_PTR(af));
2588 set_remove(c->address_families, INT_TO_PTR(af));
2590 if (!isempty(state))
2591 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2592 "Trailing garbage, ignoring.");
2598 int config_parse_unit_slice(
2600 const char *filename,
2602 const char *section,
2603 unsigned section_line,
2610 _cleanup_free_ char *k = NULL;
2611 Unit *u = userdata, *slice;
2619 r = unit_name_printf(u, rvalue, &k);
2621 log_syntax(unit, LOG_ERR, filename, line, -r,
2622 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2629 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2631 log_syntax(unit, LOG_ERR, filename, line, -r,
2632 "Failed to load slice unit %s. Ignoring.", k);
2636 if (slice->type != UNIT_SLICE) {
2637 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2638 "Slice unit %s is not a slice. Ignoring.", k);
2642 unit_ref_set(&u->slice, slice);
2646 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2648 int config_parse_cpu_shares(
2650 const char *filename,
2652 const char *section,
2653 unsigned section_line,
2660 unsigned long *shares = data, lu;
2667 if (isempty(rvalue)) {
2668 *shares = (unsigned long) -1;
2672 r = safe_atolu(rvalue, &lu);
2673 if (r < 0 || lu <= 0) {
2674 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2675 "CPU shares '%s' invalid. Ignoring.", rvalue);
2683 int config_parse_cpu_quota(
2685 const char *filename,
2687 const char *section,
2688 unsigned section_line,
2695 CGroupContext *c = data;
2702 if (isempty(rvalue)) {
2703 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2707 if (!endswith(rvalue, "%")) {
2709 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2710 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2714 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2715 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2716 "CPU quota '%s' invalid. Ignoring.", rvalue);
2720 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2725 int config_parse_memory_limit(
2727 const char *filename,
2729 const char *section,
2730 unsigned section_line,
2737 CGroupContext *c = data;
2741 if (isempty(rvalue)) {
2742 c->memory_limit = (uint64_t) -1;
2746 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2748 r = parse_size(rvalue, 1024, &bytes);
2750 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2751 "Memory limit '%s' invalid. Ignoring.", rvalue);
2755 c->memory_limit = (uint64_t) bytes;
2759 int config_parse_device_allow(
2761 const char *filename,
2763 const char *section,
2764 unsigned section_line,
2771 _cleanup_free_ char *path = NULL;
2772 CGroupContext *c = data;
2773 CGroupDeviceAllow *a;
2777 if (isempty(rvalue)) {
2778 while (c->device_allow)
2779 cgroup_context_free_device_allow(c, c->device_allow);
2784 n = strcspn(rvalue, WHITESPACE);
2785 path = strndup(rvalue, n);
2789 if (!startswith(path, "/dev/") &&
2790 !startswith(path, "block-") &&
2791 !startswith(path, "char-")) {
2792 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2793 "Invalid device node path '%s'. Ignoring.", path);
2797 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2801 if (!in_charset(m, "rwm")) {
2802 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2803 "Invalid device rights '%s'. Ignoring.", m);
2807 a = new0(CGroupDeviceAllow, 1);
2813 a->r = !!strchr(m, 'r');
2814 a->w = !!strchr(m, 'w');
2815 a->m = !!strchr(m, 'm');
2817 LIST_PREPEND(device_allow, c->device_allow, a);
2821 int config_parse_blockio_weight(
2823 const char *filename,
2825 const char *section,
2826 unsigned section_line,
2833 unsigned long *weight = data, lu;
2840 if (isempty(rvalue)) {
2841 *weight = (unsigned long) -1;
2845 r = safe_atolu(rvalue, &lu);
2846 if (r < 0 || lu < 10 || lu > 1000) {
2847 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2848 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2856 int config_parse_blockio_device_weight(
2858 const char *filename,
2860 const char *section,
2861 unsigned section_line,
2868 _cleanup_free_ char *path = NULL;
2869 CGroupBlockIODeviceWeight *w;
2870 CGroupContext *c = data;
2880 if (isempty(rvalue)) {
2881 while (c->blockio_device_weights)
2882 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2887 n = strcspn(rvalue, WHITESPACE);
2888 weight = rvalue + n;
2890 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2891 "Expected block device and device weight. Ignoring.");
2895 path = strndup(rvalue, n);
2899 if (!path_startswith(path, "/dev")) {
2900 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2901 "Invalid device node path '%s'. Ignoring.", path);
2905 weight += strspn(weight, WHITESPACE);
2906 r = safe_atolu(weight, &lu);
2907 if (r < 0 || lu < 10 || lu > 1000) {
2908 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2909 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2913 w = new0(CGroupBlockIODeviceWeight, 1);
2922 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2926 int config_parse_blockio_bandwidth(
2928 const char *filename,
2930 const char *section,
2931 unsigned section_line,
2938 _cleanup_free_ char *path = NULL;
2939 CGroupBlockIODeviceBandwidth *b;
2940 CGroupContext *c = data;
2941 const char *bandwidth;
2951 read = streq("BlockIOReadBandwidth", lvalue);
2953 if (isempty(rvalue)) {
2954 CGroupBlockIODeviceBandwidth *next;
2956 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2957 if (b->read == read)
2958 cgroup_context_free_blockio_device_bandwidth(c, b);
2963 n = strcspn(rvalue, WHITESPACE);
2964 bandwidth = rvalue + n;
2965 bandwidth += strspn(bandwidth, WHITESPACE);
2968 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2969 "Expected space separated pair of device node and bandwidth. Ignoring.");
2973 path = strndup(rvalue, n);
2977 if (!path_startswith(path, "/dev")) {
2978 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2979 "Invalid device node path '%s'. Ignoring.", path);
2983 r = parse_size(bandwidth, 1000, &bytes);
2984 if (r < 0 || bytes <= 0) {
2985 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2986 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2990 b = new0(CGroupBlockIODeviceBandwidth, 1);
2996 b->bandwidth = (uint64_t) bytes;
2999 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
3004 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
3006 int config_parse_job_mode_isolate(
3008 const char *filename,
3010 const char *section,
3011 unsigned section_line,
3025 r = parse_boolean(rvalue);
3027 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3028 "Failed to parse boolean, ignoring: %s", rvalue);
3032 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3036 int config_parse_personality(
3038 const char *filename,
3040 const char *section,
3041 unsigned section_line,
3048 unsigned long *personality = data, p;
3053 assert(personality);
3055 p = personality_from_string(rvalue);
3056 if (p == 0xffffffffUL) {
3057 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3058 "Failed to parse personality, ignoring: %s", rvalue);
3066 int config_parse_runtime_directory(
3068 const char *filename,
3070 const char *section,
3071 unsigned section_line,
3079 const char *word, *state;
3088 if (isempty(rvalue)) {
3089 /* Empty assignment resets the list */
3095 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3096 _cleanup_free_ char *n;
3098 n = strndup(word, l);
3102 if (!filename_is_valid(n)) {
3103 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3104 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3108 r = strv_push(rt, n);
3114 if (!isempty(state))
3115 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3116 "Trailing garbage, ignoring.");
3121 int config_parse_set_status(
3123 const char *filename,
3125 const char *section,
3126 unsigned section_line,
3134 const char *word, *state;
3136 ExitStatusSet *status_set = data;
3143 /* Empty assignment resets the list */
3144 if (isempty(rvalue)) {
3145 exit_status_set_free(status_set);
3149 FOREACH_WORD(word, l, rvalue, state) {
3150 _cleanup_free_ char *temp;
3153 temp = strndup(word, l);
3157 r = safe_atoi(temp, &val);
3159 val = signal_from_string_try_harder(temp);
3162 log_syntax(unit, LOG_ERR, filename, line, -val,
3163 "Failed to parse value, ignoring: %s", word);
3167 if (val < 0 || val > 255) {
3168 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3169 "Value %d is outside range 0-255, ignoring", val);
3174 r = set_ensure_allocated(&status_set->status, NULL);
3178 r = set_put(status_set->status, INT_TO_PTR(val));
3180 log_syntax(unit, LOG_ERR, filename, line, -r,
3181 "Unable to store: %s", word);
3185 if (!isempty(state))
3186 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3187 "Trailing garbage, ignoring.");
3192 int config_parse_namespace_path_strv(
3194 const char *filename,
3196 const char *section,
3197 unsigned section_line,
3205 const char *word, *state;
3214 if (isempty(rvalue)) {
3215 /* Empty assignment resets the list */
3221 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3222 _cleanup_free_ char *n;
3225 n = strndup(word, l);
3229 if (!utf8_is_valid(n)) {
3230 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3234 offset = n[0] == '-';
3235 if (!path_is_absolute(n + offset)) {
3236 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3237 "Not an absolute path, ignoring: %s", rvalue);
3241 path_kill_slashes(n);
3243 r = strv_push(sv, n);
3249 if (!isempty(state))
3250 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3251 "Trailing garbage, ignoring.");
3256 int config_parse_no_new_privileges(
3258 const char *filename,
3260 const char *section,
3261 unsigned section_line,
3268 ExecContext *c = data;
3276 k = parse_boolean(rvalue);
3278 log_syntax(unit, LOG_ERR, filename, line, -k,
3279 "Failed to parse boolean value, ignoring: %s", rvalue);
3283 c->no_new_privileges = !!k;
3284 c->no_new_privileges_set = true;
3289 int config_parse_protect_home(
3291 const char *filename,
3293 const char *section,
3294 unsigned section_line,
3301 ExecContext *c = data;
3309 /* Our enum shall be a superset of booleans, hence first try
3310 * to parse as as boolean, and then as enum */
3312 k = parse_boolean(rvalue);
3314 c->protect_home = PROTECT_HOME_YES;
3316 c->protect_home = PROTECT_HOME_NO;
3320 h = protect_home_from_string(rvalue);
3322 log_syntax(unit, LOG_ERR, filename, line, -h,
3323 "Failed to parse protect home value, ignoring: %s", rvalue);
3327 c->protect_home = h;
3333 int config_parse_protect_system(
3335 const char *filename,
3337 const char *section,
3338 unsigned section_line,
3345 ExecContext *c = data;
3353 /* Our enum shall be a superset of booleans, hence first try
3354 * to parse as as boolean, and then as enum */
3356 k = parse_boolean(rvalue);
3358 c->protect_system = PROTECT_SYSTEM_YES;
3360 c->protect_system = PROTECT_SYSTEM_NO;
3364 s = protect_system_from_string(rvalue);
3366 log_syntax(unit, LOG_ERR, filename, line, -s,
3367 "Failed to parse protect system value, ignoring: %s", rvalue);
3371 c->protect_system = s;
3377 #define FOLLOW_MAX 8
3379 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3390 /* This will update the filename pointer if the loaded file is
3391 * reached by a symlink. The old string will be freed. */
3394 char *target, *name;
3396 if (c++ >= FOLLOW_MAX)
3399 path_kill_slashes(*filename);
3401 /* Add the file name we are currently looking at to
3402 * the names of this unit, but only if it is a valid
3404 name = basename(*filename);
3406 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3408 id = set_get(names, name);
3414 r = set_consume(names, id);
3420 /* Try to open the file name, but don't if its a symlink */
3421 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3428 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3429 r = readlink_and_make_absolute(*filename, &target);
3437 f = fdopen(fd, "re");
3449 static int merge_by_names(Unit **u, Set *names, const char *id) {
3457 /* Let's try to add in all symlink names we found */
3458 while ((k = set_steal_first(names))) {
3460 /* First try to merge in the other name into our
3462 r = unit_merge_by_name(*u, k);
3466 /* Hmm, we couldn't merge the other unit into
3467 * ours? Then let's try it the other way
3470 other = manager_get_unit((*u)->manager, k);
3474 r = unit_merge(other, *u);
3477 return merge_by_names(u, names, NULL);
3485 unit_choose_id(*u, id);
3493 static int load_from_path(Unit *u, const char *path) {
3495 _cleanup_set_free_free_ Set *symlink_names = NULL;
3496 _cleanup_fclose_ FILE *f = NULL;
3497 _cleanup_free_ char *filename = NULL;
3505 symlink_names = set_new(&string_hash_ops);
3509 if (path_is_absolute(path)) {
3511 filename = strdup(path);
3515 r = open_follow(&filename, &f, symlink_names, &id);
3527 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3529 /* Instead of opening the path right away, we manually
3530 * follow all symlinks and add their name to our unit
3531 * name set while doing so */
3532 filename = path_make_absolute(path, *p);
3536 if (u->manager->unit_path_cache &&
3537 !set_get(u->manager->unit_path_cache, filename))
3540 r = open_follow(&filename, &f, symlink_names, &id);
3549 /* Empty the symlink names for the next run */
3550 set_clear_free(symlink_names);
3559 /* Hmm, no suitable file found? */
3563 r = merge_by_names(&merged, symlink_names, id);
3568 u->load_state = UNIT_MERGED;
3572 if (fstat(fileno(f), &st) < 0)
3575 if (null_or_empty(&st))
3576 u->load_state = UNIT_MASKED;
3578 u->load_state = UNIT_LOADED;
3580 /* Now, parse the file contents */
3581 r = config_parse(u->id, filename, f,
3582 UNIT_VTABLE(u)->sections,
3583 config_item_perf_lookup, load_fragment_gperf_lookup,
3584 false, true, false, u);
3589 free(u->fragment_path);
3590 u->fragment_path = filename;
3593 u->fragment_mtime = timespec_load(&st.st_mtim);
3595 if (u->source_path) {
3596 if (stat(u->source_path, &st) >= 0)
3597 u->source_mtime = timespec_load(&st.st_mtim);
3599 u->source_mtime = 0;
3605 int unit_load_fragment(Unit *u) {
3611 assert(u->load_state == UNIT_STUB);
3614 /* First, try to find the unit under its id. We always look
3615 * for unit files in the default directories, to make it easy
3616 * to override things by placing things in /etc/systemd/system */
3617 r = load_from_path(u, u->id);
3621 /* Try to find an alias we can load this with */
3622 if (u->load_state == UNIT_STUB) {
3623 SET_FOREACH(t, u->names, i) {
3628 r = load_from_path(u, t);
3632 if (u->load_state != UNIT_STUB)
3637 /* And now, try looking for it under the suggested (originally linked) path */
3638 if (u->load_state == UNIT_STUB && u->fragment_path) {
3640 r = load_from_path(u, u->fragment_path);
3644 if (u->load_state == UNIT_STUB) {
3645 /* Hmm, this didn't work? Then let's get rid
3646 * of the fragment path stored for us, so that
3647 * we don't point to an invalid location. */
3648 free(u->fragment_path);
3649 u->fragment_path = NULL;
3653 /* Look for a template */
3654 if (u->load_state == UNIT_STUB && u->instance) {
3655 _cleanup_free_ char *k;
3657 k = unit_name_template(u->id);
3661 r = load_from_path(u, k);
3665 if (u->load_state == UNIT_STUB) {
3666 SET_FOREACH(t, u->names, i) {
3667 _cleanup_free_ char *z = NULL;
3672 z = unit_name_template(t);
3676 r = load_from_path(u, z);
3680 if (u->load_state != UNIT_STUB)
3689 void unit_dump_config_items(FILE *f) {
3690 static const struct {
3691 const ConfigParserCallback callback;
3694 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3695 { config_parse_warn_compat, "NOTSUPPORTED" },
3697 { config_parse_int, "INTEGER" },
3698 { config_parse_unsigned, "UNSIGNED" },
3699 { config_parse_iec_size, "SIZE" },
3700 { config_parse_iec_off, "SIZE" },
3701 { config_parse_si_size, "SIZE" },
3702 { config_parse_bool, "BOOLEAN" },
3703 { config_parse_string, "STRING" },
3704 { config_parse_path, "PATH" },
3705 { config_parse_unit_path_printf, "PATH" },
3706 { config_parse_strv, "STRING [...]" },
3707 { config_parse_exec_nice, "NICE" },
3708 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3709 { config_parse_exec_io_class, "IOCLASS" },
3710 { config_parse_exec_io_priority, "IOPRIORITY" },
3711 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3712 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3713 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3714 { config_parse_mode, "MODE" },
3715 { config_parse_unit_env_file, "FILE" },
3716 { config_parse_output, "OUTPUT" },
3717 { config_parse_input, "INPUT" },
3718 { config_parse_log_facility, "FACILITY" },
3719 { config_parse_log_level, "LEVEL" },
3720 { config_parse_exec_capabilities, "CAPABILITIES" },
3721 { config_parse_exec_secure_bits, "SECUREBITS" },
3722 { config_parse_bounding_set, "BOUNDINGSET" },
3723 { config_parse_limit, "LIMIT" },
3724 { config_parse_unit_deps, "UNIT [...]" },
3725 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3726 { config_parse_service_type, "SERVICETYPE" },
3727 { config_parse_service_restart, "SERVICERESTART" },
3728 #ifdef HAVE_SYSV_COMPAT
3729 { config_parse_sysv_priority, "SYSVPRIORITY" },
3731 { config_parse_kill_mode, "KILLMODE" },
3732 { config_parse_kill_signal, "SIGNAL" },
3733 { config_parse_socket_listen, "SOCKET [...]" },
3734 { config_parse_socket_bind, "SOCKETBIND" },
3735 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3736 { config_parse_sec, "SECONDS" },
3737 { config_parse_nsec, "NANOSECONDS" },
3738 { config_parse_namespace_path_strv, "PATH [...]" },
3739 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3740 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3741 { config_parse_unit_string_printf, "STRING" },
3742 { config_parse_trigger_unit, "UNIT" },
3743 { config_parse_timer, "TIMER" },
3744 { config_parse_path_spec, "PATH" },
3745 { config_parse_notify_access, "ACCESS" },
3746 { config_parse_ip_tos, "TOS" },
3747 { config_parse_unit_condition_path, "CONDITION" },
3748 { config_parse_unit_condition_string, "CONDITION" },
3749 { config_parse_unit_condition_null, "CONDITION" },
3750 { config_parse_unit_slice, "SLICE" },
3751 { config_parse_documentation, "URL" },
3752 { config_parse_service_timeout, "SECONDS" },
3753 { config_parse_failure_action, "ACTION" },
3754 { config_parse_set_status, "STATUS" },
3755 { config_parse_service_sockets, "SOCKETS" },
3756 { config_parse_environ, "ENVIRON" },
3758 { config_parse_syscall_filter, "SYSCALLS" },
3759 { config_parse_syscall_archs, "ARCHS" },
3760 { config_parse_syscall_errno, "ERRNO" },
3761 { config_parse_address_families, "FAMILIES" },
3763 { config_parse_cpu_shares, "SHARES" },
3764 { config_parse_memory_limit, "LIMIT" },
3765 { config_parse_device_allow, "DEVICE" },
3766 { config_parse_device_policy, "POLICY" },
3767 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3768 { config_parse_blockio_weight, "WEIGHT" },
3769 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3770 { config_parse_long, "LONG" },
3771 { config_parse_socket_service, "SERVICE" },
3773 { config_parse_exec_selinux_context, "LABEL" },
3775 { config_parse_job_mode, "MODE" },
3776 { config_parse_job_mode_isolate, "BOOLEAN" },
3777 { config_parse_personality, "PERSONALITY" },
3780 const char *prev = NULL;
3785 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3786 const char *rvalue = "OTHER", *lvalue;
3790 const ConfigPerfItem *p;
3792 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3794 dot = strchr(i, '.');
3795 lvalue = dot ? dot + 1 : i;
3799 if (!prev || !strneq(prev, i, prefix_len+1)) {
3803 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3806 for (j = 0; j < ELEMENTSOF(table); j++)
3807 if (p->parse == table[j].callback) {
3808 rvalue = table[j].rvalue;
3812 fprintf(f, "%s=%s\n", lvalue, rvalue);