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>
41 #include "sd-messages.h"
44 #include "conf-parser.h"
45 #include "load-fragment.h"
48 #include "securebits.h"
50 #include "unit-name.h"
51 #include "unit-printf.h"
53 #include "path-util.h"
57 #include "bus-error.h"
58 #include "errno-list.h"
61 #include "seccomp-util.h"
64 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
65 int config_parse_warn_compat(
70 unsigned section_line,
77 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
78 "Support for option %s= has been disabled at compile time and is ignored",
84 int config_parse_unit_deps(const char* unit,
88 unsigned section_line,
95 UnitDependency d = ltype;
105 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
106 _cleanup_free_ char *t = NULL, *k = NULL;
113 r = unit_name_printf(u, t, &k);
115 log_syntax(unit, LOG_ERR, filename, line, -r,
116 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
120 r = unit_add_dependency_by_name(u, d, k, NULL, true);
122 log_syntax(unit, LOG_ERR, filename, line, -r,
123 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
129 int config_parse_unit_string_printf(const char *unit,
130 const char *filename,
133 unsigned section_line,
141 _cleanup_free_ char *k = NULL;
149 r = unit_full_printf(u, rvalue, &k);
151 log_syntax(unit, LOG_ERR, filename, line, -r,
152 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
154 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
155 k ? k : rvalue, data, userdata);
158 int config_parse_unit_strv_printf(const char *unit,
159 const char *filename,
162 unsigned section_line,
170 _cleanup_free_ char *k = NULL;
178 r = unit_full_printf(u, rvalue, &k);
180 log_syntax(unit, LOG_ERR, filename, line, -r,
181 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
183 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
184 k ? k : rvalue, data, userdata);
187 int config_parse_unit_path_printf(const char *unit,
188 const char *filename,
191 unsigned section_line,
199 _cleanup_free_ char *k = NULL;
207 r = unit_full_printf(u, rvalue, &k);
209 log_syntax(unit, LOG_ERR, filename, line, -r,
210 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
212 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype,
213 k ? k : rvalue, data, userdata);
216 int config_parse_socket_listen(const char *unit,
217 const char *filename,
220 unsigned section_line,
227 SocketPort *p, *tail;
238 if (isempty(rvalue)) {
239 /* An empty assignment removes all ports */
240 socket_free_ports(s);
244 p = new0(SocketPort, 1);
248 if (ltype != SOCKET_SOCKET) {
251 r = unit_full_printf(UNIT(s), rvalue, &p->path);
253 p->path = strdup(rvalue);
258 log_syntax(unit, LOG_ERR, filename, line, -r,
259 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
262 path_kill_slashes(p->path);
264 } else if (streq(lvalue, "ListenNetlink")) {
265 _cleanup_free_ char *k = NULL;
267 p->type = SOCKET_SOCKET;
268 r = unit_full_printf(UNIT(s), rvalue, &k);
270 log_syntax(unit, LOG_ERR, filename, line, -r,
271 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
273 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
275 log_syntax(unit, LOG_ERR, filename, line, -r,
276 "Failed to parse address value, ignoring: %s", rvalue);
282 _cleanup_free_ char *k = NULL;
284 p->type = SOCKET_SOCKET;
285 r = unit_full_printf(UNIT(s), rvalue, &k);
287 log_syntax(unit, LOG_ERR, filename, line, -r,
288 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
290 r = socket_address_parse(&p->address, k ? k : rvalue);
292 log_syntax(unit, LOG_ERR, filename, line, -r,
293 "Failed to parse address value, ignoring: %s", rvalue);
298 if (streq(lvalue, "ListenStream"))
299 p->address.type = SOCK_STREAM;
300 else if (streq(lvalue, "ListenDatagram"))
301 p->address.type = SOCK_DGRAM;
303 assert(streq(lvalue, "ListenSequentialPacket"));
304 p->address.type = SOCK_SEQPACKET;
307 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
308 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
309 "Address family not supported, ignoring: %s", rvalue);
319 LIST_FIND_TAIL(port, s->ports, tail);
320 LIST_INSERT_AFTER(port, s->ports, tail, p);
322 LIST_PREPEND(port, s->ports, p);
327 int config_parse_socket_bind(const char *unit,
328 const char *filename,
331 unsigned section_line,
339 SocketAddressBindIPv6Only b;
348 b = socket_address_bind_ipv6_only_from_string(rvalue);
352 r = parse_boolean(rvalue);
354 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
355 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
359 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
361 s->bind_ipv6_only = b;
366 int config_parse_exec_nice(const char *unit,
367 const char *filename,
370 unsigned section_line,
377 ExecContext *c = data;
385 r = safe_atoi(rvalue, &priority);
387 log_syntax(unit, LOG_ERR, filename, line, -r,
388 "Failed to parse nice priority, ignoring: %s. ", rvalue);
392 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
393 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
394 "Nice priority out of range, ignoring: %s", rvalue);
404 int config_parse_exec_oom_score_adjust(const char* unit,
405 const char *filename,
408 unsigned section_line,
415 ExecContext *c = data;
423 r = safe_atoi(rvalue, &oa);
425 log_syntax(unit, LOG_ERR, filename, line, -r,
426 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
430 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
431 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
432 "OOM score adjust value out of range, ignoring: %s", rvalue);
436 c->oom_score_adjust = oa;
437 c->oom_score_adjust_set = true;
442 int config_parse_exec(const char *unit,
443 const char *filename,
446 unsigned section_line,
453 ExecCommand **e = data, *nce;
465 if (isempty(rvalue)) {
466 /* An empty assignment resets the list */
467 exec_command_free_list(*e);
472 /* We accept an absolute path as first argument, or
473 * alternatively an absolute prefixed with @ to allow
474 * overriding of argv[0]. */
480 bool honour_argv0 = false, ignore = false;
486 rvalue += strspn(rvalue, WHITESPACE);
491 for (i = 0; i < 2; i++) {
492 if (rvalue[0] == '-' && !ignore) {
497 if (rvalue[0] == '@' && !honour_argv0) {
503 if (*rvalue != '/') {
504 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
505 "Executable path is not absolute, ignoring: %s", rvalue);
510 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
511 if (strneq(w, ";", MAX(l, 1U)))
517 n = new(char*, k + !honour_argv0);
522 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
523 if (strneq(w, ";", MAX(l, 1U)))
525 else if (strneq(w, "\\;", MAX(l, 1U)))
528 if (honour_argv0 && w == rvalue) {
531 path = strndup(w, l);
537 if (!utf8_is_valid(path)) {
538 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
539 "Path is not UTF-8 clean, ignoring assignment: %s",
548 c = n[k++] = cunescape_length(w, l);
554 if (!utf8_is_valid(c)) {
555 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
556 "Path is not UTF-8 clean, ignoring assignment: %s",
567 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
568 "Invalid command line, ignoring: %s", rvalue);
581 assert(path_is_absolute(path));
583 nce = new0(ExecCommand, 1);
591 nce->ignore = ignore;
593 path_kill_slashes(nce->path);
595 exec_command_append_list(e, nce);
611 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
612 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
614 int config_parse_socket_bindtodevice(const char* unit,
615 const char *filename,
618 unsigned section_line,
633 if (rvalue[0] && !streq(rvalue, "*")) {
640 free(s->bind_to_device);
641 s->bind_to_device = n;
646 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
647 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
649 int config_parse_exec_io_class(const char *unit,
650 const char *filename,
653 unsigned section_line,
660 ExecContext *c = data;
668 x = ioprio_class_from_string(rvalue);
670 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
671 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
675 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
676 c->ioprio_set = true;
681 int config_parse_exec_io_priority(const char *unit,
682 const char *filename,
685 unsigned section_line,
692 ExecContext *c = data;
700 r = safe_atoi(rvalue, &i);
701 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
702 log_syntax(unit, LOG_ERR, filename, line, -r,
703 "Failed to parse IO priority, ignoring: %s", rvalue);
707 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
708 c->ioprio_set = true;
713 int config_parse_exec_cpu_sched_policy(const char *unit,
714 const char *filename,
717 unsigned section_line,
725 ExecContext *c = data;
733 x = sched_policy_from_string(rvalue);
735 log_syntax(unit, LOG_ERR, filename, line, -x,
736 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
740 c->cpu_sched_policy = x;
741 /* Moving to or from real-time policy? We need to adjust the priority */
742 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
743 c->cpu_sched_set = true;
748 int config_parse_exec_cpu_sched_prio(const char *unit,
749 const char *filename,
752 unsigned section_line,
759 ExecContext *c = data;
767 r = safe_atoi(rvalue, &i);
769 log_syntax(unit, LOG_ERR, filename, line, -r,
770 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
774 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
775 min = sched_get_priority_min(c->cpu_sched_policy);
776 max = sched_get_priority_max(c->cpu_sched_policy);
778 if (i < min || i > max) {
779 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
780 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
784 c->cpu_sched_priority = i;
785 c->cpu_sched_set = true;
790 int config_parse_exec_cpu_affinity(const char *unit,
791 const char *filename,
794 unsigned section_line,
801 ExecContext *c = data;
811 if (isempty(rvalue)) {
812 /* An empty assignment resets the CPU list */
819 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
820 _cleanup_free_ char *t = NULL;
828 r = safe_atou(t, &cpu);
831 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
836 if (r < 0 || cpu >= c->cpuset_ncpus) {
837 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
838 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
842 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
848 int config_parse_exec_capabilities(const char *unit,
849 const char *filename,
852 unsigned section_line,
859 ExecContext *c = data;
867 cap = cap_from_text(rvalue);
869 log_syntax(unit, LOG_ERR, filename, line, errno,
870 "Failed to parse capabilities, ignoring: %s", rvalue);
875 cap_free(c->capabilities);
876 c->capabilities = cap;
881 int config_parse_exec_secure_bits(const char *unit,
882 const char *filename,
885 unsigned section_line,
892 ExecContext *c = data;
902 if (isempty(rvalue)) {
903 /* An empty assignment resets the field */
908 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
909 if (first_word(w, "keep-caps"))
910 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
911 else if (first_word(w, "keep-caps-locked"))
912 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
913 else if (first_word(w, "no-setuid-fixup"))
914 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
915 else if (first_word(w, "no-setuid-fixup-locked"))
916 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
917 else if (first_word(w, "noroot"))
918 c->secure_bits |= 1<<SECURE_NOROOT;
919 else if (first_word(w, "noroot-locked"))
920 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
922 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
923 "Failed to parse secure bits, ignoring: %s", rvalue);
931 int config_parse_bounding_set(const char *unit,
932 const char *filename,
935 unsigned section_line,
942 uint64_t *capability_bounding_set_drop = data;
954 if (rvalue[0] == '~') {
959 /* Note that we store this inverted internally, since the
960 * kernel wants it like this. But we actually expose it
961 * non-inverted everywhere to have a fully normalized
964 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
965 _cleanup_free_ char *t = NULL;
973 r = cap_from_name(t, &cap);
975 log_syntax(unit, LOG_ERR, filename, line, errno,
976 "Failed to parse capability in bounding set, ignoring: %s", t);
980 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
984 *capability_bounding_set_drop |= sum;
986 *capability_bounding_set_drop |= ~sum;
991 int config_parse_limit(const char *unit,
992 const char *filename,
995 unsigned section_line,
1002 struct rlimit **rl = data;
1003 unsigned long long u;
1012 if (streq(rvalue, "infinity"))
1013 u = (unsigned long long) RLIM_INFINITY;
1017 r = safe_atollu(rvalue, &u);
1019 log_syntax(unit, LOG_ERR, filename, line, -r,
1020 "Failed to parse resource value, ignoring: %s", rvalue);
1026 *rl = new(struct rlimit, 1);
1031 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1035 #ifdef HAVE_SYSV_COMPAT
1036 int config_parse_sysv_priority(const char *unit,
1037 const char *filename,
1039 const char *section,
1040 unsigned section_line,
1047 int *priority = data;
1055 r = safe_atoi(rvalue, &i);
1056 if (r < 0 || i < 0) {
1057 log_syntax(unit, LOG_ERR, filename, line, -r,
1058 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1062 *priority = (int) i;
1067 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1069 int config_parse_kill_signal(const char *unit,
1070 const char *filename,
1072 const char *section,
1073 unsigned section_line,
1088 r = signal_from_string_try_harder(rvalue);
1090 log_syntax(unit, LOG_ERR, filename, line, -r,
1091 "Failed to parse kill signal, ignoring: %s", rvalue);
1099 int config_parse_exec_mount_flags(const char *unit,
1100 const char *filename,
1102 const char *section,
1103 unsigned section_line,
1110 ExecContext *c = data;
1114 unsigned long flags = 0;
1121 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1122 _cleanup_free_ char *t;
1128 if (streq(t, "shared"))
1130 else if (streq(t, "slave"))
1132 else if (streq(w, "private"))
1133 flags |= MS_PRIVATE;
1135 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1136 "Failed to parse mount flag %s, ignoring: %s",
1142 c->mount_flags = flags;
1146 int config_parse_exec_selinux_context(
1148 const char *filename,
1150 const char *section,
1151 unsigned section_line,
1158 ExecContext *c = data;
1169 if (isempty(rvalue)) {
1170 free(c->selinux_context);
1171 c->selinux_context = NULL;
1172 c->selinux_context_ignore = false;
1176 if (rvalue[0] == '-') {
1182 r = unit_name_printf(u, rvalue, &k);
1184 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1188 free(c->selinux_context);
1189 c->selinux_context = k;
1190 c->selinux_context_ignore = ignore;
1195 int config_parse_exec_apparmor_profile(
1197 const char *filename,
1199 const char *section,
1200 unsigned section_line,
1207 ExecContext *c = data;
1218 if (isempty(rvalue)) {
1219 free(c->apparmor_profile);
1220 c->apparmor_profile = NULL;
1221 c->apparmor_profile_ignore = false;
1225 if (rvalue[0] == '-') {
1231 r = unit_name_printf(u, rvalue, &k);
1233 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1237 free(c->apparmor_profile);
1238 c->apparmor_profile = k;
1239 c->apparmor_profile_ignore = ignore;
1244 int config_parse_timer(const char *unit,
1245 const char *filename,
1247 const char *section,
1248 unsigned section_line,
1259 CalendarSpec *c = NULL;
1267 if (isempty(rvalue)) {
1268 /* Empty assignment resets list */
1269 timer_free_values(t);
1273 b = timer_base_from_string(lvalue);
1275 log_syntax(unit, LOG_ERR, filename, line, -b,
1276 "Failed to parse timer base, ignoring: %s", lvalue);
1280 if (b == TIMER_CALENDAR) {
1281 if (calendar_spec_from_string(rvalue, &c) < 0) {
1282 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1283 "Failed to parse calendar specification, ignoring: %s",
1288 id = CLOCK_REALTIME;
1290 if (parse_sec(rvalue, &u) < 0) {
1291 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1292 "Failed to parse timer value, ignoring: %s",
1297 id = CLOCK_MONOTONIC;
1300 v = new0(TimerValue, 1);
1307 v->calendar_spec = c;
1309 LIST_PREPEND(value, t->values, v);
1314 int config_parse_trigger_unit(
1316 const char *filename,
1318 const char *section,
1319 unsigned section_line,
1326 _cleanup_free_ char *p = NULL;
1336 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1337 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1338 "Multiple units to trigger specified, ignoring: %s", rvalue);
1342 r = unit_name_printf(u, rvalue, &p);
1344 log_syntax(unit, LOG_ERR, filename, line, -r,
1345 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1347 type = unit_name_to_type(p ?: rvalue);
1349 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1350 "Unit type not valid, ignoring: %s", rvalue);
1354 if (type == u->type) {
1355 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1356 "Trigger cannot be of same type, ignoring: %s", rvalue);
1360 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1362 log_syntax(unit, LOG_ERR, filename, line, -r,
1363 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1370 int config_parse_path_spec(const char *unit,
1371 const char *filename,
1373 const char *section,
1374 unsigned section_line,
1384 _cleanup_free_ char *k = NULL;
1392 if (isempty(rvalue)) {
1393 /* Empty assignment clears list */
1398 b = path_type_from_string(lvalue);
1400 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1401 "Failed to parse path type, ignoring: %s", lvalue);
1405 r = unit_full_printf(UNIT(p), rvalue, &k);
1411 log_syntax(unit, LOG_ERR, filename, line, -r,
1412 "Failed to resolve unit specifiers on %s. Ignoring.",
1416 if (!path_is_absolute(k)) {
1417 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1418 "Path is not absolute, ignoring: %s", k);
1422 s = new0(PathSpec, 1);
1427 s->path = path_kill_slashes(k);
1432 LIST_PREPEND(spec, p->specs, s);
1437 int config_parse_socket_service(const char *unit,
1438 const char *filename,
1440 const char *section,
1441 unsigned section_line,
1448 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1452 _cleanup_free_ char *p = NULL;
1459 r = unit_name_printf(UNIT(s), rvalue, &p);
1461 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1465 if (!endswith(p, ".service")) {
1466 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1470 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1472 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1476 unit_ref_set(&s->service, x);
1481 int config_parse_service_sockets(const char *unit,
1482 const char *filename,
1484 const char *section,
1485 unsigned section_line,
1502 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1503 _cleanup_free_ char *t = NULL, *k = NULL;
1509 r = unit_name_printf(UNIT(s), t, &k);
1511 log_syntax(unit, LOG_ERR, filename, line, -r,
1512 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1514 if (!endswith(k ?: t, ".socket")) {
1515 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1516 "Unit must be of type socket, ignoring: %s", k ?: t);
1520 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1522 log_syntax(unit, LOG_ERR, filename, line, -r,
1523 "Failed to add dependency on %s, ignoring: %s",
1524 k ?: t, strerror(-r));
1526 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1534 int config_parse_service_timeout(const char *unit,
1535 const char *filename,
1537 const char *section,
1538 unsigned section_line,
1545 Service *s = userdata;
1553 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1554 rvalue, data, userdata);
1558 if (streq(lvalue, "TimeoutSec")) {
1559 s->start_timeout_defined = true;
1560 s->timeout_stop_usec = s->timeout_start_usec;
1561 } else if (streq(lvalue, "TimeoutStartSec"))
1562 s->start_timeout_defined = true;
1567 int config_parse_busname_service(
1569 const char *filename,
1571 const char *section,
1572 unsigned section_line,
1579 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1583 _cleanup_free_ char *p = NULL;
1590 r = unit_name_printf(UNIT(n), rvalue, &p);
1592 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1596 if (!endswith(p, ".service")) {
1597 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1601 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1603 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1607 unit_ref_set(&n->service, x);
1612 int config_parse_unit_env_file(const char *unit,
1613 const char *filename,
1615 const char *section,
1616 unsigned section_line,
1625 _cleanup_free_ char *n = NULL;
1634 if (isempty(rvalue)) {
1635 /* Empty assignment frees the list */
1641 r = unit_full_printf(u, rvalue, &n);
1643 log_syntax(unit, LOG_ERR, filename, line, r,
1644 "Failed to resolve specifiers, ignoring: %s", rvalue);
1647 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1648 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1649 "Path '%s' is not absolute, ignoring.", s);
1653 r = strv_extend(env, s);
1660 int config_parse_environ(const char *unit,
1661 const char *filename,
1663 const char *section,
1664 unsigned section_line,
1672 char*** env = data, *w, *state;
1674 _cleanup_free_ char *k = NULL;
1682 if (isempty(rvalue)) {
1683 /* Empty assignment resets the list */
1690 r = unit_full_printf(u, rvalue, &k);
1692 log_syntax(unit, LOG_ERR, filename, line, -r,
1693 "Failed to resolve specifiers, ignoring: %s", rvalue);
1701 FOREACH_WORD_QUOTED(w, l, k, state) {
1702 _cleanup_free_ char *n;
1705 n = cunescape_length(w, l);
1709 if (!env_assignment_is_valid(n)) {
1710 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1711 "Invalid environment assignment, ignoring: %s", rvalue);
1715 x = strv_env_set(*env, n);
1726 int config_parse_ip_tos(const char *unit,
1727 const char *filename,
1729 const char *section,
1730 unsigned section_line,
1737 int *ip_tos = data, x;
1744 x = ip_tos_from_string(rvalue);
1746 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1747 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1755 int config_parse_unit_condition_path(const char *unit,
1756 const char *filename,
1758 const char *section,
1759 unsigned section_line,
1766 ConditionType cond = ltype;
1768 bool trigger, negate;
1770 _cleanup_free_ char *p = NULL;
1778 if (isempty(rvalue)) {
1779 /* Empty assignment resets the list */
1780 condition_free_list(u->conditions);
1781 u->conditions = NULL;
1785 trigger = rvalue[0] == '|';
1789 negate = rvalue[0] == '!';
1793 r = unit_full_printf(u, rvalue, &p);
1795 log_syntax(unit, LOG_ERR, filename, line, -r,
1796 "Failed to resolve specifiers, ignoring: %s", rvalue);
1803 if (!path_is_absolute(p)) {
1804 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1805 "Path in condition not absolute, ignoring: %s", p);
1809 c = condition_new(cond, p, trigger, negate);
1813 LIST_PREPEND(conditions, u->conditions, c);
1817 int config_parse_unit_condition_string(const char *unit,
1818 const char *filename,
1820 const char *section,
1821 unsigned section_line,
1828 ConditionType cond = ltype;
1830 bool trigger, negate;
1832 _cleanup_free_ char *s = NULL;
1840 if (isempty(rvalue)) {
1841 /* Empty assignment resets the list */
1842 condition_free_list(u->conditions);
1843 u->conditions = NULL;
1847 trigger = rvalue[0] == '|';
1851 negate = rvalue[0] == '!';
1855 r = unit_full_printf(u, rvalue, &s);
1857 log_syntax(unit, LOG_ERR, filename, line, -r,
1858 "Failed to resolve specifiers, ignoring: %s", rvalue);
1865 c = condition_new(cond, s, trigger, negate);
1869 LIST_PREPEND(conditions, u->conditions, c);
1873 int config_parse_unit_condition_null(const char *unit,
1874 const char *filename,
1876 const char *section,
1877 unsigned section_line,
1886 bool trigger, negate;
1894 if (isempty(rvalue)) {
1895 /* Empty assignment resets the list */
1896 condition_free_list(u->conditions);
1897 u->conditions = NULL;
1901 trigger = rvalue[0] == '|';
1905 negate = rvalue[0] == '!';
1909 b = parse_boolean(rvalue);
1911 log_syntax(unit, LOG_ERR, filename, line, -b,
1912 "Failed to parse boolean value in condition, ignoring: %s",
1920 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1924 LIST_PREPEND(conditions, u->conditions, c);
1928 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1929 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1931 int config_parse_unit_requires_mounts_for(
1933 const char *filename,
1935 const char *section,
1936 unsigned section_line,
1953 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1955 _cleanup_free_ char *n;
1961 if (!utf8_is_valid(n)) {
1962 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1963 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
1967 r = unit_require_mounts_for(u, n);
1969 log_syntax(unit, LOG_ERR, filename, line, r,
1970 "Failed to add required mount for, ignoring: %s", rvalue);
1978 int config_parse_documentation(const char *unit,
1979 const char *filename,
1981 const char *section,
1982 unsigned section_line,
1998 if (isempty(rvalue)) {
1999 /* Empty assignment resets the list */
2000 strv_free(u->documentation);
2001 u->documentation = NULL;
2005 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2006 rvalue, data, userdata);
2010 for (a = b = u->documentation; a && *a; a++) {
2012 if (is_valid_documentation_url(*a))
2015 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2016 "Invalid URL, ignoring: %s", *a);
2027 int config_parse_syscall_filter(
2029 const char *filename,
2031 const char *section,
2032 unsigned section_line,
2039 static const char default_syscalls[] =
2046 ExecContext *c = data;
2048 bool invert = false;
2058 if (isempty(rvalue)) {
2059 /* Empty assignment resets the list */
2060 set_free(c->syscall_filter);
2061 c->syscall_filter = NULL;
2062 c->syscall_whitelist = false;
2066 if (rvalue[0] == '~') {
2071 if (!c->syscall_filter) {
2072 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2073 if (!c->syscall_filter)
2077 /* Allow everything but the ones listed */
2078 c->syscall_whitelist = false;
2082 /* Allow nothing but the ones listed */
2083 c->syscall_whitelist = true;
2085 /* Accept default syscalls if we are on a whitelist */
2086 NULSTR_FOREACH(i, default_syscalls) {
2089 id = seccomp_syscall_resolve_name(i);
2093 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2102 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2103 _cleanup_free_ char *t = NULL;
2110 id = seccomp_syscall_resolve_name(t);
2112 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2116 /* If we previously wanted to forbid a syscall and now
2117 * we want to allow it, then remove it from the list
2119 if (!invert == c->syscall_whitelist) {
2120 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2126 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2129 c->no_new_privileges = true;
2134 int config_parse_syscall_archs(
2136 const char *filename,
2138 const char *section,
2139 unsigned section_line,
2151 if (isempty(rvalue)) {
2157 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2161 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2162 _cleanup_free_ char *t = NULL;
2169 r = seccomp_arch_from_string(t, &a);
2171 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2175 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2185 int config_parse_syscall_errno(
2187 const char *filename,
2189 const char *section,
2190 unsigned section_line,
2197 ExecContext *c = data;
2204 if (isempty(rvalue)) {
2205 /* Empty assignment resets to KILL */
2206 c->syscall_errno = 0;
2210 e = errno_from_name(rvalue);
2212 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2216 c->syscall_errno = e;
2221 int config_parse_unit_slice(
2223 const char *filename,
2225 const char *section,
2226 unsigned section_line,
2233 _cleanup_free_ char *k = NULL;
2234 Unit *u = userdata, *slice;
2242 r = unit_name_printf(u, rvalue, &k);
2244 log_syntax(unit, LOG_ERR, filename, line, -r,
2245 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2252 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2254 log_syntax(unit, LOG_ERR, filename, line, -r,
2255 "Failed to load slice unit %s. Ignoring.", k);
2259 if (slice->type != UNIT_SLICE) {
2260 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2261 "Slice unit %s is not a slice. Ignoring.", k);
2265 unit_ref_set(&u->slice, slice);
2269 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2271 int config_parse_cpu_shares(
2273 const char *filename,
2275 const char *section,
2276 unsigned section_line,
2283 CGroupContext *c = data;
2291 if (isempty(rvalue)) {
2292 c->cpu_shares = 1024;
2296 r = safe_atolu(rvalue, &lu);
2297 if (r < 0 || lu <= 0) {
2298 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2299 "CPU shares '%s' invalid. Ignoring.", rvalue);
2307 int config_parse_memory_limit(
2309 const char *filename,
2311 const char *section,
2312 unsigned section_line,
2319 CGroupContext *c = data;
2323 if (isempty(rvalue)) {
2324 c->memory_limit = (uint64_t) -1;
2328 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2330 r = parse_bytes(rvalue, &bytes);
2332 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2333 "Memory limit '%s' invalid. Ignoring.", rvalue);
2337 c->memory_limit = (uint64_t) bytes;
2341 int config_parse_device_allow(
2343 const char *filename,
2345 const char *section,
2346 unsigned section_line,
2353 _cleanup_free_ char *path = NULL;
2354 CGroupContext *c = data;
2355 CGroupDeviceAllow *a;
2359 if (isempty(rvalue)) {
2360 while (c->device_allow)
2361 cgroup_context_free_device_allow(c, c->device_allow);
2366 n = strcspn(rvalue, WHITESPACE);
2367 path = strndup(rvalue, n);
2371 if (!path_startswith(path, "/dev")) {
2372 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2373 "Invalid device node path '%s'. Ignoring.", path);
2377 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2381 if (!in_charset(m, "rwm")) {
2382 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2383 "Invalid device rights '%s'. Ignoring.", m);
2387 a = new0(CGroupDeviceAllow, 1);
2393 a->r = !!strchr(m, 'r');
2394 a->w = !!strchr(m, 'w');
2395 a->m = !!strchr(m, 'm');
2397 LIST_PREPEND(device_allow, c->device_allow, a);
2401 int config_parse_blockio_weight(
2403 const char *filename,
2405 const char *section,
2406 unsigned section_line,
2413 CGroupContext *c = data;
2421 if (isempty(rvalue)) {
2422 c->blockio_weight = 1000;
2426 r = safe_atolu(rvalue, &lu);
2427 if (r < 0 || lu < 10 || lu > 1000) {
2428 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2429 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2433 c->blockio_weight = lu;
2438 int config_parse_blockio_device_weight(
2440 const char *filename,
2442 const char *section,
2443 unsigned section_line,
2450 _cleanup_free_ char *path = NULL;
2451 CGroupBlockIODeviceWeight *w;
2452 CGroupContext *c = data;
2462 if (isempty(rvalue)) {
2463 while (c->blockio_device_weights)
2464 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2469 n = strcspn(rvalue, WHITESPACE);
2470 weight = rvalue + n;
2472 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2473 "Expected block device and device weight. Ignoring.");
2477 path = strndup(rvalue, n);
2481 if (!path_startswith(path, "/dev")) {
2482 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2483 "Invalid device node path '%s'. Ignoring.", path);
2487 weight += strspn(weight, WHITESPACE);
2488 r = safe_atolu(weight, &lu);
2489 if (r < 0 || lu < 10 || lu > 1000) {
2490 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2491 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2496 w = new0(CGroupBlockIODeviceWeight, 1);
2505 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2509 int config_parse_blockio_bandwidth(
2511 const char *filename,
2513 const char *section,
2514 unsigned section_line,
2521 _cleanup_free_ char *path = NULL;
2522 CGroupBlockIODeviceBandwidth *b;
2523 CGroupContext *c = data;
2524 const char *bandwidth;
2534 read = streq("BlockIOReadBandwidth", lvalue);
2536 if (isempty(rvalue)) {
2537 CGroupBlockIODeviceBandwidth *next;
2539 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2540 if (b->read == read)
2541 cgroup_context_free_blockio_device_bandwidth(c, b);
2546 n = strcspn(rvalue, WHITESPACE);
2547 bandwidth = rvalue + n;
2548 bandwidth += strspn(bandwidth, WHITESPACE);
2551 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2552 "Expected space separated pair of device node and bandwidth. Ignoring.");
2556 path = strndup(rvalue, n);
2560 if (!path_startswith(path, "/dev")) {
2561 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2562 "Invalid device node path '%s'. Ignoring.", path);
2566 r = parse_bytes(bandwidth, &bytes);
2567 if (r < 0 || bytes <= 0) {
2568 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2569 "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2573 b = new0(CGroupBlockIODeviceBandwidth, 1);
2579 b->bandwidth = (uint64_t) bytes;
2582 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2587 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2589 int config_parse_job_mode_isolate(
2591 const char *filename,
2593 const char *section,
2594 unsigned section_line,
2608 r = parse_boolean(rvalue);
2610 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2614 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2618 int config_parse_personality(
2620 const char *filename,
2622 const char *section,
2623 unsigned section_line,
2630 unsigned long *personality = data, p;
2635 assert(personality);
2637 p = personality_from_string(rvalue);
2638 if (p == 0xffffffffUL) {
2639 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2640 "Failed to parse personality, ignoring: %s", rvalue);
2648 #define FOLLOW_MAX 8
2650 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2661 /* This will update the filename pointer if the loaded file is
2662 * reached by a symlink. The old string will be freed. */
2665 char *target, *name;
2667 if (c++ >= FOLLOW_MAX)
2670 path_kill_slashes(*filename);
2672 /* Add the file name we are currently looking at to
2673 * the names of this unit, but only if it is a valid
2675 name = basename(*filename);
2677 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
2679 id = set_get(names, name);
2685 r = set_consume(names, id);
2691 /* Try to open the file name, but don't if its a symlink */
2692 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2699 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2700 r = readlink_and_make_absolute(*filename, &target);
2708 f = fdopen(fd, "re");
2711 close_nointr_nofail(fd);
2720 static int merge_by_names(Unit **u, Set *names, const char *id) {
2728 /* Let's try to add in all symlink names we found */
2729 while ((k = set_steal_first(names))) {
2731 /* First try to merge in the other name into our
2733 r = unit_merge_by_name(*u, k);
2737 /* Hmm, we couldn't merge the other unit into
2738 * ours? Then let's try it the other way
2741 other = manager_get_unit((*u)->manager, k);
2745 r = unit_merge(other, *u);
2748 return merge_by_names(u, names, NULL);
2756 unit_choose_id(*u, id);
2764 static int load_from_path(Unit *u, const char *path) {
2766 _cleanup_set_free_free_ Set *symlink_names = NULL;
2767 _cleanup_fclose_ FILE *f = NULL;
2768 _cleanup_free_ char *filename = NULL;
2776 symlink_names = set_new(string_hash_func, string_compare_func);
2780 if (path_is_absolute(path)) {
2782 filename = strdup(path);
2786 r = open_follow(&filename, &f, symlink_names, &id);
2798 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2800 /* Instead of opening the path right away, we manually
2801 * follow all symlinks and add their name to our unit
2802 * name set while doing so */
2803 filename = path_make_absolute(path, *p);
2807 if (u->manager->unit_path_cache &&
2808 !set_get(u->manager->unit_path_cache, filename))
2811 r = open_follow(&filename, &f, symlink_names, &id);
2820 /* Empty the symlink names for the next run */
2821 set_clear_free(symlink_names);
2830 /* Hmm, no suitable file found? */
2834 r = merge_by_names(&merged, symlink_names, id);
2839 u->load_state = UNIT_MERGED;
2843 if (fstat(fileno(f), &st) < 0)
2846 if (null_or_empty(&st))
2847 u->load_state = UNIT_MASKED;
2849 u->load_state = UNIT_LOADED;
2851 /* Now, parse the file contents */
2852 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
2853 config_item_perf_lookup,
2854 (void*) load_fragment_gperf_lookup, false, true, u);
2859 free(u->fragment_path);
2860 u->fragment_path = filename;
2863 u->fragment_mtime = timespec_load(&st.st_mtim);
2865 if (u->source_path) {
2866 if (stat(u->source_path, &st) >= 0)
2867 u->source_mtime = timespec_load(&st.st_mtim);
2869 u->source_mtime = 0;
2875 int unit_load_fragment(Unit *u) {
2881 assert(u->load_state == UNIT_STUB);
2884 /* First, try to find the unit under its id. We always look
2885 * for unit files in the default directories, to make it easy
2886 * to override things by placing things in /etc/systemd/system */
2887 r = load_from_path(u, u->id);
2891 /* Try to find an alias we can load this with */
2892 if (u->load_state == UNIT_STUB)
2893 SET_FOREACH(t, u->names, i) {
2898 r = load_from_path(u, t);
2902 if (u->load_state != UNIT_STUB)
2906 /* And now, try looking for it under the suggested (originally linked) path */
2907 if (u->load_state == UNIT_STUB && u->fragment_path) {
2909 r = load_from_path(u, u->fragment_path);
2913 if (u->load_state == UNIT_STUB) {
2914 /* Hmm, this didn't work? Then let's get rid
2915 * of the fragment path stored for us, so that
2916 * we don't point to an invalid location. */
2917 free(u->fragment_path);
2918 u->fragment_path = NULL;
2922 /* Look for a template */
2923 if (u->load_state == UNIT_STUB && u->instance) {
2924 _cleanup_free_ char *k;
2926 k = unit_name_template(u->id);
2930 r = load_from_path(u, k);
2934 if (u->load_state == UNIT_STUB)
2935 SET_FOREACH(t, u->names, i) {
2936 _cleanup_free_ char *z = NULL;
2941 z = unit_name_template(t);
2945 r = load_from_path(u, z);
2949 if (u->load_state != UNIT_STUB)
2957 void unit_dump_config_items(FILE *f) {
2958 static const struct {
2959 const ConfigParserCallback callback;
2962 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
2963 { config_parse_warn_compat, "NOTSUPPORTED" },
2965 { config_parse_int, "INTEGER" },
2966 { config_parse_unsigned, "UNSIGNED" },
2967 { config_parse_bytes_size, "SIZE" },
2968 { config_parse_bool, "BOOLEAN" },
2969 { config_parse_string, "STRING" },
2970 { config_parse_path, "PATH" },
2971 { config_parse_unit_path_printf, "PATH" },
2972 { config_parse_strv, "STRING [...]" },
2973 { config_parse_exec_nice, "NICE" },
2974 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2975 { config_parse_exec_io_class, "IOCLASS" },
2976 { config_parse_exec_io_priority, "IOPRIORITY" },
2977 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2978 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2979 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2980 { config_parse_mode, "MODE" },
2981 { config_parse_unit_env_file, "FILE" },
2982 { config_parse_output, "OUTPUT" },
2983 { config_parse_input, "INPUT" },
2984 { config_parse_facility, "FACILITY" },
2985 { config_parse_level, "LEVEL" },
2986 { config_parse_exec_capabilities, "CAPABILITIES" },
2987 { config_parse_exec_secure_bits, "SECUREBITS" },
2988 { config_parse_bounding_set, "BOUNDINGSET" },
2989 { config_parse_limit, "LIMIT" },
2990 { config_parse_unit_deps, "UNIT [...]" },
2991 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2992 { config_parse_service_type, "SERVICETYPE" },
2993 { config_parse_service_restart, "SERVICERESTART" },
2994 #ifdef HAVE_SYSV_COMPAT
2995 { config_parse_sysv_priority, "SYSVPRIORITY" },
2997 { config_parse_kill_mode, "KILLMODE" },
2998 { config_parse_kill_signal, "SIGNAL" },
2999 { config_parse_socket_listen, "SOCKET [...]" },
3000 { config_parse_socket_bind, "SOCKETBIND" },
3001 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3002 { config_parse_sec, "SECONDS" },
3003 { config_parse_nsec, "NANOSECONDS" },
3004 { config_parse_path_strv, "PATH [...]" },
3005 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3006 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3007 { config_parse_unit_string_printf, "STRING" },
3008 { config_parse_trigger_unit, "UNIT" },
3009 { config_parse_timer, "TIMER" },
3010 { config_parse_path_spec, "PATH" },
3011 { config_parse_notify_access, "ACCESS" },
3012 { config_parse_ip_tos, "TOS" },
3013 { config_parse_unit_condition_path, "CONDITION" },
3014 { config_parse_unit_condition_string, "CONDITION" },
3015 { config_parse_unit_condition_null, "CONDITION" },
3016 { config_parse_unit_slice, "SLICE" },
3017 { config_parse_documentation, "URL" },
3018 { config_parse_service_timeout, "SECONDS" },
3019 { config_parse_start_limit_action, "ACTION" },
3020 { config_parse_set_status, "STATUS" },
3021 { config_parse_service_sockets, "SOCKETS" },
3022 { config_parse_environ, "ENVIRON" },
3024 { config_parse_syscall_filter, "SYSCALLS" },
3025 { config_parse_syscall_archs, "ARCHS" },
3026 { config_parse_syscall_errno, "ERRNO" },
3028 { config_parse_cpu_shares, "SHARES" },
3029 { config_parse_memory_limit, "LIMIT" },
3030 { config_parse_device_allow, "DEVICE" },
3031 { config_parse_device_policy, "POLICY" },
3032 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3033 { config_parse_blockio_weight, "WEIGHT" },
3034 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3035 { config_parse_long, "LONG" },
3036 { config_parse_socket_service, "SERVICE" },
3038 { config_parse_exec_selinux_context, "LABEL" },
3040 { config_parse_job_mode, "MODE" },
3041 { config_parse_job_mode_isolate, "BOOLEAN" },
3044 const char *prev = NULL;
3049 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3050 const char *rvalue = "OTHER", *lvalue;
3054 const ConfigPerfItem *p;
3056 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3058 dot = strchr(i, '.');
3059 lvalue = dot ? dot + 1 : i;
3063 if (!prev || !strneq(prev, i, prefix_len+1)) {
3067 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3070 for (j = 0; j < ELEMENTSOF(table); j++)
3071 if (p->parse == table[j].callback) {
3072 rvalue = table[j].rvalue;
3076 fprintf(f, "%s=%s\n", lvalue, rvalue);