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"
62 #include "seccomp-util.h"
65 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
66 int config_parse_warn_compat(
71 unsigned section_line,
78 log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
79 "Support for option %s= has been disabled at compile time and is ignored",
85 int config_parse_unit_deps(const char* unit,
89 unsigned section_line,
96 UnitDependency d = ltype;
106 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
107 _cleanup_free_ char *t = NULL, *k = NULL;
114 r = unit_name_printf(u, t, &k);
116 log_syntax(unit, LOG_ERR, filename, line, -r,
117 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
121 r = unit_add_dependency_by_name(u, d, k, NULL, true);
123 log_syntax(unit, LOG_ERR, filename, line, -r,
124 "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
130 int config_parse_unit_string_printf(const char *unit,
131 const char *filename,
134 unsigned section_line,
142 _cleanup_free_ char *k = NULL;
150 r = unit_full_printf(u, rvalue, &k);
152 log_syntax(unit, LOG_ERR, filename, line, -r,
153 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
155 return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
156 k ? k : rvalue, data, userdata);
159 int config_parse_unit_strv_printf(const char *unit,
160 const char *filename,
163 unsigned section_line,
171 _cleanup_free_ char *k = NULL;
179 r = unit_full_printf(u, rvalue, &k);
181 log_syntax(unit, LOG_ERR, filename, line, -r,
182 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
184 return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
185 k ? k : rvalue, data, userdata);
188 int config_parse_unit_path_printf(const char *unit,
189 const char *filename,
192 unsigned section_line,
200 _cleanup_free_ char *k = NULL;
208 r = unit_full_printf(u, rvalue, &k);
210 log_syntax(unit, LOG_ERR, filename, line, -r,
211 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
213 return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype,
214 k ? k : rvalue, data, userdata);
217 int config_parse_socket_listen(const char *unit,
218 const char *filename,
221 unsigned section_line,
228 SocketPort *p, *tail;
239 if (isempty(rvalue)) {
240 /* An empty assignment removes all ports */
241 socket_free_ports(s);
245 p = new0(SocketPort, 1);
249 if (ltype != SOCKET_SOCKET) {
252 r = unit_full_printf(UNIT(s), rvalue, &p->path);
254 p->path = strdup(rvalue);
259 log_syntax(unit, LOG_ERR, filename, line, -r,
260 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
263 path_kill_slashes(p->path);
265 } else if (streq(lvalue, "ListenNetlink")) {
266 _cleanup_free_ char *k = NULL;
268 p->type = SOCKET_SOCKET;
269 r = unit_full_printf(UNIT(s), rvalue, &k);
271 log_syntax(unit, LOG_ERR, filename, line, -r,
272 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
274 r = socket_address_parse_netlink(&p->address, k ? k : rvalue);
276 log_syntax(unit, LOG_ERR, filename, line, -r,
277 "Failed to parse address value, ignoring: %s", rvalue);
283 _cleanup_free_ char *k = NULL;
285 p->type = SOCKET_SOCKET;
286 r = unit_full_printf(UNIT(s), rvalue, &k);
288 log_syntax(unit, LOG_ERR, filename, line, -r,
289 "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
291 r = socket_address_parse(&p->address, k ? k : rvalue);
293 log_syntax(unit, LOG_ERR, filename, line, -r,
294 "Failed to parse address value, ignoring: %s", rvalue);
299 if (streq(lvalue, "ListenStream"))
300 p->address.type = SOCK_STREAM;
301 else if (streq(lvalue, "ListenDatagram"))
302 p->address.type = SOCK_DGRAM;
304 assert(streq(lvalue, "ListenSequentialPacket"));
305 p->address.type = SOCK_SEQPACKET;
308 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
309 log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
310 "Address family not supported, ignoring: %s", rvalue);
320 LIST_FIND_TAIL(port, s->ports, tail);
321 LIST_INSERT_AFTER(port, s->ports, tail, p);
323 LIST_PREPEND(port, s->ports, p);
328 int config_parse_socket_bind(const char *unit,
329 const char *filename,
332 unsigned section_line,
340 SocketAddressBindIPv6Only b;
349 b = socket_address_bind_ipv6_only_from_string(rvalue);
353 r = parse_boolean(rvalue);
355 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
356 "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
360 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
362 s->bind_ipv6_only = b;
367 int config_parse_exec_nice(const char *unit,
368 const char *filename,
371 unsigned section_line,
378 ExecContext *c = data;
386 r = safe_atoi(rvalue, &priority);
388 log_syntax(unit, LOG_ERR, filename, line, -r,
389 "Failed to parse nice priority, ignoring: %s. ", rvalue);
393 if (priority < PRIO_MIN || priority >= PRIO_MAX) {
394 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
395 "Nice priority out of range, ignoring: %s", rvalue);
405 int config_parse_exec_oom_score_adjust(const char* unit,
406 const char *filename,
409 unsigned section_line,
416 ExecContext *c = data;
424 r = safe_atoi(rvalue, &oa);
426 log_syntax(unit, LOG_ERR, filename, line, -r,
427 "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
431 if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
432 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
433 "OOM score adjust value out of range, ignoring: %s", rvalue);
437 c->oom_score_adjust = oa;
438 c->oom_score_adjust_set = true;
443 int config_parse_exec(const char *unit,
444 const char *filename,
447 unsigned section_line,
454 ExecCommand **e = data, *nce;
466 if (isempty(rvalue)) {
467 /* An empty assignment resets the list */
468 exec_command_free_list(*e);
473 /* We accept an absolute path as first argument, or
474 * alternatively an absolute prefixed with @ to allow
475 * overriding of argv[0]. */
481 bool honour_argv0 = false, ignore = false;
487 rvalue += strspn(rvalue, WHITESPACE);
492 for (i = 0; i < 2; i++) {
493 if (rvalue[0] == '-' && !ignore) {
498 if (rvalue[0] == '@' && !honour_argv0) {
504 if (*rvalue != '/') {
505 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
506 "Executable path is not absolute, ignoring: %s", rvalue);
511 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
512 if (strneq(w, ";", MAX(l, 1U)))
518 n = new(char*, k + !honour_argv0);
523 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
524 if (strneq(w, ";", MAX(l, 1U)))
526 else if (strneq(w, "\\;", MAX(l, 1U)))
529 if (honour_argv0 && w == rvalue) {
532 path = strndup(w, l);
538 if (!utf8_is_valid(path)) {
539 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
547 c = n[k++] = cunescape_length(w, l);
553 if (!utf8_is_valid(c)) {
554 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
564 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
565 "Invalid command line, ignoring: %s", rvalue);
578 assert(path_is_absolute(path));
580 nce = new0(ExecCommand, 1);
588 nce->ignore = ignore;
590 path_kill_slashes(nce->path);
592 exec_command_append_list(e, nce);
608 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
609 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
611 int config_parse_socket_bindtodevice(const char* unit,
612 const char *filename,
615 unsigned section_line,
630 if (rvalue[0] && !streq(rvalue, "*")) {
637 free(s->bind_to_device);
638 s->bind_to_device = n;
643 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
644 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
646 int config_parse_exec_io_class(const char *unit,
647 const char *filename,
650 unsigned section_line,
657 ExecContext *c = data;
665 x = ioprio_class_from_string(rvalue);
667 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
668 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
672 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
673 c->ioprio_set = true;
678 int config_parse_exec_io_priority(const char *unit,
679 const char *filename,
682 unsigned section_line,
689 ExecContext *c = data;
697 r = safe_atoi(rvalue, &i);
698 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
699 log_syntax(unit, LOG_ERR, filename, line, -r,
700 "Failed to parse IO priority, ignoring: %s", rvalue);
704 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
705 c->ioprio_set = true;
710 int config_parse_exec_cpu_sched_policy(const char *unit,
711 const char *filename,
714 unsigned section_line,
722 ExecContext *c = data;
730 x = sched_policy_from_string(rvalue);
732 log_syntax(unit, LOG_ERR, filename, line, -x,
733 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
737 c->cpu_sched_policy = x;
738 /* Moving to or from real-time policy? We need to adjust the priority */
739 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
740 c->cpu_sched_set = true;
745 int config_parse_exec_cpu_sched_prio(const char *unit,
746 const char *filename,
749 unsigned section_line,
756 ExecContext *c = data;
764 r = safe_atoi(rvalue, &i);
766 log_syntax(unit, LOG_ERR, filename, line, -r,
767 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
771 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
772 min = sched_get_priority_min(c->cpu_sched_policy);
773 max = sched_get_priority_max(c->cpu_sched_policy);
775 if (i < min || i > max) {
776 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
777 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
781 c->cpu_sched_priority = i;
782 c->cpu_sched_set = true;
787 int config_parse_exec_cpu_affinity(const char *unit,
788 const char *filename,
791 unsigned section_line,
798 ExecContext *c = data;
808 if (isempty(rvalue)) {
809 /* An empty assignment resets the CPU list */
816 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
817 _cleanup_free_ char *t = NULL;
825 r = safe_atou(t, &cpu);
828 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
833 if (r < 0 || cpu >= c->cpuset_ncpus) {
834 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
835 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
839 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
845 int config_parse_exec_capabilities(const char *unit,
846 const char *filename,
849 unsigned section_line,
856 ExecContext *c = data;
864 cap = cap_from_text(rvalue);
866 log_syntax(unit, LOG_ERR, filename, line, errno,
867 "Failed to parse capabilities, ignoring: %s", rvalue);
872 cap_free(c->capabilities);
873 c->capabilities = cap;
878 int config_parse_exec_secure_bits(const char *unit,
879 const char *filename,
882 unsigned section_line,
889 ExecContext *c = data;
899 if (isempty(rvalue)) {
900 /* An empty assignment resets the field */
905 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
906 if (first_word(w, "keep-caps"))
907 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
908 else if (first_word(w, "keep-caps-locked"))
909 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
910 else if (first_word(w, "no-setuid-fixup"))
911 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
912 else if (first_word(w, "no-setuid-fixup-locked"))
913 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
914 else if (first_word(w, "noroot"))
915 c->secure_bits |= 1<<SECURE_NOROOT;
916 else if (first_word(w, "noroot-locked"))
917 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
919 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
920 "Failed to parse secure bits, ignoring: %s", rvalue);
928 int config_parse_bounding_set(const char *unit,
929 const char *filename,
932 unsigned section_line,
939 uint64_t *capability_bounding_set_drop = data;
951 if (rvalue[0] == '~') {
956 /* Note that we store this inverted internally, since the
957 * kernel wants it like this. But we actually expose it
958 * non-inverted everywhere to have a fully normalized
961 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
962 _cleanup_free_ char *t = NULL;
970 r = cap_from_name(t, &cap);
972 log_syntax(unit, LOG_ERR, filename, line, errno,
973 "Failed to parse capability in bounding set, ignoring: %s", t);
977 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
981 *capability_bounding_set_drop |= sum;
983 *capability_bounding_set_drop |= ~sum;
988 int config_parse_limit(const char *unit,
989 const char *filename,
992 unsigned section_line,
999 struct rlimit **rl = data;
1000 unsigned long long u;
1009 if (streq(rvalue, "infinity"))
1010 u = (unsigned long long) RLIM_INFINITY;
1014 r = safe_atollu(rvalue, &u);
1016 log_syntax(unit, LOG_ERR, filename, line, -r,
1017 "Failed to parse resource value, ignoring: %s", rvalue);
1023 *rl = new(struct rlimit, 1);
1028 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1032 #ifdef HAVE_SYSV_COMPAT
1033 int config_parse_sysv_priority(const char *unit,
1034 const char *filename,
1036 const char *section,
1037 unsigned section_line,
1044 int *priority = data;
1052 r = safe_atoi(rvalue, &i);
1053 if (r < 0 || i < 0) {
1054 log_syntax(unit, LOG_ERR, filename, line, -r,
1055 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1059 *priority = (int) i;
1064 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1066 int config_parse_kill_signal(const char *unit,
1067 const char *filename,
1069 const char *section,
1070 unsigned section_line,
1085 r = signal_from_string_try_harder(rvalue);
1087 log_syntax(unit, LOG_ERR, filename, line, -r,
1088 "Failed to parse kill signal, ignoring: %s", rvalue);
1096 int config_parse_exec_mount_flags(const char *unit,
1097 const char *filename,
1099 const char *section,
1100 unsigned section_line,
1107 ExecContext *c = data;
1111 unsigned long flags = 0;
1118 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1119 _cleanup_free_ char *t;
1125 if (streq(t, "shared"))
1127 else if (streq(t, "slave"))
1129 else if (streq(w, "private"))
1130 flags |= MS_PRIVATE;
1132 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1133 "Failed to parse mount flag %s, ignoring: %s",
1139 c->mount_flags = flags;
1143 int config_parse_exec_selinux_context(
1145 const char *filename,
1147 const char *section,
1148 unsigned section_line,
1155 ExecContext *c = data;
1166 if (isempty(rvalue)) {
1167 free(c->selinux_context);
1168 c->selinux_context = NULL;
1169 c->selinux_context_ignore = false;
1173 if (rvalue[0] == '-') {
1179 r = unit_name_printf(u, rvalue, &k);
1181 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1185 free(c->selinux_context);
1186 c->selinux_context = k;
1187 c->selinux_context_ignore = ignore;
1192 int config_parse_exec_apparmor_profile(
1194 const char *filename,
1196 const char *section,
1197 unsigned section_line,
1204 ExecContext *c = data;
1215 if (isempty(rvalue)) {
1216 free(c->apparmor_profile);
1217 c->apparmor_profile = NULL;
1218 c->apparmor_profile_ignore = false;
1222 if (rvalue[0] == '-') {
1228 r = unit_name_printf(u, rvalue, &k);
1230 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1234 free(c->apparmor_profile);
1235 c->apparmor_profile = k;
1236 c->apparmor_profile_ignore = ignore;
1241 int config_parse_timer(const char *unit,
1242 const char *filename,
1244 const char *section,
1245 unsigned section_line,
1256 CalendarSpec *c = NULL;
1264 if (isempty(rvalue)) {
1265 /* Empty assignment resets list */
1266 timer_free_values(t);
1270 b = timer_base_from_string(lvalue);
1272 log_syntax(unit, LOG_ERR, filename, line, -b,
1273 "Failed to parse timer base, ignoring: %s", lvalue);
1277 if (b == TIMER_CALENDAR) {
1278 if (calendar_spec_from_string(rvalue, &c) < 0) {
1279 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1280 "Failed to parse calendar specification, ignoring: %s",
1285 id = CLOCK_REALTIME;
1287 if (parse_sec(rvalue, &u) < 0) {
1288 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1289 "Failed to parse timer value, ignoring: %s",
1294 id = CLOCK_MONOTONIC;
1297 v = new0(TimerValue, 1);
1304 v->calendar_spec = c;
1306 LIST_PREPEND(value, t->values, v);
1311 int config_parse_trigger_unit(
1313 const char *filename,
1315 const char *section,
1316 unsigned section_line,
1323 _cleanup_free_ char *p = NULL;
1333 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1334 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1335 "Multiple units to trigger specified, ignoring: %s", rvalue);
1339 r = unit_name_printf(u, rvalue, &p);
1341 log_syntax(unit, LOG_ERR, filename, line, -r,
1342 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1344 type = unit_name_to_type(p ?: rvalue);
1346 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1347 "Unit type not valid, ignoring: %s", rvalue);
1351 if (type == u->type) {
1352 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1353 "Trigger cannot be of same type, ignoring: %s", rvalue);
1357 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1359 log_syntax(unit, LOG_ERR, filename, line, -r,
1360 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1367 int config_parse_path_spec(const char *unit,
1368 const char *filename,
1370 const char *section,
1371 unsigned section_line,
1381 _cleanup_free_ char *k = NULL;
1389 if (isempty(rvalue)) {
1390 /* Empty assignment clears list */
1395 b = path_type_from_string(lvalue);
1397 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1398 "Failed to parse path type, ignoring: %s", lvalue);
1402 r = unit_full_printf(UNIT(p), rvalue, &k);
1408 log_syntax(unit, LOG_ERR, filename, line, -r,
1409 "Failed to resolve unit specifiers on %s. Ignoring.",
1413 if (!path_is_absolute(k)) {
1414 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1415 "Path is not absolute, ignoring: %s", k);
1419 s = new0(PathSpec, 1);
1424 s->path = path_kill_slashes(k);
1429 LIST_PREPEND(spec, p->specs, s);
1434 int config_parse_socket_service(const char *unit,
1435 const char *filename,
1437 const char *section,
1438 unsigned section_line,
1445 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1449 _cleanup_free_ char *p = NULL;
1456 r = unit_name_printf(UNIT(s), rvalue, &p);
1458 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1462 if (!endswith(p, ".service")) {
1463 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1467 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1469 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1473 unit_ref_set(&s->service, x);
1478 int config_parse_service_sockets(const char *unit,
1479 const char *filename,
1481 const char *section,
1482 unsigned section_line,
1499 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1500 _cleanup_free_ char *t = NULL, *k = NULL;
1506 r = unit_name_printf(UNIT(s), t, &k);
1508 log_syntax(unit, LOG_ERR, filename, line, -r,
1509 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1511 if (!endswith(k ?: t, ".socket")) {
1512 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1513 "Unit must be of type socket, ignoring: %s", k ?: t);
1517 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1519 log_syntax(unit, LOG_ERR, filename, line, -r,
1520 "Failed to add dependency on %s, ignoring: %s",
1521 k ?: t, strerror(-r));
1523 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1531 int config_parse_service_timeout(const char *unit,
1532 const char *filename,
1534 const char *section,
1535 unsigned section_line,
1542 Service *s = userdata;
1550 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1551 rvalue, data, userdata);
1555 if (streq(lvalue, "TimeoutSec")) {
1556 s->start_timeout_defined = true;
1557 s->timeout_stop_usec = s->timeout_start_usec;
1558 } else if (streq(lvalue, "TimeoutStartSec"))
1559 s->start_timeout_defined = true;
1564 int config_parse_busname_service(
1566 const char *filename,
1568 const char *section,
1569 unsigned section_line,
1576 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1580 _cleanup_free_ char *p = NULL;
1587 r = unit_name_printf(UNIT(n), rvalue, &p);
1589 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1593 if (!endswith(p, ".service")) {
1594 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1598 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1600 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1604 unit_ref_set(&n->service, x);
1609 int config_parse_unit_env_file(const char *unit,
1610 const char *filename,
1612 const char *section,
1613 unsigned section_line,
1622 _cleanup_free_ char *n = NULL;
1631 if (isempty(rvalue)) {
1632 /* Empty assignment frees the list */
1638 r = unit_full_printf(u, rvalue, &n);
1640 log_syntax(unit, LOG_ERR, filename, line, r,
1641 "Failed to resolve specifiers, ignoring: %s", rvalue);
1644 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1645 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1646 "Path '%s' is not absolute, ignoring.", s);
1650 r = strv_extend(env, s);
1657 int config_parse_environ(const char *unit,
1658 const char *filename,
1660 const char *section,
1661 unsigned section_line,
1669 char*** env = data, *w, *state;
1671 _cleanup_free_ char *k = NULL;
1679 if (isempty(rvalue)) {
1680 /* Empty assignment resets the list */
1687 r = unit_full_printf(u, rvalue, &k);
1689 log_syntax(unit, LOG_ERR, filename, line, -r,
1690 "Failed to resolve specifiers, ignoring: %s", rvalue);
1698 FOREACH_WORD_QUOTED(w, l, k, state) {
1699 _cleanup_free_ char *n;
1702 n = cunescape_length(w, l);
1706 if (!env_assignment_is_valid(n)) {
1707 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1708 "Invalid environment assignment, ignoring: %s", rvalue);
1712 x = strv_env_set(*env, n);
1723 int config_parse_ip_tos(const char *unit,
1724 const char *filename,
1726 const char *section,
1727 unsigned section_line,
1734 int *ip_tos = data, x;
1741 x = ip_tos_from_string(rvalue);
1743 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1744 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1752 int config_parse_unit_condition_path(const char *unit,
1753 const char *filename,
1755 const char *section,
1756 unsigned section_line,
1763 ConditionType cond = ltype;
1765 bool trigger, negate;
1767 _cleanup_free_ char *p = NULL;
1775 if (isempty(rvalue)) {
1776 /* Empty assignment resets the list */
1777 condition_free_list(u->conditions);
1778 u->conditions = NULL;
1782 trigger = rvalue[0] == '|';
1786 negate = rvalue[0] == '!';
1790 r = unit_full_printf(u, rvalue, &p);
1792 log_syntax(unit, LOG_ERR, filename, line, -r,
1793 "Failed to resolve specifiers, ignoring: %s", rvalue);
1800 if (!path_is_absolute(p)) {
1801 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1802 "Path in condition not absolute, ignoring: %s", p);
1806 c = condition_new(cond, p, trigger, negate);
1810 LIST_PREPEND(conditions, u->conditions, c);
1814 int config_parse_unit_condition_string(const char *unit,
1815 const char *filename,
1817 const char *section,
1818 unsigned section_line,
1825 ConditionType cond = ltype;
1827 bool trigger, negate;
1829 _cleanup_free_ char *s = NULL;
1837 if (isempty(rvalue)) {
1838 /* Empty assignment resets the list */
1839 condition_free_list(u->conditions);
1840 u->conditions = NULL;
1844 trigger = rvalue[0] == '|';
1848 negate = rvalue[0] == '!';
1852 r = unit_full_printf(u, rvalue, &s);
1854 log_syntax(unit, LOG_ERR, filename, line, -r,
1855 "Failed to resolve specifiers, ignoring: %s", rvalue);
1862 c = condition_new(cond, s, trigger, negate);
1866 LIST_PREPEND(conditions, u->conditions, c);
1870 int config_parse_unit_condition_null(const char *unit,
1871 const char *filename,
1873 const char *section,
1874 unsigned section_line,
1883 bool trigger, negate;
1891 if (isempty(rvalue)) {
1892 /* Empty assignment resets the list */
1893 condition_free_list(u->conditions);
1894 u->conditions = NULL;
1898 trigger = rvalue[0] == '|';
1902 negate = rvalue[0] == '!';
1906 b = parse_boolean(rvalue);
1908 log_syntax(unit, LOG_ERR, filename, line, -b,
1909 "Failed to parse boolean value in condition, ignoring: %s",
1917 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1921 LIST_PREPEND(conditions, u->conditions, c);
1925 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1926 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1928 int config_parse_unit_requires_mounts_for(
1930 const char *filename,
1932 const char *section,
1933 unsigned section_line,
1950 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1952 _cleanup_free_ char *n;
1958 if (!utf8_is_valid(n)) {
1959 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
1963 r = unit_require_mounts_for(u, n);
1965 log_syntax(unit, LOG_ERR, filename, line, r,
1966 "Failed to add required mount for, ignoring: %s", rvalue);
1974 int config_parse_documentation(const char *unit,
1975 const char *filename,
1977 const char *section,
1978 unsigned section_line,
1994 if (isempty(rvalue)) {
1995 /* Empty assignment resets the list */
1996 strv_free(u->documentation);
1997 u->documentation = NULL;
2001 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2002 rvalue, data, userdata);
2006 for (a = b = u->documentation; a && *a; a++) {
2008 if (is_valid_documentation_url(*a))
2011 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2012 "Invalid URL, ignoring: %s", *a);
2023 int config_parse_syscall_filter(
2025 const char *filename,
2027 const char *section,
2028 unsigned section_line,
2035 static const char default_syscalls[] =
2042 ExecContext *c = data;
2044 bool invert = false;
2054 if (isempty(rvalue)) {
2055 /* Empty assignment resets the list */
2056 set_free(c->syscall_filter);
2057 c->syscall_filter = NULL;
2058 c->syscall_whitelist = false;
2062 if (rvalue[0] == '~') {
2067 if (!c->syscall_filter) {
2068 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2069 if (!c->syscall_filter)
2073 /* Allow everything but the ones listed */
2074 c->syscall_whitelist = false;
2078 /* Allow nothing but the ones listed */
2079 c->syscall_whitelist = true;
2081 /* Accept default syscalls if we are on a whitelist */
2082 NULSTR_FOREACH(i, default_syscalls) {
2085 id = seccomp_syscall_resolve_name(i);
2089 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2098 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2099 _cleanup_free_ char *t = NULL;
2106 id = seccomp_syscall_resolve_name(t);
2108 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2112 /* If we previously wanted to forbid a syscall and now
2113 * we want to allow it, then remove it from the list
2115 if (!invert == c->syscall_whitelist) {
2116 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2122 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2125 /* Turn on NNP, but only if it wasn't configured explicitly
2126 * before, and only if we are in user mode. */
2127 if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
2128 c->no_new_privileges = true;
2133 int config_parse_syscall_archs(
2135 const char *filename,
2137 const char *section,
2138 unsigned section_line,
2150 if (isempty(rvalue)) {
2156 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2160 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2161 _cleanup_free_ char *t = NULL;
2168 r = seccomp_arch_from_string(t, &a);
2170 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2174 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2184 int config_parse_syscall_errno(
2186 const char *filename,
2188 const char *section,
2189 unsigned section_line,
2196 ExecContext *c = data;
2203 if (isempty(rvalue)) {
2204 /* Empty assignment resets to KILL */
2205 c->syscall_errno = 0;
2209 e = errno_from_name(rvalue);
2211 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2215 c->syscall_errno = e;
2219 int config_parse_address_families(
2221 const char *filename,
2223 const char *section,
2224 unsigned section_line,
2231 ExecContext *c = data;
2233 bool invert = false;
2243 if (isempty(rvalue)) {
2244 /* Empty assignment resets the list */
2245 set_free(c->address_families);
2246 c->address_families = NULL;
2247 c->address_families_whitelist = false;
2251 if (rvalue[0] == '~') {
2256 if (!c->address_families) {
2257 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2258 if (!c->address_families)
2261 c->address_families_whitelist = !invert;
2264 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2265 _cleanup_free_ char *t = NULL;
2272 af = af_from_name(t);
2274 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
2278 /* If we previously wanted to forbid an address family and now
2279 * we want to allow it, then remove it from the list
2281 if (!invert == c->address_families_whitelist) {
2282 r = set_put(c->address_families, INT_TO_PTR(af));
2288 set_remove(c->address_families, INT_TO_PTR(af));
2295 int config_parse_unit_slice(
2297 const char *filename,
2299 const char *section,
2300 unsigned section_line,
2307 _cleanup_free_ char *k = NULL;
2308 Unit *u = userdata, *slice;
2316 r = unit_name_printf(u, rvalue, &k);
2318 log_syntax(unit, LOG_ERR, filename, line, -r,
2319 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2326 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2328 log_syntax(unit, LOG_ERR, filename, line, -r,
2329 "Failed to load slice unit %s. Ignoring.", k);
2333 if (slice->type != UNIT_SLICE) {
2334 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2335 "Slice unit %s is not a slice. Ignoring.", k);
2339 unit_ref_set(&u->slice, slice);
2343 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2345 int config_parse_cpu_shares(
2347 const char *filename,
2349 const char *section,
2350 unsigned section_line,
2357 CGroupContext *c = data;
2365 if (isempty(rvalue)) {
2366 c->cpu_shares = 1024;
2370 r = safe_atolu(rvalue, &lu);
2371 if (r < 0 || lu <= 0) {
2372 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2373 "CPU shares '%s' invalid. Ignoring.", rvalue);
2381 int config_parse_memory_limit(
2383 const char *filename,
2385 const char *section,
2386 unsigned section_line,
2393 CGroupContext *c = data;
2397 if (isempty(rvalue)) {
2398 c->memory_limit = (uint64_t) -1;
2402 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2404 r = parse_size(rvalue, 1024, &bytes);
2406 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
2410 c->memory_limit = (uint64_t) bytes;
2414 int config_parse_device_allow(
2416 const char *filename,
2418 const char *section,
2419 unsigned section_line,
2426 _cleanup_free_ char *path = NULL;
2427 CGroupContext *c = data;
2428 CGroupDeviceAllow *a;
2432 if (isempty(rvalue)) {
2433 while (c->device_allow)
2434 cgroup_context_free_device_allow(c, c->device_allow);
2439 n = strcspn(rvalue, WHITESPACE);
2440 path = strndup(rvalue, n);
2444 if (!startswith(path, "/dev/") &&
2445 !startswith(path, "block-") &&
2446 !startswith(path, "char-")) {
2447 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2451 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2455 if (!in_charset(m, "rwm")) {
2456 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
2460 a = new0(CGroupDeviceAllow, 1);
2466 a->r = !!strchr(m, 'r');
2467 a->w = !!strchr(m, 'w');
2468 a->m = !!strchr(m, 'm');
2470 LIST_PREPEND(device_allow, c->device_allow, a);
2474 int config_parse_blockio_weight(
2476 const char *filename,
2478 const char *section,
2479 unsigned section_line,
2486 CGroupContext *c = data;
2494 if (isempty(rvalue)) {
2495 c->blockio_weight = 1000;
2499 r = safe_atolu(rvalue, &lu);
2500 if (r < 0 || lu < 10 || lu > 1000) {
2501 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2502 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2506 c->blockio_weight = lu;
2511 int config_parse_blockio_device_weight(
2513 const char *filename,
2515 const char *section,
2516 unsigned section_line,
2523 _cleanup_free_ char *path = NULL;
2524 CGroupBlockIODeviceWeight *w;
2525 CGroupContext *c = data;
2535 if (isempty(rvalue)) {
2536 while (c->blockio_device_weights)
2537 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2542 n = strcspn(rvalue, WHITESPACE);
2543 weight = rvalue + n;
2545 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2546 "Expected block device and device weight. Ignoring.");
2550 path = strndup(rvalue, n);
2554 if (!path_startswith(path, "/dev")) {
2555 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2556 "Invalid device node path '%s'. Ignoring.", path);
2560 weight += strspn(weight, WHITESPACE);
2561 r = safe_atolu(weight, &lu);
2562 if (r < 0 || lu < 10 || lu > 1000) {
2563 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2564 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2569 w = new0(CGroupBlockIODeviceWeight, 1);
2578 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2582 int config_parse_blockio_bandwidth(
2584 const char *filename,
2586 const char *section,
2587 unsigned section_line,
2594 _cleanup_free_ char *path = NULL;
2595 CGroupBlockIODeviceBandwidth *b;
2596 CGroupContext *c = data;
2597 const char *bandwidth;
2607 read = streq("BlockIOReadBandwidth", lvalue);
2609 if (isempty(rvalue)) {
2610 CGroupBlockIODeviceBandwidth *next;
2612 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2613 if (b->read == read)
2614 cgroup_context_free_blockio_device_bandwidth(c, b);
2619 n = strcspn(rvalue, WHITESPACE);
2620 bandwidth = rvalue + n;
2621 bandwidth += strspn(bandwidth, WHITESPACE);
2624 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2625 "Expected space separated pair of device node and bandwidth. Ignoring.");
2629 path = strndup(rvalue, n);
2633 if (!path_startswith(path, "/dev")) {
2634 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2635 "Invalid device node path '%s'. Ignoring.", path);
2639 r = parse_size(bandwidth, 1000, &bytes);
2640 if (r < 0 || bytes <= 0) {
2641 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2645 b = new0(CGroupBlockIODeviceBandwidth, 1);
2651 b->bandwidth = (uint64_t) bytes;
2654 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2659 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2661 int config_parse_job_mode_isolate(
2663 const char *filename,
2665 const char *section,
2666 unsigned section_line,
2680 r = parse_boolean(rvalue);
2682 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2686 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2690 int config_parse_personality(
2692 const char *filename,
2694 const char *section,
2695 unsigned section_line,
2702 unsigned long *personality = data, p;
2707 assert(personality);
2709 p = personality_from_string(rvalue);
2710 if (p == 0xffffffffUL) {
2711 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2712 "Failed to parse personality, ignoring: %s", rvalue);
2720 int config_parse_runtime_directory(
2722 const char *filename,
2724 const char *section,
2725 unsigned section_line,
2732 char***rt = data, *w, *state;
2741 if (isempty(rvalue)) {
2742 /* Empty assignment resets the list */
2748 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2749 _cleanup_free_ char *n;
2755 if (!filename_is_safe(n)) {
2756 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2760 r = strv_push(rt, n);
2770 int config_parse_set_status(
2772 const char *filename,
2774 const char *section,
2775 unsigned section_line,
2786 ExitStatusSet *status_set = data;
2793 if (isempty(rvalue)) {
2794 /* Empty assignment resets the list */
2796 set_free(status_set->signal);
2797 set_free(status_set->code);
2799 status_set->signal = status_set->code = NULL;
2803 FOREACH_WORD(w, l, rvalue, state) {
2804 _cleanup_free_ char *temp;
2807 temp = strndup(w, l);
2811 r = safe_atoi(temp, &val);
2813 val = signal_from_string_try_harder(temp);
2816 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
2820 r = set_put(status_set->signal, INT_TO_PTR(val));
2822 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2826 log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", w);
2830 if (val < 0 || val > 255)
2831 log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
2833 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
2837 r = set_put(status_set->code, INT_TO_PTR(val));
2839 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2849 int config_parse_namespace_path_strv(
2851 const char *filename,
2853 const char *section,
2854 unsigned section_line,
2861 char*** sv = data, *w, *state;
2870 if (isempty(rvalue)) {
2871 /* Empty assignment resets the list */
2877 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2878 _cleanup_free_ char *n;
2885 if (!utf8_is_valid(n)) {
2886 log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
2890 offset = n[0] == '-';
2891 if (!path_is_absolute(n + offset)) {
2892 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
2896 path_kill_slashes(n);
2898 r = strv_push(sv, n);
2908 int config_parse_no_new_priviliges(
2910 const char *filename,
2912 const char *section,
2913 unsigned section_line,
2920 ExecContext *c = data;
2928 k = parse_boolean(rvalue);
2930 log_syntax(unit, LOG_ERR, filename, line, -k, "Failed to parse boolean value, ignoring: %s", rvalue);
2934 c->no_new_privileges = !!k;
2935 c->no_new_privileges_set = true;
2940 #define FOLLOW_MAX 8
2942 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2953 /* This will update the filename pointer if the loaded file is
2954 * reached by a symlink. The old string will be freed. */
2957 char *target, *name;
2959 if (c++ >= FOLLOW_MAX)
2962 path_kill_slashes(*filename);
2964 /* Add the file name we are currently looking at to
2965 * the names of this unit, but only if it is a valid
2967 name = basename(*filename);
2969 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
2971 id = set_get(names, name);
2977 r = set_consume(names, id);
2983 /* Try to open the file name, but don't if its a symlink */
2984 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2991 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2992 r = readlink_and_make_absolute(*filename, &target);
3000 f = fdopen(fd, "re");
3003 close_nointr_nofail(fd);
3012 static int merge_by_names(Unit **u, Set *names, const char *id) {
3020 /* Let's try to add in all symlink names we found */
3021 while ((k = set_steal_first(names))) {
3023 /* First try to merge in the other name into our
3025 r = unit_merge_by_name(*u, k);
3029 /* Hmm, we couldn't merge the other unit into
3030 * ours? Then let's try it the other way
3033 other = manager_get_unit((*u)->manager, k);
3037 r = unit_merge(other, *u);
3040 return merge_by_names(u, names, NULL);
3048 unit_choose_id(*u, id);
3056 static int load_from_path(Unit *u, const char *path) {
3058 _cleanup_set_free_free_ Set *symlink_names = NULL;
3059 _cleanup_fclose_ FILE *f = NULL;
3060 _cleanup_free_ char *filename = NULL;
3068 symlink_names = set_new(string_hash_func, string_compare_func);
3072 if (path_is_absolute(path)) {
3074 filename = strdup(path);
3078 r = open_follow(&filename, &f, symlink_names, &id);
3090 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3092 /* Instead of opening the path right away, we manually
3093 * follow all symlinks and add their name to our unit
3094 * name set while doing so */
3095 filename = path_make_absolute(path, *p);
3099 if (u->manager->unit_path_cache &&
3100 !set_get(u->manager->unit_path_cache, filename))
3103 r = open_follow(&filename, &f, symlink_names, &id);
3112 /* Empty the symlink names for the next run */
3113 set_clear_free(symlink_names);
3122 /* Hmm, no suitable file found? */
3126 r = merge_by_names(&merged, symlink_names, id);
3131 u->load_state = UNIT_MERGED;
3135 if (fstat(fileno(f), &st) < 0)
3138 if (null_or_empty(&st))
3139 u->load_state = UNIT_MASKED;
3141 u->load_state = UNIT_LOADED;
3143 /* Now, parse the file contents */
3144 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
3145 config_item_perf_lookup,
3146 (void*) load_fragment_gperf_lookup, false, true, u);
3151 free(u->fragment_path);
3152 u->fragment_path = filename;
3155 u->fragment_mtime = timespec_load(&st.st_mtim);
3157 if (u->source_path) {
3158 if (stat(u->source_path, &st) >= 0)
3159 u->source_mtime = timespec_load(&st.st_mtim);
3161 u->source_mtime = 0;
3167 int unit_load_fragment(Unit *u) {
3173 assert(u->load_state == UNIT_STUB);
3176 /* First, try to find the unit under its id. We always look
3177 * for unit files in the default directories, to make it easy
3178 * to override things by placing things in /etc/systemd/system */
3179 r = load_from_path(u, u->id);
3183 /* Try to find an alias we can load this with */
3184 if (u->load_state == UNIT_STUB)
3185 SET_FOREACH(t, u->names, i) {
3190 r = load_from_path(u, t);
3194 if (u->load_state != UNIT_STUB)
3198 /* And now, try looking for it under the suggested (originally linked) path */
3199 if (u->load_state == UNIT_STUB && u->fragment_path) {
3201 r = load_from_path(u, u->fragment_path);
3205 if (u->load_state == UNIT_STUB) {
3206 /* Hmm, this didn't work? Then let's get rid
3207 * of the fragment path stored for us, so that
3208 * we don't point to an invalid location. */
3209 free(u->fragment_path);
3210 u->fragment_path = NULL;
3214 /* Look for a template */
3215 if (u->load_state == UNIT_STUB && u->instance) {
3216 _cleanup_free_ char *k;
3218 k = unit_name_template(u->id);
3222 r = load_from_path(u, k);
3226 if (u->load_state == UNIT_STUB)
3227 SET_FOREACH(t, u->names, i) {
3228 _cleanup_free_ char *z = NULL;
3233 z = unit_name_template(t);
3237 r = load_from_path(u, z);
3241 if (u->load_state != UNIT_STUB)
3249 void unit_dump_config_items(FILE *f) {
3250 static const struct {
3251 const ConfigParserCallback callback;
3254 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3255 { config_parse_warn_compat, "NOTSUPPORTED" },
3257 { config_parse_int, "INTEGER" },
3258 { config_parse_unsigned, "UNSIGNED" },
3259 { config_parse_iec_size, "SIZE" },
3260 { config_parse_iec_off, "SIZE" },
3261 { config_parse_si_size, "SIZE" },
3262 { config_parse_bool, "BOOLEAN" },
3263 { config_parse_string, "STRING" },
3264 { config_parse_path, "PATH" },
3265 { config_parse_unit_path_printf, "PATH" },
3266 { config_parse_strv, "STRING [...]" },
3267 { config_parse_exec_nice, "NICE" },
3268 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3269 { config_parse_exec_io_class, "IOCLASS" },
3270 { config_parse_exec_io_priority, "IOPRIORITY" },
3271 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3272 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3273 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3274 { config_parse_mode, "MODE" },
3275 { config_parse_unit_env_file, "FILE" },
3276 { config_parse_output, "OUTPUT" },
3277 { config_parse_input, "INPUT" },
3278 { config_parse_log_facility, "FACILITY" },
3279 { config_parse_log_level, "LEVEL" },
3280 { config_parse_exec_capabilities, "CAPABILITIES" },
3281 { config_parse_exec_secure_bits, "SECUREBITS" },
3282 { config_parse_bounding_set, "BOUNDINGSET" },
3283 { config_parse_limit, "LIMIT" },
3284 { config_parse_unit_deps, "UNIT [...]" },
3285 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3286 { config_parse_service_type, "SERVICETYPE" },
3287 { config_parse_service_restart, "SERVICERESTART" },
3288 #ifdef HAVE_SYSV_COMPAT
3289 { config_parse_sysv_priority, "SYSVPRIORITY" },
3291 { config_parse_kill_mode, "KILLMODE" },
3292 { config_parse_kill_signal, "SIGNAL" },
3293 { config_parse_socket_listen, "SOCKET [...]" },
3294 { config_parse_socket_bind, "SOCKETBIND" },
3295 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3296 { config_parse_sec, "SECONDS" },
3297 { config_parse_nsec, "NANOSECONDS" },
3298 { config_parse_namespace_path_strv, "PATH [...]" },
3299 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3300 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3301 { config_parse_unit_string_printf, "STRING" },
3302 { config_parse_trigger_unit, "UNIT" },
3303 { config_parse_timer, "TIMER" },
3304 { config_parse_path_spec, "PATH" },
3305 { config_parse_notify_access, "ACCESS" },
3306 { config_parse_ip_tos, "TOS" },
3307 { config_parse_unit_condition_path, "CONDITION" },
3308 { config_parse_unit_condition_string, "CONDITION" },
3309 { config_parse_unit_condition_null, "CONDITION" },
3310 { config_parse_unit_slice, "SLICE" },
3311 { config_parse_documentation, "URL" },
3312 { config_parse_service_timeout, "SECONDS" },
3313 { config_parse_start_limit_action, "ACTION" },
3314 { config_parse_set_status, "STATUS" },
3315 { config_parse_service_sockets, "SOCKETS" },
3316 { config_parse_environ, "ENVIRON" },
3318 { config_parse_syscall_filter, "SYSCALLS" },
3319 { config_parse_syscall_archs, "ARCHS" },
3320 { config_parse_syscall_errno, "ERRNO" },
3321 { config_parse_address_families, "FAMILIES" },
3323 { config_parse_cpu_shares, "SHARES" },
3324 { config_parse_memory_limit, "LIMIT" },
3325 { config_parse_device_allow, "DEVICE" },
3326 { config_parse_device_policy, "POLICY" },
3327 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3328 { config_parse_blockio_weight, "WEIGHT" },
3329 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3330 { config_parse_long, "LONG" },
3331 { config_parse_socket_service, "SERVICE" },
3333 { config_parse_exec_selinux_context, "LABEL" },
3335 { config_parse_job_mode, "MODE" },
3336 { config_parse_job_mode_isolate, "BOOLEAN" },
3337 { config_parse_personality, "PERSONALITY" },
3340 const char *prev = NULL;
3345 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3346 const char *rvalue = "OTHER", *lvalue;
3350 const ConfigPerfItem *p;
3352 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3354 dot = strchr(i, '.');
3355 lvalue = dot ? dot + 1 : i;
3359 if (!prev || !strneq(prev, i, prefix_len+1)) {
3363 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3366 for (j = 0; j < ELEMENTSOF(table); j++)
3367 if (p->parse == table[j].callback) {
3368 rvalue = table[j].rvalue;
3372 fprintf(f, "%s=%s\n", lvalue, rvalue);