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>
39 #include "conf-parser.h"
40 #include "load-fragment.h"
43 #include "securebits.h"
45 #include "unit-name.h"
46 #include "unit-printf.h"
47 #include "bus-errors.h"
49 #include "path-util.h"
50 #include "syscall-list.h"
53 #ifndef HAVE_SYSV_COMPAT
54 int config_parse_warn_compat(
64 log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
69 int config_parse_unit_deps(
79 UnitDependency d = ltype;
89 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
90 char _cleanup_free_ *t = NULL, *k = NULL;
97 k = unit_name_printf(u, t);
101 r = unit_add_dependency_by_name(u, d, k, NULL, true);
103 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s",
104 filename, line, k, strerror(-r));
110 int config_parse_unit_string_printf(
111 const char *filename,
121 _cleanup_free_ char *k = NULL;
128 k = unit_full_printf(u, rvalue);
130 log_error("[%s:%u] Failed to resolve unit specifiers on %s. Ignoring.",
131 filename, line, rvalue);
133 return config_parse_string(filename, line, section, lvalue, ltype, k ? k : rvalue, data, userdata);
136 int config_parse_unit_strv_printf(
137 const char *filename,
147 _cleanup_free_ char *k = NULL;
154 k = unit_full_printf(u, rvalue);
156 log_error("[%s:%u] Failed to resolve unit specifiers on %s. Ignoring.",
157 filename, line, rvalue);
159 return config_parse_strv(filename, line, section, lvalue, ltype, k ? k : rvalue, data, userdata);
162 int config_parse_unit_path_printf(
163 const char *filename,
173 _cleanup_free_ char *k = NULL;
180 k = unit_full_printf(u, rvalue);
182 log_error("[%s:%u] Failed to resolve unit specifiers on %s. Ignoring.",
183 filename, line, rvalue);
185 return config_parse_path(filename, line, section, lvalue, ltype, k ? k : rvalue, data, userdata);
188 int config_parse_socket_listen(
189 const char *filename,
198 SocketPort *p, *tail;
208 if (isempty(rvalue)) {
209 /* An empty assignment removes all ports */
210 socket_free_ports(s);
214 p = new0(SocketPort, 1);
218 if (ltype != SOCKET_SOCKET) {
221 p->path = unit_full_printf(UNIT(s), rvalue);
223 p->path = strdup(rvalue);
228 log_error("[%s:%u] Failed to resolve unit specifiers on %s. Ignoring.",
229 filename, line, rvalue);
232 path_kill_slashes(p->path);
234 } else if (streq(lvalue, "ListenNetlink")) {
235 _cleanup_free_ char *k = NULL;
238 p->type = SOCKET_SOCKET;
239 k = unit_full_printf(UNIT(s), rvalue);
241 log_error("[%s:%u] Failed to resolve unit specifiers on %s. Ignoring.",
242 filename, line, rvalue);
244 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
246 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
252 _cleanup_free_ char *k = NULL;
255 p->type = SOCKET_SOCKET;
256 k = unit_full_printf(UNIT(s), rvalue);
258 log_error("[%s:%u] Failed to resolve unit specifiers on %s. Ignoring.",
259 filename, line, rvalue);
261 r = socket_address_parse(&p->address, k ? k : rvalue);
263 log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
268 if (streq(lvalue, "ListenStream"))
269 p->address.type = SOCK_STREAM;
270 else if (streq(lvalue, "ListenDatagram"))
271 p->address.type = SOCK_DGRAM;
273 assert(streq(lvalue, "ListenSequentialPacket"));
274 p->address.type = SOCK_SEQPACKET;
277 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
278 log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
287 LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
288 LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
290 LIST_PREPEND(SocketPort, port, s->ports, p);
295 int config_parse_socket_bind(
296 const char *filename,
306 SocketAddressBindIPv6Only b;
315 b = socket_address_bind_ipv6_only_from_string(rvalue);
319 r = parse_boolean(rvalue);
321 log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
325 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
327 s->bind_ipv6_only = b;
332 int config_parse_exec_nice(
333 const char *filename,
342 ExecContext *c = data;
350 if (safe_atoi(rvalue, &priority) < 0) {
351 log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
355 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
356 log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
366 int config_parse_exec_oom_score_adjust(
367 const char *filename,
376 ExecContext *c = data;
384 if (safe_atoi(rvalue, &oa) < 0) {
385 log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
389 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
390 log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
394 c->oom_score_adjust = oa;
395 c->oom_score_adjust_set = true;
400 int config_parse_exec(
401 const char *filename,
410 ExecCommand **e = data, *nce;
422 if (isempty(rvalue)) {
423 /* An empty assignment resets the list */
424 exec_command_free_list(*e);
429 /* We accept an absolute path as first argument, or
430 * alternatively an absolute prefixed with @ to allow
431 * overriding of argv[0]. */
437 bool honour_argv0 = false, ignore = false;
443 rvalue += strspn(rvalue, WHITESPACE);
448 for (i = 0; i < 2; i++) {
449 if (rvalue[0] == '-' && !ignore) {
454 if (rvalue[0] == '@' && !honour_argv0) {
460 if (*rvalue != '/') {
461 log_error("[%s:%u] Executable path is not absolute, ignoring: %s",
462 filename, line, rvalue);
467 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
468 if (strneq(w, ";", MAX(l, 1U)))
474 n = new(char*, k + !honour_argv0);
479 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
480 if (strneq(w, ";", MAX(l, 1U)))
482 else if (strneq(w, "\\;", MAX(l, 1U)))
485 if (honour_argv0 && w == rvalue) {
488 path = strndup(w, l);
494 if (!utf8_is_valid(path)) {
495 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
503 c = n[k++] = cunescape_length(w, l);
509 if (!utf8_is_valid(c)) {
510 log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
520 log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
533 assert(path_is_absolute(path));
535 nce = new0(ExecCommand, 1);
543 nce->ignore = ignore;
545 path_kill_slashes(nce->path);
547 exec_command_append_list(e, nce);
563 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
564 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
566 int config_parse_socket_bindtodevice(
567 const char *filename,
584 if (rvalue[0] && !streq(rvalue, "*")) {
591 free(s->bind_to_device);
592 s->bind_to_device = n;
597 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
598 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
600 int config_parse_exec_io_class(
601 const char *filename,
610 ExecContext *c = data;
618 x = ioprio_class_from_string(rvalue);
620 log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
624 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
625 c->ioprio_set = true;
630 int config_parse_exec_io_priority(
631 const char *filename,
640 ExecContext *c = data;
648 if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
649 log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
653 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
654 c->ioprio_set = true;
659 int config_parse_exec_cpu_sched_policy(
660 const char *filename,
670 ExecContext *c = data;
678 x = sched_policy_from_string(rvalue);
680 log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
684 c->cpu_sched_policy = x;
685 /* Moving to or from real-time policy? We need to adjust the priority */
686 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
687 c->cpu_sched_set = true;
692 int config_parse_exec_cpu_sched_prio(
693 const char *filename,
702 ExecContext *c = data;
710 if (safe_atoi(rvalue, &i) < 0) {
711 log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
715 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
716 min = sched_get_priority_min(c->cpu_sched_policy);
717 max = sched_get_priority_max(c->cpu_sched_policy);
719 if (i < min || i > max) {
720 log_error("[%s:%u] CPU scheduling priority is out of range, ignoring: %s", filename, line, rvalue);
724 c->cpu_sched_priority = i;
725 c->cpu_sched_set = true;
730 int config_parse_exec_cpu_affinity(
731 const char *filename,
740 ExecContext *c = data;
750 if (isempty(rvalue)) {
751 /* An empty assignment resets the CPU list */
758 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
759 char _cleanup_free_ *t = NULL;
767 r = safe_atou(t, &cpu);
770 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
775 if (r < 0 || cpu >= c->cpuset_ncpus) {
776 log_error("[%s:%u] Failed to parse CPU affinity %s, ignoring: %s",
777 filename, line, t, rvalue);
781 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
787 int config_parse_exec_capabilities(
788 const char *filename,
797 ExecContext *c = data;
805 cap = cap_from_text(rvalue);
810 log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
815 cap_free(c->capabilities);
816 c->capabilities = cap;
821 int config_parse_exec_secure_bits(
822 const char *filename,
831 ExecContext *c = data;
841 if (isempty(rvalue)) {
842 /* An empty assignment resets the field */
847 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
848 if (first_word(w, "keep-caps"))
849 c->secure_bits |= SECURE_KEEP_CAPS;
850 else if (first_word(w, "keep-caps-locked"))
851 c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
852 else if (first_word(w, "no-setuid-fixup"))
853 c->secure_bits |= SECURE_NO_SETUID_FIXUP;
854 else if (first_word(w, "no-setuid-fixup-locked"))
855 c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
856 else if (first_word(w, "noroot"))
857 c->secure_bits |= SECURE_NOROOT;
858 else if (first_word(w, "noroot-locked"))
859 c->secure_bits |= SECURE_NOROOT_LOCKED;
861 log_error("[%s:%u] Failed to parse secure bits, ignoring: %s",
862 filename, line, rvalue);
870 int config_parse_bounding_set(
871 const char *filename,
880 uint64_t *capability_bounding_set_drop = data;
892 if (isempty(rvalue)) {
893 /* An empty assignment resets */
894 *capability_bounding_set_drop = 0;
898 if (rvalue[0] == '~') {
903 /* Note that we store this inverted internally, since the
904 * kernel wants it like this. But we actually expose it
905 * non-inverted everywhere to have a fully normalized
908 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
909 char _cleanup_free_ *t = NULL;
917 r = cap_from_name(t, &cap);
919 log_error("[%s:%u] Failed to parse capability in bounding set, ignoring: %s",
924 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
928 *capability_bounding_set_drop |= sum;
930 *capability_bounding_set_drop |= ~sum;
935 int config_parse_limit(
936 const char *filename,
945 struct rlimit **rl = data;
946 unsigned long long u;
955 if (streq(rvalue, "infinity"))
956 u = (unsigned long long) RLIM_INFINITY;
957 else if (safe_atollu(rvalue, &u) < 0) {
958 log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
963 *rl = new(struct rlimit, 1);
968 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
972 int config_parse_unit_cgroup(
973 const char *filename,
987 if (isempty(rvalue)) {
988 /* An empty assignment resets the list */
989 cgroup_bonding_free_list(u->cgroup_bondings, false);
990 u->cgroup_bondings = NULL;
994 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
995 char _cleanup_free_ *t = NULL, *k = NULL, *ku = NULL;
1002 k = unit_full_printf(u, t);
1004 log_error("[%s:%u] Failed to resolve unit specifiers on %s. Ignoring.",
1007 ku = cunescape(k ? k : t);
1011 r = unit_add_cgroup_from_text(u, ku, true, NULL);
1013 log_error("[%s:%u] Failed to parse cgroup value %s, ignoring: %s",
1014 filename, line, k, rvalue);
1022 #ifdef HAVE_SYSV_COMPAT
1023 int config_parse_sysv_priority(
1024 const char *filename,
1026 const char *section,
1033 int *priority = data;
1041 if (safe_atoi(rvalue, &i) < 0 || i < 0) {
1042 log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
1046 *priority = (int) i;
1051 int config_parse_fsck_passno(
1052 const char *filename,
1054 const char *section,
1069 if (safe_atoi(rvalue, &i) || i < 0) {
1070 log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
1078 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1080 int config_parse_kill_signal(
1081 const char *filename,
1083 const char *section,
1098 r = signal_from_string_try_harder(rvalue);
1100 log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
1108 int config_parse_exec_mount_flags(
1109 const char *filename,
1111 const char *section,
1118 ExecContext *c = data;
1122 unsigned long flags = 0;
1129 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1130 char _cleanup_free_ *t;
1136 if (streq(t, "shared"))
1138 else if (streq(t, "slave"))
1140 else if (streq(w, "private"))
1141 flags |= MS_PRIVATE;
1143 log_error("[%s:%u] Failed to parse mount flag %s, ignoring: %s",
1144 filename, line, t, rvalue);
1149 c->mount_flags = flags;
1153 int config_parse_timer(
1154 const char *filename,
1156 const char *section,
1167 CalendarSpec *c = NULL;
1175 if (isempty(rvalue)) {
1176 /* Empty assignment resets list */
1177 timer_free_values(t);
1181 b = timer_base_from_string(lvalue);
1183 log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
1187 if (b == TIMER_CALENDAR) {
1188 if (calendar_spec_from_string(rvalue, &c) < 0) {
1189 log_error("[%s:%u] Failed to parse calendar specification, ignoring: %s", filename, line, rvalue);
1193 id = CLOCK_REALTIME;
1195 if (parse_usec(rvalue, &u) < 0) {
1196 log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
1200 id = CLOCK_MONOTONIC;
1203 v = new0(TimerValue, 1);
1210 v->calendar_spec = c;
1212 LIST_PREPEND(TimerValue, value, t->values, v);
1217 int config_parse_timer_unit(
1218 const char *filename,
1220 const char *section,
1231 _cleanup_free_ char *p = NULL;
1238 dbus_error_init(&error);
1240 p = unit_name_printf(UNIT(t), rvalue);
1244 if (endswith(p, ".timer")) {
1245 log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
1249 r = manager_load_unit(UNIT(t)->manager, p, NULL, NULL, &u);
1251 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1252 dbus_error_free(&error);
1256 unit_ref_set(&t->unit, u);
1261 int config_parse_path_spec(
1262 const char *filename,
1264 const char *section,
1281 if (isempty(rvalue)) {
1282 /* Empty assignment clears list */
1287 b = path_type_from_string(lvalue);
1289 log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
1293 k = unit_full_printf(UNIT(p), rvalue);
1299 log_error("[%s:%u] Failed to resolve unit specifiers on %s. Ignoring.",
1300 filename, line, rvalue);
1303 if (!path_is_absolute(k)) {
1304 log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, k);
1309 s = new0(PathSpec, 1);
1315 s->path = path_kill_slashes(k);
1319 LIST_PREPEND(PathSpec, spec, p->specs, s);
1324 int config_parse_path_unit(
1325 const char *filename,
1327 const char *section,
1338 _cleanup_free_ char *p = NULL;
1345 dbus_error_init(&error);
1347 p = unit_name_printf(UNIT(t), rvalue);
1351 if (endswith(p, ".path")) {
1352 log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, p);
1356 r = manager_load_unit(UNIT(t)->manager, p, NULL, &error, &u);
1358 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, p, bus_error(&error, r));
1359 dbus_error_free(&error);
1363 unit_ref_set(&t->unit, u);
1368 int config_parse_socket_service(
1369 const char *filename,
1371 const char *section,
1382 _cleanup_free_ char *p = NULL;
1389 dbus_error_init(&error);
1391 p = unit_name_printf(UNIT(s), rvalue);
1395 if (!endswith(p, ".service")) {
1396 log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
1400 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1402 log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
1403 dbus_error_free(&error);
1407 unit_ref_set(&s->service, x);
1412 int config_parse_service_sockets(
1413 const char *filename,
1415 const char *section,
1432 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1433 char _cleanup_free_ *t = NULL, *k = NULL;
1439 k = unit_name_printf(UNIT(s), t);
1443 if (!endswith(k, ".socket")) {
1444 log_error("[%s:%u] Unit must be of type socket, ignoring: %s",
1449 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
1451 log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s",
1452 filename, line, k, strerror(-r));
1454 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
1462 int config_parse_service_timeout(
1463 const char *filename,
1465 const char *section,
1472 Service *s = userdata;
1480 r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1484 if (streq(lvalue, "TimeoutSec")) {
1485 s->start_timeout_defined = true;
1486 s->timeout_stop_usec = s->timeout_start_usec;
1487 } else if (streq(lvalue, "TimeoutStartSec"))
1488 s->start_timeout_defined = true;
1493 int config_parse_unit_env_file(
1494 const char *filename,
1496 const char *section,
1505 _cleanup_free_ char *s = NULL;
1513 if (isempty(rvalue)) {
1514 /* Empty assignment frees the list */
1520 s = unit_full_printf(u, rvalue);
1524 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1525 log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
1529 r = strv_extend(env, s);
1536 int config_parse_environ(
1537 const char *filename,
1539 const char *section,
1547 char*** env = data, *w, *state;
1549 _cleanup_free_ char *k = NULL;
1556 if (isempty(rvalue)) {
1557 /* Empty assignment resets the list */
1563 k = unit_full_printf(u, rvalue);
1567 FOREACH_WORD_QUOTED(w, l, k, state) {
1568 _cleanup_free_ char *n;
1571 n = cunescape_length(w, l);
1575 if (!env_assignment_is_valid(n)) {
1576 log_error("[%s:%u] Invalid environment assignment, ignoring: %s", filename, line, rvalue);
1580 x = strv_env_set(*env, n);
1591 int config_parse_ip_tos(
1592 const char *filename,
1594 const char *section,
1601 int *ip_tos = data, x;
1608 x = ip_tos_from_string(rvalue);
1610 log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
1618 int config_parse_unit_condition_path(
1619 const char *filename,
1621 const char *section,
1628 ConditionType cond = ltype;
1630 bool trigger, negate;
1632 _cleanup_free_ char *p = NULL;
1639 if (isempty(rvalue)) {
1640 /* Empty assignment resets the list */
1641 condition_free_list(u->conditions);
1642 u->conditions = NULL;
1646 trigger = rvalue[0] == '|';
1650 negate = rvalue[0] == '!';
1654 p = unit_full_printf(u, rvalue);
1658 if (!path_is_absolute(p)) {
1659 log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
1663 c = condition_new(cond, p, trigger, negate);
1667 LIST_PREPEND(Condition, conditions, u->conditions, c);
1671 int config_parse_unit_condition_string(
1672 const char *filename,
1674 const char *section,
1681 ConditionType cond = ltype;
1683 bool trigger, negate;
1685 _cleanup_free_ char *s = NULL;
1692 if (isempty(rvalue)) {
1693 /* Empty assignment resets the list */
1694 condition_free_list(u->conditions);
1695 u->conditions = NULL;
1699 trigger = rvalue[0] == '|';
1703 negate = rvalue[0] == '!';
1707 s = unit_full_printf(u, rvalue);
1711 c = condition_new(cond, s, trigger, negate);
1715 LIST_PREPEND(Condition, conditions, u->conditions, c);
1719 int config_parse_unit_condition_null(
1720 const char *filename,
1722 const char *section,
1731 bool trigger, negate;
1739 if (isempty(rvalue)) {
1740 /* Empty assignment resets the list */
1741 condition_free_list(u->conditions);
1742 u->conditions = NULL;
1746 trigger = rvalue[0] == '|';
1750 negate = rvalue[0] == '!';
1754 b = parse_boolean(rvalue);
1756 log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
1763 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1767 LIST_PREPEND(Condition, conditions, u->conditions, c);
1771 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1772 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1774 int config_parse_unit_cgroup_attr(
1775 const char *filename,
1777 const char *section,
1786 _cleanup_free_ char *n = NULL, *v = NULL;
1787 const CGroupSemantics *s;
1795 if (isempty(rvalue)) {
1796 /* Empty assignment clears the list */
1797 cgroup_attribute_free_list(u->cgroup_attributes);
1798 u->cgroup_attributes = NULL;
1802 a = strcspn(rvalue, WHITESPACE);
1803 b = strspn(rvalue + a, WHITESPACE);
1804 if (a <= 0 || b <= 0) {
1805 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1809 n = strndup(rvalue, a);
1813 r = cgroup_semantics_find(NULL, n, rvalue + a + b, &v, &s);
1815 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1819 r = unit_add_cgroup_attribute(u, s, NULL, n, v ? v : rvalue + a + b, NULL);
1821 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1828 int config_parse_unit_cgroup_attr_pretty(
1829 const char *filename,
1831 const char *section,
1839 _cleanup_free_ char *v = NULL;
1840 const CGroupSemantics *s;
1848 r = cgroup_semantics_find(NULL, lvalue, rvalue, &v, &s);
1850 log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
1852 } else if (r == 0) {
1853 log_error("[%s:%u] Unknown or unsupported cgroup attribute %s, ignoring: %s", filename, line, lvalue, rvalue);
1857 r = unit_add_cgroup_attribute(u, s, NULL, NULL, v, NULL);
1859 log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
1866 int config_parse_unit_requires_mounts_for(
1867 const char *filename,
1869 const char *section,
1885 empty_before = !u->requires_mounts_for;
1887 r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1889 /* Make it easy to find units with requires_mounts set */
1890 if (empty_before && u->requires_mounts_for)
1891 LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
1896 int config_parse_documentation(
1897 const char *filename,
1899 const char *section,
1915 if (isempty(rvalue)) {
1916 /* Empty assignment resets the list */
1917 strv_free(u->documentation);
1918 u->documentation = NULL;
1922 r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
1926 for (a = b = u->documentation; a && *a; a++) {
1928 if (is_valid_documentation_url(*a))
1931 log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
1940 static void syscall_set(uint32_t *p, int nr) {
1941 nr = SYSCALL_TO_INDEX(nr);
1942 p[nr >> 4] |= 1 << (nr & 31);
1945 static void syscall_unset(uint32_t *p, int nr) {
1946 nr = SYSCALL_TO_INDEX(nr);
1947 p[nr >> 4] &= ~(1 << (nr & 31));
1950 int config_parse_syscall_filter(
1951 const char *filename,
1953 const char *section,
1960 ExecContext *c = data;
1962 bool invert = false;
1972 if (isempty(rvalue)) {
1973 /* Empty assignment resets the list */
1974 free(c->syscall_filter);
1975 c->syscall_filter = NULL;
1979 if (rvalue[0] == '~') {
1984 if (!c->syscall_filter) {
1987 n = (syscall_max() + 31) >> 4;
1988 c->syscall_filter = new(uint32_t, n);
1989 if (!c->syscall_filter)
1992 memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
1994 /* Add these by default */
1995 syscall_set(c->syscall_filter, __NR_execve);
1996 syscall_set(c->syscall_filter, __NR_rt_sigreturn);
1997 #ifdef __NR_sigreturn
1998 syscall_set(c->syscall_filter, __NR_sigreturn);
2000 syscall_set(c->syscall_filter, __NR_exit_group);
2001 syscall_set(c->syscall_filter, __NR_exit);
2004 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2006 char _cleanup_free_ *t = NULL;
2012 id = syscall_from_name(t);
2014 log_error("[%s:%u] Failed to parse syscall, ignoring: %s",
2020 syscall_unset(c->syscall_filter, id);
2022 syscall_set(c->syscall_filter, id);
2025 c->no_new_privileges = true;
2030 #define FOLLOW_MAX 8
2032 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2043 /* This will update the filename pointer if the loaded file is
2044 * reached by a symlink. The old string will be freed. */
2047 char *target, *name;
2049 if (c++ >= FOLLOW_MAX)
2052 path_kill_slashes(*filename);
2054 /* Add the file name we are currently looking at to
2055 * the names of this unit, but only if it is a valid
2057 name = path_get_file_name(*filename);
2059 if (unit_name_is_valid(name, true)) {
2061 id = set_get(names, name);
2067 r = set_put(names, id);
2075 /* Try to open the file name, but don't if its a symlink */
2076 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2083 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2084 r = readlink_and_make_absolute(*filename, &target);
2092 f = fdopen(fd, "re");
2095 close_nointr_nofail(fd);
2104 static int merge_by_names(Unit **u, Set *names, const char *id) {
2112 /* Let's try to add in all symlink names we found */
2113 while ((k = set_steal_first(names))) {
2115 /* First try to merge in the other name into our
2117 r = unit_merge_by_name(*u, k);
2121 /* Hmm, we couldn't merge the other unit into
2122 * ours? Then let's try it the other way
2125 other = manager_get_unit((*u)->manager, k);
2129 r = unit_merge(other, *u);
2132 return merge_by_names(u, names, NULL);
2140 unit_choose_id(*u, id);
2148 static int load_from_path(Unit *u, const char *path) {
2152 char *filename = NULL, *id = NULL;
2159 symlink_names = set_new(string_hash_func, string_compare_func);
2163 if (path_is_absolute(path)) {
2165 filename = strdup(path);
2171 r = open_follow(&filename, &f, symlink_names, &id);
2183 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
2185 /* Instead of opening the path right away, we manually
2186 * follow all symlinks and add their name to our unit
2187 * name set while doing so */
2188 filename = path_make_absolute(path, *p);
2194 if (u->manager->unit_path_cache &&
2195 !set_get(u->manager->unit_path_cache, filename))
2198 r = open_follow(&filename, &f, symlink_names, &id);
2207 /* Empty the symlink names for the next run */
2208 set_clear_free(symlink_names);
2217 /* Hmm, no suitable file found? */
2223 r = merge_by_names(&merged, symlink_names, id);
2228 u->load_state = UNIT_MERGED;
2233 if (fstat(fileno(f), &st) < 0) {
2238 if (null_or_empty(&st))
2239 u->load_state = UNIT_MASKED;
2241 /* Now, parse the file contents */
2242 r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
2246 u->load_state = UNIT_LOADED;
2249 free(u->fragment_path);
2250 u->fragment_path = filename;
2253 u->fragment_mtime = timespec_load(&st.st_mtim);
2255 if (u->source_path) {
2256 if (stat(u->source_path, &st) >= 0)
2257 u->source_mtime = timespec_load(&st.st_mtim);
2259 u->source_mtime = 0;
2265 set_free_free(symlink_names);
2274 int unit_load_fragment(Unit *u) {
2280 assert(u->load_state == UNIT_STUB);
2283 /* First, try to find the unit under its id. We always look
2284 * for unit files in the default directories, to make it easy
2285 * to override things by placing things in /etc/systemd/system */
2286 r = load_from_path(u, u->id);
2290 /* Try to find an alias we can load this with */
2291 if (u->load_state == UNIT_STUB)
2292 SET_FOREACH(t, u->names, i) {
2297 r = load_from_path(u, t);
2301 if (u->load_state != UNIT_STUB)
2305 /* And now, try looking for it under the suggested (originally linked) path */
2306 if (u->load_state == UNIT_STUB && u->fragment_path) {
2308 r = load_from_path(u, u->fragment_path);
2312 if (u->load_state == UNIT_STUB) {
2313 /* Hmm, this didn't work? Then let's get rid
2314 * of the fragment path stored for us, so that
2315 * we don't point to an invalid location. */
2316 free(u->fragment_path);
2317 u->fragment_path = NULL;
2321 /* Look for a template */
2322 if (u->load_state == UNIT_STUB && u->instance) {
2325 k = unit_name_template(u->id);
2329 r = load_from_path(u, k);
2335 if (u->load_state == UNIT_STUB)
2336 SET_FOREACH(t, u->names, i) {
2341 k = unit_name_template(t);
2345 r = load_from_path(u, k);
2351 if (u->load_state != UNIT_STUB)
2359 void unit_dump_config_items(FILE *f) {
2360 static const struct {
2361 const ConfigParserCallback callback;
2364 { config_parse_int, "INTEGER" },
2365 { config_parse_unsigned, "UNSIGNED" },
2366 { config_parse_bytes_size, "SIZE" },
2367 { config_parse_bool, "BOOLEAN" },
2368 { config_parse_string, "STRING" },
2369 { config_parse_path, "PATH" },
2370 { config_parse_unit_path_printf, "PATH" },
2371 { config_parse_strv, "STRING [...]" },
2372 { config_parse_exec_nice, "NICE" },
2373 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
2374 { config_parse_exec_io_class, "IOCLASS" },
2375 { config_parse_exec_io_priority, "IOPRIORITY" },
2376 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
2377 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
2378 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
2379 { config_parse_mode, "MODE" },
2380 { config_parse_unit_env_file, "FILE" },
2381 { config_parse_output, "OUTPUT" },
2382 { config_parse_input, "INPUT" },
2383 { config_parse_facility, "FACILITY" },
2384 { config_parse_level, "LEVEL" },
2385 { config_parse_exec_capabilities, "CAPABILITIES" },
2386 { config_parse_exec_secure_bits, "SECUREBITS" },
2387 { config_parse_bounding_set, "BOUNDINGSET" },
2388 { config_parse_limit, "LIMIT" },
2389 { config_parse_unit_cgroup, "CGROUP [...]" },
2390 { config_parse_unit_deps, "UNIT [...]" },
2391 { config_parse_exec, "PATH [ARGUMENT [...]]" },
2392 { config_parse_service_type, "SERVICETYPE" },
2393 { config_parse_service_restart, "SERVICERESTART" },
2394 #ifdef HAVE_SYSV_COMPAT
2395 { config_parse_sysv_priority, "SYSVPRIORITY" },
2397 { config_parse_warn_compat, "NOTSUPPORTED" },
2399 { config_parse_kill_mode, "KILLMODE" },
2400 { config_parse_kill_signal, "SIGNAL" },
2401 { config_parse_socket_listen, "SOCKET [...]" },
2402 { config_parse_socket_bind, "SOCKETBIND" },
2403 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
2404 { config_parse_usec, "SECONDS" },
2405 { config_parse_nsec, "NANOSECONDS" },
2406 { config_parse_path_strv, "PATH [...]" },
2407 { config_parse_unit_requires_mounts_for, "PATH [...]" },
2408 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
2409 { config_parse_unit_string_printf, "STRING" },
2410 { config_parse_timer, "TIMER" },
2411 { config_parse_timer_unit, "NAME" },
2412 { config_parse_path_spec, "PATH" },
2413 { config_parse_path_unit, "UNIT" },
2414 { config_parse_notify_access, "ACCESS" },
2415 { config_parse_ip_tos, "TOS" },
2416 { config_parse_unit_condition_path, "CONDITION" },
2417 { config_parse_unit_condition_string, "CONDITION" },
2418 { config_parse_unit_condition_null, "CONDITION" },
2421 const char *prev = NULL;
2426 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
2427 const char *rvalue = "OTHER", *lvalue;
2431 const ConfigPerfItem *p;
2433 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
2435 dot = strchr(i, '.');
2436 lvalue = dot ? dot + 1 : i;
2440 if (!prev || !strneq(prev, i, prefix_len+1)) {
2444 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
2447 for (j = 0; j < ELEMENTSOF(table); j++)
2448 if (p->parse == table[j].callback) {
2449 rvalue = table[j].rvalue;
2453 fprintf(f, "%s=%s\n", lvalue, rvalue);