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/resource.h>
38 #include "conf-parser.h"
39 #include "load-fragment.h"
42 #include "securebits.h"
44 #include "unit-name.h"
45 #include "unit-printf.h"
47 #include "path-util.h"
51 #include "bus-error.h"
52 #include "errno-list.h"
55 #include "bus-internal.h"
58 #include "seccomp-util.h"
61 int config_parse_warn_compat(
66 unsigned section_line,
72 Disabled reason = ltype;
75 case DISABLED_CONFIGURATION:
76 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
77 "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
80 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
81 "Support for option %s= has been removed and it is ignored", lvalue);
83 case DISABLED_EXPERIMENTAL:
84 log_syntax(unit, LOG_INFO, filename, line, EINVAL,
85 "Support for option %s= has not yet been enabled and it is ignored", lvalue);
92 int config_parse_unit_deps(const char *unit,
96 unsigned section_line,
103 UnitDependency d = ltype;
105 const char *word, *state;
112 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
113 _cleanup_free_ char *t = NULL, *k = NULL;
116 t = strndup(word, l);
120 r = unit_name_printf(u, t, &k);
122 log_syntax(unit, LOG_ERR, filename, line, -r,
123 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
127 r = unit_add_dependency_by_name(u, d, k, NULL, true);
129 log_syntax(unit, LOG_ERR, filename, line, -r,
130 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
133 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
138 int config_parse_unit_string_printf(
140 const char *filename,
143 unsigned section_line,
150 _cleanup_free_ char *k = NULL;
159 r = unit_full_printf(u, rvalue, &k);
161 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
165 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
168 int config_parse_unit_strv_printf(const char *unit,
169 const char *filename,
172 unsigned section_line,
180 _cleanup_free_ char *k = NULL;
188 r = unit_full_printf(u, rvalue, &k);
190 log_syntax(unit, LOG_ERR, filename, line, -r,
191 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
193 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
194 k ? k : rvalue, data, userdata);
197 int config_parse_unit_path_printf(const char *unit,
198 const char *filename,
201 unsigned section_line,
208 _cleanup_free_ char *k = NULL;
217 r = unit_full_printf(u, rvalue, &k);
219 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
223 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
226 int config_parse_unit_path_strv_printf(
228 const char *filename,
231 unsigned section_line,
239 const char *word, *state;
249 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
250 _cleanup_free_ char *k = NULL;
256 r = unit_full_printf(u, t, &k);
258 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
262 if (!utf8_is_valid(k)) {
263 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
267 if (!path_is_absolute(k)) {
268 log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
272 path_kill_slashes(k);
281 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
286 int config_parse_socket_listen(const char *unit,
287 const char *filename,
290 unsigned section_line,
297 _cleanup_free_ SocketPort *p = NULL;
309 if (isempty(rvalue)) {
310 /* An empty assignment removes all ports */
311 socket_free_ports(s);
315 p = new0(SocketPort, 1);
319 if (ltype != SOCKET_SOCKET) {
322 r = unit_full_printf(UNIT(s), rvalue, &p->path);
324 p->path = strdup(rvalue);
328 log_syntax(unit, LOG_ERR, filename, line, -r,
329 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
332 path_kill_slashes(p->path);
334 } else if (streq(lvalue, "ListenNetlink")) {
335 _cleanup_free_ char *k = NULL;
337 p->type = SOCKET_SOCKET;
338 r = unit_full_printf(UNIT(s), rvalue, &k);
340 log_syntax(unit, LOG_ERR, filename, line, -r,
341 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
343 r = socket_address_parse_netlink(&p->address, k ?: rvalue);
345 log_syntax(unit, LOG_ERR, filename, line, -r,
346 "Failed to parse address value, ignoring: %s", rvalue);
351 _cleanup_free_ char *k = NULL;
353 p->type = SOCKET_SOCKET;
354 r = unit_full_printf(UNIT(s), rvalue, &k);
356 log_syntax(unit, LOG_ERR, filename, line, -r,
357 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
359 r = socket_address_parse(&p->address, k ? k : rvalue);
361 log_syntax(unit, LOG_ERR, filename, line, -r,
362 "Failed to parse address value, ignoring: %s", rvalue);
366 if (streq(lvalue, "ListenStream"))
367 p->address.type = SOCK_STREAM;
368 else if (streq(lvalue, "ListenDatagram"))
369 p->address.type = SOCK_DGRAM;
371 assert(streq(lvalue, "ListenSequentialPacket"));
372 p->address.type = SOCK_SEQPACKET;
375 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
376 log_syntax(unit, LOG_ERR, filename, line, EOPNOTSUPP,
377 "Address family not supported, ignoring: %s", rvalue);
386 LIST_FIND_TAIL(port, s->ports, tail);
387 LIST_INSERT_AFTER(port, s->ports, tail, p);
389 LIST_PREPEND(port, s->ports, p);
395 int config_parse_socket_bind(const char *unit,
396 const char *filename,
399 unsigned section_line,
407 SocketAddressBindIPv6Only b;
416 b = socket_address_bind_ipv6_only_from_string(rvalue);
420 r = parse_boolean(rvalue);
422 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
423 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
427 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
429 s->bind_ipv6_only = b;
434 int config_parse_exec_nice(const char *unit,
435 const char *filename,
438 unsigned section_line,
445 ExecContext *c = data;
453 r = safe_atoi(rvalue, &priority);
455 log_syntax(unit, LOG_ERR, filename, line, -r,
456 "Failed to parse nice priority, ignoring: %s. ", rvalue);
460 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
461 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
462 "Nice priority out of range, ignoring: %s", rvalue);
472 int config_parse_exec_oom_score_adjust(const char* unit,
473 const char *filename,
476 unsigned section_line,
483 ExecContext *c = data;
491 r = safe_atoi(rvalue, &oa);
493 log_syntax(unit, LOG_ERR, filename, line, -r,
494 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
498 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
499 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
500 "OOM score adjust value out of range, ignoring: %s", rvalue);
504 c->oom_score_adjust = oa;
505 c->oom_score_adjust_set = true;
510 int config_parse_exec(const char *unit,
511 const char *filename,
514 unsigned section_line,
521 ExecCommand **e = data, *nce;
533 if (isempty(rvalue)) {
534 /* An empty assignment resets the list */
535 *e = exec_command_free_list(*e);
539 /* We accept an absolute path as first argument, or
540 * alternatively an absolute prefixed with @ to allow
541 * overriding of argv[0]. */
544 const char *word, *state, *reason;
546 bool separate_argv0 = false, ignore = false;
552 rvalue += strspn(rvalue, WHITESPACE);
558 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
560 for (i = 0; i < 2; i++) {
561 if (*word == '-' && !ignore) {
566 if (*word == '@' && !separate_argv0) {
567 separate_argv0 = true;
572 if (strneq(word, ";", MAX(l, 1U)))
577 if (!isempty(state)) {
578 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
579 "Trailing garbage, ignoring.");
584 /* If separate_argv0, we'll move first element to path variable */
585 n = new(char*, MAX(k + !separate_argv0, 1u));
590 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
594 if (separate_argv0 ? path == NULL : k == 0) {
595 /* first word, very special */
596 skip = separate_argv0 + ignore;
598 /* skip special chars in the beginning */
601 } else if (strneq(word, ";", MAX(l, 1U)))
602 /* new commandline */
606 skip = strneq(word, "\\;", MAX(l, 1U));
608 c = cunescape_length(word + skip, l - skip);
614 if (!utf8_is_valid(c)) {
615 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
620 /* where to stuff this? */
621 if (separate_argv0 && path == NULL)
629 log_debug("path: %s", path ?: n[0]);
632 reason = "Empty executable name or zeroeth argument";
633 else if (!string_is_safe(path ?: n[0]))
634 reason = "Executable path contains special characters";
635 else if (!path_is_absolute(path ?: n[0]))
636 reason = "Executable path is not absolute";
637 else if (endswith(path ?: n[0], "/"))
638 reason = "Executable path specifies a directory";
642 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
643 "%s, ignoring: %s", reason, rvalue);
656 nce = new0(ExecCommand, 1);
664 nce->ignore = ignore;
666 path_kill_slashes(nce->path);
668 exec_command_append_list(e, nce);
684 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
685 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
687 int config_parse_socket_bindtodevice(const char* unit,
688 const char *filename,
691 unsigned section_line,
706 if (rvalue[0] && !streq(rvalue, "*")) {
713 free(s->bind_to_device);
714 s->bind_to_device = n;
719 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
720 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
722 int config_parse_exec_io_class(const char *unit,
723 const char *filename,
726 unsigned section_line,
733 ExecContext *c = data;
741 x = ioprio_class_from_string(rvalue);
743 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
744 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
748 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
749 c->ioprio_set = true;
754 int config_parse_exec_io_priority(const char *unit,
755 const char *filename,
758 unsigned section_line,
765 ExecContext *c = data;
773 r = safe_atoi(rvalue, &i);
774 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
775 log_syntax(unit, LOG_ERR, filename, line, -r,
776 "Failed to parse IO priority, ignoring: %s", rvalue);
780 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
781 c->ioprio_set = true;
786 int config_parse_exec_cpu_sched_policy(const char *unit,
787 const char *filename,
790 unsigned section_line,
798 ExecContext *c = data;
806 x = sched_policy_from_string(rvalue);
808 log_syntax(unit, LOG_ERR, filename, line, -x,
809 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
813 c->cpu_sched_policy = x;
814 /* Moving to or from real-time policy? We need to adjust the priority */
815 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
816 c->cpu_sched_set = true;
821 int config_parse_exec_cpu_sched_prio(const char *unit,
822 const char *filename,
825 unsigned section_line,
832 ExecContext *c = data;
840 r = safe_atoi(rvalue, &i);
842 log_syntax(unit, LOG_ERR, filename, line, -r,
843 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
847 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
848 min = sched_get_priority_min(c->cpu_sched_policy);
849 max = sched_get_priority_max(c->cpu_sched_policy);
851 if (i < min || i > max) {
852 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
853 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
857 c->cpu_sched_priority = i;
858 c->cpu_sched_set = true;
863 int config_parse_exec_cpu_affinity(const char *unit,
864 const char *filename,
867 unsigned section_line,
874 ExecContext *c = data;
875 const char *word, *state;
883 if (isempty(rvalue)) {
884 /* An empty assignment resets the CPU list */
891 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
892 _cleanup_free_ char *t = NULL;
896 t = strndup(word, l);
900 r = safe_atou(t, &cpu);
903 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
908 if (r < 0 || cpu >= c->cpuset_ncpus) {
909 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
910 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
914 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
917 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
918 "Trailing garbage, ignoring.");
923 int config_parse_exec_capabilities(const char *unit,
924 const char *filename,
927 unsigned section_line,
934 ExecContext *c = data;
942 cap = cap_from_text(rvalue);
944 log_syntax(unit, LOG_ERR, filename, line, errno,
945 "Failed to parse capabilities, ignoring: %s", rvalue);
950 cap_free(c->capabilities);
951 c->capabilities = cap;
956 int config_parse_exec_secure_bits(const char *unit,
957 const char *filename,
960 unsigned section_line,
967 ExecContext *c = data;
969 const char *word, *state;
976 if (isempty(rvalue)) {
977 /* An empty assignment resets the field */
982 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
983 if (first_word(word, "keep-caps"))
984 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
985 else if (first_word(word, "keep-caps-locked"))
986 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
987 else if (first_word(word, "no-setuid-fixup"))
988 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
989 else if (first_word(word, "no-setuid-fixup-locked"))
990 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
991 else if (first_word(word, "noroot"))
992 c->secure_bits |= 1<<SECURE_NOROOT;
993 else if (first_word(word, "noroot-locked"))
994 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
996 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
997 "Failed to parse secure bits, ignoring: %s", rvalue);
1001 if (!isempty(state))
1002 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1003 "Invalid syntax, garbage at the end, ignoring.");
1008 int config_parse_bounding_set(const char *unit,
1009 const char *filename,
1011 const char *section,
1012 unsigned section_line,
1019 uint64_t *capability_bounding_set_drop = data;
1020 const char *word, *state;
1022 bool invert = false;
1030 if (rvalue[0] == '~') {
1035 /* Note that we store this inverted internally, since the
1036 * kernel wants it like this. But we actually expose it
1037 * non-inverted everywhere to have a fully normalized
1040 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1041 _cleanup_free_ char *t = NULL;
1044 t = strndup(word, l);
1048 cap = capability_from_name(t);
1050 log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
1054 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
1056 if (!isempty(state))
1057 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1058 "Trailing garbage, ignoring.");
1061 *capability_bounding_set_drop |= sum;
1063 *capability_bounding_set_drop |= ~sum;
1068 int config_parse_limit(const char *unit,
1069 const char *filename,
1071 const char *section,
1072 unsigned section_line,
1079 struct rlimit **rl = data;
1080 unsigned long long u;
1089 if (streq(rvalue, "infinity"))
1090 u = (unsigned long long) RLIM_INFINITY;
1094 r = safe_atollu(rvalue, &u);
1096 log_syntax(unit, LOG_ERR, filename, line, -r,
1097 "Failed to parse resource value, ignoring: %s", rvalue);
1103 *rl = new(struct rlimit, 1);
1108 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1112 #ifdef HAVE_SYSV_COMPAT
1113 int config_parse_sysv_priority(const char *unit,
1114 const char *filename,
1116 const char *section,
1117 unsigned section_line,
1124 int *priority = data;
1132 r = safe_atoi(rvalue, &i);
1133 if (r < 0 || i < 0) {
1134 log_syntax(unit, LOG_ERR, filename, line, -r,
1135 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1139 *priority = (int) i;
1144 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1146 int config_parse_kill_signal(const char *unit,
1147 const char *filename,
1149 const char *section,
1150 unsigned section_line,
1165 r = signal_from_string_try_harder(rvalue);
1167 log_syntax(unit, LOG_ERR, filename, line, -r,
1168 "Failed to parse kill signal, ignoring: %s", rvalue);
1176 int config_parse_exec_mount_flags(const char *unit,
1177 const char *filename,
1179 const char *section,
1180 unsigned section_line,
1187 ExecContext *c = data;
1188 const char *word, *state;
1190 unsigned long flags = 0;
1197 FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
1198 _cleanup_free_ char *t;
1200 t = strndup(word, l);
1204 if (streq(t, "shared"))
1206 else if (streq(t, "slave"))
1208 else if (streq(word, "private"))
1211 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1212 "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
1216 if (!isempty(state))
1217 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1218 "Trailing garbage, ignoring.");
1220 c->mount_flags = flags;
1224 int config_parse_exec_selinux_context(
1226 const char *filename,
1228 const char *section,
1229 unsigned section_line,
1236 ExecContext *c = data;
1247 if (isempty(rvalue)) {
1248 free(c->selinux_context);
1249 c->selinux_context = NULL;
1250 c->selinux_context_ignore = false;
1254 if (rvalue[0] == '-') {
1260 r = unit_name_printf(u, rvalue, &k);
1262 log_syntax(unit, LOG_ERR, filename, line, -r,
1263 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1267 free(c->selinux_context);
1268 c->selinux_context = k;
1269 c->selinux_context_ignore = ignore;
1274 int config_parse_exec_apparmor_profile(
1276 const char *filename,
1278 const char *section,
1279 unsigned section_line,
1286 ExecContext *c = data;
1297 if (isempty(rvalue)) {
1298 free(c->apparmor_profile);
1299 c->apparmor_profile = NULL;
1300 c->apparmor_profile_ignore = false;
1304 if (rvalue[0] == '-') {
1310 r = unit_name_printf(u, rvalue, &k);
1312 log_syntax(unit, LOG_ERR, filename, line, -r,
1313 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1317 free(c->apparmor_profile);
1318 c->apparmor_profile = k;
1319 c->apparmor_profile_ignore = ignore;
1324 int config_parse_exec_smack_process_label(
1326 const char *filename,
1328 const char *section,
1329 unsigned section_line,
1336 ExecContext *c = data;
1347 if (isempty(rvalue)) {
1348 free(c->smack_process_label);
1349 c->smack_process_label = NULL;
1350 c->smack_process_label_ignore = false;
1354 if (rvalue[0] == '-') {
1360 r = unit_name_printf(u, rvalue, &k);
1362 log_syntax(unit, LOG_ERR, filename, line, -r,
1363 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1367 free(c->smack_process_label);
1368 c->smack_process_label = k;
1369 c->smack_process_label_ignore = ignore;
1374 int config_parse_timer(const char *unit,
1375 const char *filename,
1377 const char *section,
1378 unsigned section_line,
1389 CalendarSpec *c = NULL;
1396 if (isempty(rvalue)) {
1397 /* Empty assignment resets list */
1398 timer_free_values(t);
1402 b = timer_base_from_string(lvalue);
1404 log_syntax(unit, LOG_ERR, filename, line, -b,
1405 "Failed to parse timer base, ignoring: %s", lvalue);
1409 if (b == TIMER_CALENDAR) {
1410 if (calendar_spec_from_string(rvalue, &c) < 0) {
1411 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1412 "Failed to parse calendar specification, ignoring: %s",
1417 if (parse_sec(rvalue, &u) < 0) {
1418 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1419 "Failed to parse timer value, ignoring: %s",
1425 v = new0(TimerValue, 1);
1427 calendar_spec_free(c);
1433 v->calendar_spec = c;
1435 LIST_PREPEND(value, t->values, v);
1440 int config_parse_trigger_unit(
1442 const char *filename,
1444 const char *section,
1445 unsigned section_line,
1452 _cleanup_free_ char *p = NULL;
1462 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1463 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1464 "Multiple units to trigger specified, ignoring: %s", rvalue);
1468 r = unit_name_printf(u, rvalue, &p);
1470 log_syntax(unit, LOG_ERR, filename, line, -r,
1471 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1473 type = unit_name_to_type(p ?: rvalue);
1475 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1476 "Unit type not valid, ignoring: %s", rvalue);
1480 if (type == u->type) {
1481 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1482 "Trigger cannot be of same type, ignoring: %s", rvalue);
1486 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1488 log_syntax(unit, LOG_ERR, filename, line, -r,
1489 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1496 int config_parse_path_spec(const char *unit,
1497 const char *filename,
1499 const char *section,
1500 unsigned section_line,
1510 _cleanup_free_ char *k = NULL;
1518 if (isempty(rvalue)) {
1519 /* Empty assignment clears list */
1524 b = path_type_from_string(lvalue);
1526 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1527 "Failed to parse path type, ignoring: %s", lvalue);
1531 r = unit_full_printf(UNIT(p), rvalue, &k);
1537 log_syntax(unit, LOG_ERR, filename, line, -r,
1538 "Failed to resolve unit specifiers on %s. Ignoring.",
1542 if (!path_is_absolute(k)) {
1543 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1544 "Path is not absolute, ignoring: %s", k);
1548 s = new0(PathSpec, 1);
1553 s->path = path_kill_slashes(k);
1558 LIST_PREPEND(spec, p->specs, s);
1563 int config_parse_socket_service(
1565 const char *filename,
1567 const char *section,
1568 unsigned section_line,
1575 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1579 _cleanup_free_ char *p = NULL;
1586 r = unit_name_printf(UNIT(s), rvalue, &p);
1588 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1592 if (!endswith(p, ".service")) {
1593 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1597 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1599 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1603 unit_ref_set(&s->service, x);
1608 int config_parse_service_sockets(
1610 const char *filename,
1612 const char *section,
1613 unsigned section_line,
1621 const char *word, *state;
1630 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
1631 _cleanup_free_ char *t = NULL, *k = NULL;
1633 t = strndup(word, l);
1637 r = unit_name_printf(UNIT(s), t, &k);
1639 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
1643 if (!endswith(k, ".socket")) {
1644 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type socket, ignoring: %s", k);
1648 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1650 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1652 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1654 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
1656 if (!isempty(state))
1657 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
1662 int config_parse_bus_name(
1664 const char *filename,
1666 const char *section,
1667 unsigned section_line,
1674 _cleanup_free_ char *k = NULL;
1683 r = unit_full_printf(u, rvalue, &k);
1685 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
1689 if (!service_name_is_valid(k)) {
1690 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bus name %s, ignoring.", k);
1694 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
1697 int config_parse_service_timeout(const char *unit,
1698 const char *filename,
1700 const char *section,
1701 unsigned section_line,
1708 Service *s = userdata;
1716 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1717 rvalue, data, userdata);
1721 if (streq(lvalue, "TimeoutSec")) {
1722 s->start_timeout_defined = true;
1723 s->timeout_stop_usec = s->timeout_start_usec;
1724 } else if (streq(lvalue, "TimeoutStartSec"))
1725 s->start_timeout_defined = true;
1730 int config_parse_busname_service(
1732 const char *filename,
1734 const char *section,
1735 unsigned section_line,
1742 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1746 _cleanup_free_ char *p = NULL;
1753 r = unit_name_printf(UNIT(n), rvalue, &p);
1755 log_syntax(unit, LOG_ERR, filename, line, -r,
1756 "Failed to resolve specifiers, ignoring: %s", rvalue);
1760 if (!endswith(p, ".service")) {
1761 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1762 "Unit must be of type service, ignoring: %s", rvalue);
1766 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1768 log_syntax(unit, LOG_ERR, filename, line, -r,
1769 "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1773 unit_ref_set(&n->service, x);
1778 DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
1780 int config_parse_bus_policy(
1782 const char *filename,
1784 const char *section,
1785 unsigned section_line,
1792 _cleanup_free_ BusNamePolicy *p = NULL;
1793 _cleanup_free_ char *id_str = NULL;
1794 BusName *busname = data;
1802 p = new0(BusNamePolicy, 1);
1806 if (streq(lvalue, "AllowUser"))
1807 p->type = BUSNAME_POLICY_TYPE_USER;
1808 else if (streq(lvalue, "AllowGroup"))
1809 p->type = BUSNAME_POLICY_TYPE_GROUP;
1811 assert_not_reached("Unknown lvalue");
1813 id_str = strdup(rvalue);
1817 access_str = strpbrk(id_str, WHITESPACE);
1819 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1820 "Invalid busname policy value '%s'", rvalue);
1826 access_str += strspn(access_str, WHITESPACE);
1828 p->access = bus_policy_access_from_string(access_str);
1829 if (p->access < 0) {
1830 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1831 "Invalid busname policy access type '%s'", access_str);
1838 LIST_PREPEND(policy, busname->policy, p);
1844 int config_parse_bus_endpoint_policy(
1846 const char *filename,
1848 const char *section,
1849 unsigned section_line,
1856 _cleanup_free_ char *name = NULL;
1857 BusPolicyAccess access;
1858 ExecContext *c = data;
1867 name = strdup(rvalue);
1871 access_str = strpbrk(name, WHITESPACE);
1873 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1874 "Invalid endpoint policy value '%s'", rvalue);
1880 access_str += strspn(access_str, WHITESPACE);
1882 access = bus_policy_access_from_string(access_str);
1883 if (access <= _BUS_POLICY_ACCESS_INVALID ||
1884 access >= _BUS_POLICY_ACCESS_MAX) {
1885 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1886 "Invalid endpoint policy access type '%s'", access_str);
1890 if (!c->bus_endpoint) {
1891 r = bus_endpoint_new(&c->bus_endpoint);
1897 return bus_endpoint_add_policy(c->bus_endpoint, name, access);
1900 int config_parse_unit_env_file(const char *unit,
1901 const char *filename,
1903 const char *section,
1904 unsigned section_line,
1913 _cleanup_free_ char *n = NULL;
1922 if (isempty(rvalue)) {
1923 /* Empty assignment frees the list */
1929 r = unit_full_printf(u, rvalue, &n);
1931 log_syntax(unit, LOG_ERR, filename, line, -r,
1932 "Failed to resolve specifiers, ignoring: %s", rvalue);
1935 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1936 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1937 "Path '%s' is not absolute, ignoring.", s);
1941 r = strv_extend(env, s);
1948 int config_parse_environ(const char *unit,
1949 const char *filename,
1951 const char *section,
1952 unsigned section_line,
1961 const char *word, *state;
1963 _cleanup_free_ char *k = NULL;
1971 if (isempty(rvalue)) {
1972 /* Empty assignment resets the list */
1979 r = unit_full_printf(u, rvalue, &k);
1981 log_syntax(unit, LOG_ERR, filename, line, -r,
1982 "Failed to resolve specifiers, ignoring: %s", rvalue);
1990 FOREACH_WORD_QUOTED(word, l, k, state) {
1991 _cleanup_free_ char *n;
1994 n = cunescape_length(word, l);
1998 if (!env_assignment_is_valid(n)) {
1999 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2000 "Invalid environment assignment, ignoring: %s", rvalue);
2004 x = strv_env_set(*env, n);
2011 if (!isempty(state))
2012 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2013 "Trailing garbage, ignoring.");
2018 int config_parse_ip_tos(const char *unit,
2019 const char *filename,
2021 const char *section,
2022 unsigned section_line,
2029 int *ip_tos = data, x;
2036 x = ip_tos_from_string(rvalue);
2038 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2039 "Failed to parse IP TOS value, ignoring: %s", rvalue);
2047 int config_parse_unit_condition_path(
2049 const char *filename,
2051 const char *section,
2052 unsigned section_line,
2059 _cleanup_free_ char *p = NULL;
2060 Condition **list = data, *c;
2061 ConditionType t = ltype;
2062 bool trigger, negate;
2071 if (isempty(rvalue)) {
2072 /* Empty assignment resets the list */
2073 *list = condition_free_list(*list);
2077 trigger = rvalue[0] == '|';
2081 negate = rvalue[0] == '!';
2085 r = unit_full_printf(u, rvalue, &p);
2087 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2091 if (!path_is_absolute(p)) {
2092 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
2096 c = condition_new(t, p, trigger, negate);
2100 LIST_PREPEND(conditions, *list, c);
2104 int config_parse_unit_condition_string(
2106 const char *filename,
2108 const char *section,
2109 unsigned section_line,
2116 _cleanup_free_ char *s = NULL;
2117 Condition **list = data, *c;
2118 ConditionType t = ltype;
2119 bool trigger, negate;
2128 if (isempty(rvalue)) {
2129 /* Empty assignment resets the list */
2130 *list = condition_free_list(*list);
2134 trigger = rvalue[0] == '|';
2138 negate = rvalue[0] == '!';
2142 r = unit_full_printf(u, rvalue, &s);
2144 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
2148 c = condition_new(t, s, trigger, negate);
2152 LIST_PREPEND(conditions, *list, c);
2156 int config_parse_unit_condition_null(
2158 const char *filename,
2160 const char *section,
2161 unsigned section_line,
2168 Condition **list = data, *c;
2169 bool trigger, negate;
2177 if (isempty(rvalue)) {
2178 /* Empty assignment resets the list */
2179 *list = condition_free_list(*list);
2183 trigger = rvalue[0] == '|';
2187 negate = rvalue[0] == '!';
2191 b = parse_boolean(rvalue);
2193 log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
2200 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
2204 LIST_PREPEND(conditions, *list, c);
2208 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
2209 DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
2211 int config_parse_unit_requires_mounts_for(
2213 const char *filename,
2215 const char *section,
2216 unsigned section_line,
2224 const char *word, *state;
2232 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2234 _cleanup_free_ char *n;
2236 n = strndup(word, l);
2240 if (!utf8_is_valid(n)) {
2241 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2245 r = unit_require_mounts_for(u, n);
2247 log_syntax(unit, LOG_ERR, filename, line, -r,
2248 "Failed to add required mount for, ignoring: %s", rvalue);
2252 if (!isempty(state))
2253 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2254 "Trailing garbage, ignoring.");
2259 int config_parse_documentation(const char *unit,
2260 const char *filename,
2262 const char *section,
2263 unsigned section_line,
2279 if (isempty(rvalue)) {
2280 /* Empty assignment resets the list */
2281 strv_free(u->documentation);
2282 u->documentation = NULL;
2286 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2287 rvalue, data, userdata);
2291 for (a = b = u->documentation; a && *a; a++) {
2293 if (documentation_url_is_valid(*a))
2296 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2297 "Invalid URL, ignoring: %s", *a);
2308 int config_parse_syscall_filter(
2310 const char *filename,
2312 const char *section,
2313 unsigned section_line,
2320 static const char default_syscalls[] =
2327 ExecContext *c = data;
2329 bool invert = false;
2330 const char *word, *state;
2339 if (isempty(rvalue)) {
2340 /* Empty assignment resets the list */
2341 set_free(c->syscall_filter);
2342 c->syscall_filter = NULL;
2343 c->syscall_whitelist = false;
2347 if (rvalue[0] == '~') {
2352 if (!c->syscall_filter) {
2353 c->syscall_filter = set_new(NULL);
2354 if (!c->syscall_filter)
2358 /* Allow everything but the ones listed */
2359 c->syscall_whitelist = false;
2363 /* Allow nothing but the ones listed */
2364 c->syscall_whitelist = true;
2366 /* Accept default syscalls if we are on a whitelist */
2367 NULSTR_FOREACH(i, default_syscalls) {
2370 id = seccomp_syscall_resolve_name(i);
2374 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2383 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2384 _cleanup_free_ char *t = NULL;
2387 t = strndup(word, l);
2391 id = seccomp_syscall_resolve_name(t);
2393 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2394 "Failed to parse system call, ignoring: %s", t);
2398 /* If we previously wanted to forbid a syscall and now
2399 * we want to allow it, then remove it from the list
2401 if (!invert == c->syscall_whitelist) {
2402 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2408 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2410 if (!isempty(state))
2411 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2412 "Trailing garbage, ignoring.");
2414 /* Turn on NNP, but only if it wasn't configured explicitly
2415 * before, and only if we are in user mode. */
2416 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2417 c->no_new_privileges = true;
2422 int config_parse_syscall_archs(
2424 const char *filename,
2426 const char *section,
2427 unsigned section_line,
2435 const char *word, *state;
2439 if (isempty(rvalue)) {
2445 r = set_ensure_allocated(archs, NULL);
2449 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2450 _cleanup_free_ char *t = NULL;
2453 t = strndup(word, l);
2457 r = seccomp_arch_from_string(t, &a);
2459 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2460 "Failed to parse system call architecture, ignoring: %s", t);
2464 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2470 if (!isempty(state))
2471 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2472 "Trailing garbage, ignoring.");
2477 int config_parse_syscall_errno(
2479 const char *filename,
2481 const char *section,
2482 unsigned section_line,
2489 ExecContext *c = data;
2496 if (isempty(rvalue)) {
2497 /* Empty assignment resets to KILL */
2498 c->syscall_errno = 0;
2502 e = errno_from_name(rvalue);
2504 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2505 "Failed to parse error number, ignoring: %s", rvalue);
2509 c->syscall_errno = e;
2513 int config_parse_address_families(
2515 const char *filename,
2517 const char *section,
2518 unsigned section_line,
2525 ExecContext *c = data;
2526 bool invert = false;
2527 const char *word, *state;
2535 if (isempty(rvalue)) {
2536 /* Empty assignment resets the list */
2537 set_free(c->address_families);
2538 c->address_families = NULL;
2539 c->address_families_whitelist = false;
2543 if (rvalue[0] == '~') {
2548 if (!c->address_families) {
2549 c->address_families = set_new(NULL);
2550 if (!c->address_families)
2553 c->address_families_whitelist = !invert;
2556 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
2557 _cleanup_free_ char *t = NULL;
2560 t = strndup(word, l);
2564 af = af_from_name(t);
2566 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2567 "Failed to parse address family, ignoring: %s", t);
2571 /* If we previously wanted to forbid an address family and now
2572 * we want to allow it, then remove it from the list
2574 if (!invert == c->address_families_whitelist) {
2575 r = set_put(c->address_families, INT_TO_PTR(af));
2581 set_remove(c->address_families, INT_TO_PTR(af));
2583 if (!isempty(state))
2584 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2585 "Trailing garbage, ignoring.");
2591 int config_parse_unit_slice(
2593 const char *filename,
2595 const char *section,
2596 unsigned section_line,
2603 _cleanup_free_ char *k = NULL;
2604 Unit *u = userdata, *slice;
2612 r = unit_name_printf(u, rvalue, &k);
2614 log_syntax(unit, LOG_ERR, filename, line, -r,
2615 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2622 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2624 log_syntax(unit, LOG_ERR, filename, line, -r,
2625 "Failed to load slice unit %s. Ignoring.", k);
2629 if (slice->type != UNIT_SLICE) {
2630 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2631 "Slice unit %s is not a slice. Ignoring.", k);
2635 unit_ref_set(&u->slice, slice);
2639 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2641 int config_parse_cpu_shares(
2643 const char *filename,
2645 const char *section,
2646 unsigned section_line,
2653 unsigned long *shares = data, lu;
2660 if (isempty(rvalue)) {
2661 *shares = (unsigned long) -1;
2665 r = safe_atolu(rvalue, &lu);
2666 if (r < 0 || lu <= 0) {
2667 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2668 "CPU shares '%s' invalid. Ignoring.", rvalue);
2676 int config_parse_cpu_quota(
2678 const char *filename,
2680 const char *section,
2681 unsigned section_line,
2688 CGroupContext *c = data;
2695 if (isempty(rvalue)) {
2696 c->cpu_quota_per_sec_usec = USEC_INFINITY;
2700 if (!endswith(rvalue, "%")) {
2702 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2703 "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
2707 if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
2708 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2709 "CPU quota '%s' invalid. Ignoring.", rvalue);
2713 c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
2718 int config_parse_memory_limit(
2720 const char *filename,
2722 const char *section,
2723 unsigned section_line,
2730 CGroupContext *c = data;
2734 if (isempty(rvalue)) {
2735 c->memory_limit = (uint64_t) -1;
2739 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2741 r = parse_size(rvalue, 1024, &bytes);
2743 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2744 "Memory limit '%s' invalid. Ignoring.", rvalue);
2748 c->memory_limit = (uint64_t) bytes;
2752 int config_parse_device_allow(
2754 const char *filename,
2756 const char *section,
2757 unsigned section_line,
2764 _cleanup_free_ char *path = NULL;
2765 CGroupContext *c = data;
2766 CGroupDeviceAllow *a;
2770 if (isempty(rvalue)) {
2771 while (c->device_allow)
2772 cgroup_context_free_device_allow(c, c->device_allow);
2777 n = strcspn(rvalue, WHITESPACE);
2778 path = strndup(rvalue, n);
2782 if (!startswith(path, "/dev/") &&
2783 !startswith(path, "block-") &&
2784 !startswith(path, "char-")) {
2785 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2786 "Invalid device node path '%s'. Ignoring.", path);
2790 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2794 if (!in_charset(m, "rwm")) {
2795 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2796 "Invalid device rights '%s'. Ignoring.", m);
2800 a = new0(CGroupDeviceAllow, 1);
2806 a->r = !!strchr(m, 'r');
2807 a->w = !!strchr(m, 'w');
2808 a->m = !!strchr(m, 'm');
2810 LIST_PREPEND(device_allow, c->device_allow, a);
2814 int config_parse_blockio_weight(
2816 const char *filename,
2818 const char *section,
2819 unsigned section_line,
2826 unsigned long *weight = data, lu;
2833 if (isempty(rvalue)) {
2834 *weight = (unsigned long) -1;
2838 r = safe_atolu(rvalue, &lu);
2839 if (r < 0 || lu < 10 || lu > 1000) {
2840 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2841 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2849 int config_parse_blockio_device_weight(
2851 const char *filename,
2853 const char *section,
2854 unsigned section_line,
2861 _cleanup_free_ char *path = NULL;
2862 CGroupBlockIODeviceWeight *w;
2863 CGroupContext *c = data;
2873 if (isempty(rvalue)) {
2874 while (c->blockio_device_weights)
2875 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2880 n = strcspn(rvalue, WHITESPACE);
2881 weight = rvalue + n;
2883 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2884 "Expected block device and device weight. Ignoring.");
2888 path = strndup(rvalue, n);
2892 if (!path_startswith(path, "/dev")) {
2893 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2894 "Invalid device node path '%s'. Ignoring.", path);
2898 weight += strspn(weight, WHITESPACE);
2899 r = safe_atolu(weight, &lu);
2900 if (r < 0 || lu < 10 || lu > 1000) {
2901 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2902 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2906 w = new0(CGroupBlockIODeviceWeight, 1);
2915 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2919 int config_parse_blockio_bandwidth(
2921 const char *filename,
2923 const char *section,
2924 unsigned section_line,
2931 _cleanup_free_ char *path = NULL;
2932 CGroupBlockIODeviceBandwidth *b;
2933 CGroupContext *c = data;
2934 const char *bandwidth;
2944 read = streq("BlockIOReadBandwidth", lvalue);
2946 if (isempty(rvalue)) {
2947 CGroupBlockIODeviceBandwidth *next;
2949 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2950 if (b->read == read)
2951 cgroup_context_free_blockio_device_bandwidth(c, b);
2956 n = strcspn(rvalue, WHITESPACE);
2957 bandwidth = rvalue + n;
2958 bandwidth += strspn(bandwidth, WHITESPACE);
2961 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2962 "Expected space separated pair of device node and bandwidth. Ignoring.");
2966 path = strndup(rvalue, n);
2970 if (!path_startswith(path, "/dev")) {
2971 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2972 "Invalid device node path '%s'. Ignoring.", path);
2976 r = parse_size(bandwidth, 1000, &bytes);
2977 if (r < 0 || bytes <= 0) {
2978 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2979 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2983 b = new0(CGroupBlockIODeviceBandwidth, 1);
2989 b->bandwidth = (uint64_t) bytes;
2992 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2997 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2999 int config_parse_job_mode_isolate(
3001 const char *filename,
3003 const char *section,
3004 unsigned section_line,
3018 r = parse_boolean(rvalue);
3020 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3021 "Failed to parse boolean, ignoring: %s", rvalue);
3025 *m = r ? JOB_ISOLATE : JOB_REPLACE;
3029 int config_parse_personality(
3031 const char *filename,
3033 const char *section,
3034 unsigned section_line,
3041 unsigned long *personality = data, p;
3046 assert(personality);
3048 p = personality_from_string(rvalue);
3049 if (p == 0xffffffffUL) {
3050 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3051 "Failed to parse personality, ignoring: %s", rvalue);
3059 int config_parse_runtime_directory(
3061 const char *filename,
3063 const char *section,
3064 unsigned section_line,
3072 const char *word, *state;
3081 if (isempty(rvalue)) {
3082 /* Empty assignment resets the list */
3088 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3089 _cleanup_free_ char *n;
3091 n = strndup(word, l);
3095 if (!filename_is_valid(n)) {
3096 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3097 "Runtime directory is not valid, ignoring assignment: %s", rvalue);
3101 r = strv_push(rt, n);
3107 if (!isempty(state))
3108 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3109 "Trailing garbage, ignoring.");
3114 int config_parse_set_status(
3116 const char *filename,
3118 const char *section,
3119 unsigned section_line,
3127 const char *word, *state;
3129 ExitStatusSet *status_set = data;
3136 /* Empty assignment resets the list */
3137 if (isempty(rvalue)) {
3138 exit_status_set_free(status_set);
3142 FOREACH_WORD(word, l, rvalue, state) {
3143 _cleanup_free_ char *temp;
3147 temp = strndup(word, l);
3151 r = safe_atoi(temp, &val);
3153 val = signal_from_string_try_harder(temp);
3156 log_syntax(unit, LOG_ERR, filename, line, -val,
3157 "Failed to parse value, ignoring: %s", word);
3160 set = &status_set->signal;
3162 if (val < 0 || val > 255) {
3163 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
3164 "Value %d is outside range 0-255, ignoring", val);
3167 set = &status_set->status;
3170 r = set_ensure_allocated(set, NULL);
3174 r = set_put(*set, INT_TO_PTR(val));
3176 log_syntax(unit, LOG_ERR, filename, line, -r,
3177 "Unable to store: %s", word);
3181 if (!isempty(state))
3182 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3183 "Trailing garbage, ignoring.");
3188 int config_parse_namespace_path_strv(
3190 const char *filename,
3192 const char *section,
3193 unsigned section_line,
3201 const char *word, *state;
3210 if (isempty(rvalue)) {
3211 /* Empty assignment resets the list */
3217 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
3218 _cleanup_free_ char *n;
3221 n = strndup(word, l);
3225 if (!utf8_is_valid(n)) {
3226 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
3230 offset = n[0] == '-';
3231 if (!path_is_absolute(n + offset)) {
3232 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3233 "Not an absolute path, ignoring: %s", rvalue);
3237 path_kill_slashes(n);
3239 r = strv_push(sv, n);
3245 if (!isempty(state))
3246 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
3247 "Trailing garbage, ignoring.");
3252 int config_parse_no_new_privileges(
3254 const char *filename,
3256 const char *section,
3257 unsigned section_line,
3264 ExecContext *c = data;
3272 k = parse_boolean(rvalue);
3274 log_syntax(unit, LOG_ERR, filename, line, -k,
3275 "Failed to parse boolean value, ignoring: %s", rvalue);
3279 c->no_new_privileges = !!k;
3280 c->no_new_privileges_set = true;
3285 int config_parse_protect_home(
3287 const char *filename,
3289 const char *section,
3290 unsigned section_line,
3297 ExecContext *c = data;
3305 /* Our enum shall be a superset of booleans, hence first try
3306 * to parse as as boolean, and then as enum */
3308 k = parse_boolean(rvalue);
3310 c->protect_home = PROTECT_HOME_YES;
3312 c->protect_home = PROTECT_HOME_NO;
3316 h = protect_home_from_string(rvalue);
3318 log_syntax(unit, LOG_ERR, filename, line, -h,
3319 "Failed to parse protect home value, ignoring: %s", rvalue);
3323 c->protect_home = h;
3329 int config_parse_protect_system(
3331 const char *filename,
3333 const char *section,
3334 unsigned section_line,
3341 ExecContext *c = data;
3349 /* Our enum shall be a superset of booleans, hence first try
3350 * to parse as as boolean, and then as enum */
3352 k = parse_boolean(rvalue);
3354 c->protect_system = PROTECT_SYSTEM_YES;
3356 c->protect_system = PROTECT_SYSTEM_NO;
3360 s = protect_system_from_string(rvalue);
3362 log_syntax(unit, LOG_ERR, filename, line, -s,
3363 "Failed to parse protect system value, ignoring: %s", rvalue);
3367 c->protect_system = s;
3373 #define FOLLOW_MAX 8
3375 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
3386 /* This will update the filename pointer if the loaded file is
3387 * reached by a symlink. The old string will be freed. */
3390 char *target, *name;
3392 if (c++ >= FOLLOW_MAX)
3395 path_kill_slashes(*filename);
3397 /* Add the file name we are currently looking at to
3398 * the names of this unit, but only if it is a valid
3400 name = basename(*filename);
3402 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
3404 id = set_get(names, name);
3410 r = set_consume(names, id);
3416 /* Try to open the file name, but don't if its a symlink */
3417 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
3424 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
3425 r = readlink_and_make_absolute(*filename, &target);
3433 f = fdopen(fd, "re");
3444 static int merge_by_names(Unit **u, Set *names, const char *id) {
3452 /* Let's try to add in all symlink names we found */
3453 while ((k = set_steal_first(names))) {
3455 /* First try to merge in the other name into our
3457 r = unit_merge_by_name(*u, k);
3461 /* Hmm, we couldn't merge the other unit into
3462 * ours? Then let's try it the other way
3465 other = manager_get_unit((*u)->manager, k);
3469 r = unit_merge(other, *u);
3472 return merge_by_names(u, names, NULL);
3480 unit_choose_id(*u, id);
3488 static int load_from_path(Unit *u, const char *path) {
3490 _cleanup_set_free_free_ Set *symlink_names = NULL;
3491 _cleanup_fclose_ FILE *f = NULL;
3492 _cleanup_free_ char *filename = NULL;
3500 symlink_names = set_new(&string_hash_ops);
3504 if (path_is_absolute(path)) {
3506 filename = strdup(path);
3510 r = open_follow(&filename, &f, symlink_names, &id);
3522 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3524 /* Instead of opening the path right away, we manually
3525 * follow all symlinks and add their name to our unit
3526 * name set while doing so */
3527 filename = path_make_absolute(path, *p);
3531 if (u->manager->unit_path_cache &&
3532 !set_get(u->manager->unit_path_cache, filename))
3535 r = open_follow(&filename, &f, symlink_names, &id);
3544 /* Empty the symlink names for the next run */
3545 set_clear_free(symlink_names);
3554 /* Hmm, no suitable file found? */
3558 r = merge_by_names(&merged, symlink_names, id);
3563 u->load_state = UNIT_MERGED;
3567 if (fstat(fileno(f), &st) < 0)
3570 if (null_or_empty(&st))
3571 u->load_state = UNIT_MASKED;
3573 u->load_state = UNIT_LOADED;
3575 /* Now, parse the file contents */
3576 r = config_parse(u->id, filename, f,
3577 UNIT_VTABLE(u)->sections,
3578 config_item_perf_lookup, load_fragment_gperf_lookup,
3579 false, true, false, u);
3584 free(u->fragment_path);
3585 u->fragment_path = filename;
3588 u->fragment_mtime = timespec_load(&st.st_mtim);
3590 if (u->source_path) {
3591 if (stat(u->source_path, &st) >= 0)
3592 u->source_mtime = timespec_load(&st.st_mtim);
3594 u->source_mtime = 0;
3600 int unit_load_fragment(Unit *u) {
3606 assert(u->load_state == UNIT_STUB);
3609 /* First, try to find the unit under its id. We always look
3610 * for unit files in the default directories, to make it easy
3611 * to override things by placing things in /etc/systemd/system */
3612 r = load_from_path(u, u->id);
3616 /* Try to find an alias we can load this with */
3617 if (u->load_state == UNIT_STUB) {
3618 SET_FOREACH(t, u->names, i) {
3623 r = load_from_path(u, t);
3627 if (u->load_state != UNIT_STUB)
3632 /* And now, try looking for it under the suggested (originally linked) path */
3633 if (u->load_state == UNIT_STUB && u->fragment_path) {
3635 r = load_from_path(u, u->fragment_path);
3639 if (u->load_state == UNIT_STUB) {
3640 /* Hmm, this didn't work? Then let's get rid
3641 * of the fragment path stored for us, so that
3642 * we don't point to an invalid location. */
3643 free(u->fragment_path);
3644 u->fragment_path = NULL;
3648 /* Look for a template */
3649 if (u->load_state == UNIT_STUB && u->instance) {
3650 _cleanup_free_ char *k;
3652 k = unit_name_template(u->id);
3656 r = load_from_path(u, k);
3660 if (u->load_state == UNIT_STUB) {
3661 SET_FOREACH(t, u->names, i) {
3662 _cleanup_free_ char *z = NULL;
3667 z = unit_name_template(t);
3671 r = load_from_path(u, z);
3675 if (u->load_state != UNIT_STUB)
3684 void unit_dump_config_items(FILE *f) {
3685 static const struct {
3686 const ConfigParserCallback callback;
3689 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3690 { config_parse_warn_compat, "NOTSUPPORTED" },
3692 { config_parse_int, "INTEGER" },
3693 { config_parse_unsigned, "UNSIGNED" },
3694 { config_parse_iec_size, "SIZE" },
3695 { config_parse_iec_off, "SIZE" },
3696 { config_parse_si_size, "SIZE" },
3697 { config_parse_bool, "BOOLEAN" },
3698 { config_parse_string, "STRING" },
3699 { config_parse_path, "PATH" },
3700 { config_parse_unit_path_printf, "PATH" },
3701 { config_parse_strv, "STRING [...]" },
3702 { config_parse_exec_nice, "NICE" },
3703 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3704 { config_parse_exec_io_class, "IOCLASS" },
3705 { config_parse_exec_io_priority, "IOPRIORITY" },
3706 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3707 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3708 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3709 { config_parse_mode, "MODE" },
3710 { config_parse_unit_env_file, "FILE" },
3711 { config_parse_output, "OUTPUT" },
3712 { config_parse_input, "INPUT" },
3713 { config_parse_log_facility, "FACILITY" },
3714 { config_parse_log_level, "LEVEL" },
3715 { config_parse_exec_capabilities, "CAPABILITIES" },
3716 { config_parse_exec_secure_bits, "SECUREBITS" },
3717 { config_parse_bounding_set, "BOUNDINGSET" },
3718 { config_parse_limit, "LIMIT" },
3719 { config_parse_unit_deps, "UNIT [...]" },
3720 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3721 { config_parse_service_type, "SERVICETYPE" },
3722 { config_parse_service_restart, "SERVICERESTART" },
3723 #ifdef HAVE_SYSV_COMPAT
3724 { config_parse_sysv_priority, "SYSVPRIORITY" },
3726 { config_parse_kill_mode, "KILLMODE" },
3727 { config_parse_kill_signal, "SIGNAL" },
3728 { config_parse_socket_listen, "SOCKET [...]" },
3729 { config_parse_socket_bind, "SOCKETBIND" },
3730 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3731 { config_parse_sec, "SECONDS" },
3732 { config_parse_nsec, "NANOSECONDS" },
3733 { config_parse_namespace_path_strv, "PATH [...]" },
3734 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3735 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3736 { config_parse_unit_string_printf, "STRING" },
3737 { config_parse_trigger_unit, "UNIT" },
3738 { config_parse_timer, "TIMER" },
3739 { config_parse_path_spec, "PATH" },
3740 { config_parse_notify_access, "ACCESS" },
3741 { config_parse_ip_tos, "TOS" },
3742 { config_parse_unit_condition_path, "CONDITION" },
3743 { config_parse_unit_condition_string, "CONDITION" },
3744 { config_parse_unit_condition_null, "CONDITION" },
3745 { config_parse_unit_slice, "SLICE" },
3746 { config_parse_documentation, "URL" },
3747 { config_parse_service_timeout, "SECONDS" },
3748 { config_parse_failure_action, "ACTION" },
3749 { config_parse_set_status, "STATUS" },
3750 { config_parse_service_sockets, "SOCKETS" },
3751 { config_parse_environ, "ENVIRON" },
3753 { config_parse_syscall_filter, "SYSCALLS" },
3754 { config_parse_syscall_archs, "ARCHS" },
3755 { config_parse_syscall_errno, "ERRNO" },
3756 { config_parse_address_families, "FAMILIES" },
3758 { config_parse_cpu_shares, "SHARES" },
3759 { config_parse_memory_limit, "LIMIT" },
3760 { config_parse_device_allow, "DEVICE" },
3761 { config_parse_device_policy, "POLICY" },
3762 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3763 { config_parse_blockio_weight, "WEIGHT" },
3764 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3765 { config_parse_long, "LONG" },
3766 { config_parse_socket_service, "SERVICE" },
3768 { config_parse_exec_selinux_context, "LABEL" },
3770 { config_parse_job_mode, "MODE" },
3771 { config_parse_job_mode_isolate, "BOOLEAN" },
3772 { config_parse_personality, "PERSONALITY" },
3775 const char *prev = NULL;
3780 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3781 const char *rvalue = "OTHER", *lvalue;
3785 const ConfigPerfItem *p;
3787 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3789 dot = strchr(i, '.');
3790 lvalue = dot ? dot + 1 : i;
3794 if (!prev || !strneq(prev, i, prefix_len+1)) {
3798 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3801 for (j = 0; j < ELEMENTSOF(table); j++)
3802 if (p->parse == table[j].callback) {
3803 rvalue = table[j].rvalue;
3807 fprintf(f, "%s=%s\n", lvalue, rvalue);