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_syntax(unit, LOG_ERR, filename, line, EINVAL,
540 "Path is not UTF-8 clean, ignoring assignment: %s",
549 c = n[k++] = cunescape_length(w, l);
555 if (!utf8_is_valid(c)) {
556 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
557 "Path is not UTF-8 clean, ignoring assignment: %s",
568 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
569 "Invalid command line, ignoring: %s", rvalue);
582 assert(path_is_absolute(path));
584 nce = new0(ExecCommand, 1);
592 nce->ignore = ignore;
594 path_kill_slashes(nce->path);
596 exec_command_append_list(e, nce);
612 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
613 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
615 int config_parse_socket_bindtodevice(const char* unit,
616 const char *filename,
619 unsigned section_line,
634 if (rvalue[0] && !streq(rvalue, "*")) {
641 free(s->bind_to_device);
642 s->bind_to_device = n;
647 DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
648 DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
650 int config_parse_exec_io_class(const char *unit,
651 const char *filename,
654 unsigned section_line,
661 ExecContext *c = data;
669 x = ioprio_class_from_string(rvalue);
671 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
672 "Failed to parse IO scheduling class, ignoring: %s", rvalue);
676 c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
677 c->ioprio_set = true;
682 int config_parse_exec_io_priority(const char *unit,
683 const char *filename,
686 unsigned section_line,
693 ExecContext *c = data;
701 r = safe_atoi(rvalue, &i);
702 if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
703 log_syntax(unit, LOG_ERR, filename, line, -r,
704 "Failed to parse IO priority, ignoring: %s", rvalue);
708 c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
709 c->ioprio_set = true;
714 int config_parse_exec_cpu_sched_policy(const char *unit,
715 const char *filename,
718 unsigned section_line,
726 ExecContext *c = data;
734 x = sched_policy_from_string(rvalue);
736 log_syntax(unit, LOG_ERR, filename, line, -x,
737 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
741 c->cpu_sched_policy = x;
742 /* Moving to or from real-time policy? We need to adjust the priority */
743 c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
744 c->cpu_sched_set = true;
749 int config_parse_exec_cpu_sched_prio(const char *unit,
750 const char *filename,
753 unsigned section_line,
760 ExecContext *c = data;
768 r = safe_atoi(rvalue, &i);
770 log_syntax(unit, LOG_ERR, filename, line, -r,
771 "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
775 /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
776 min = sched_get_priority_min(c->cpu_sched_policy);
777 max = sched_get_priority_max(c->cpu_sched_policy);
779 if (i < min || i > max) {
780 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
781 "CPU scheduling priority is out of range, ignoring: %s", rvalue);
785 c->cpu_sched_priority = i;
786 c->cpu_sched_set = true;
791 int config_parse_exec_cpu_affinity(const char *unit,
792 const char *filename,
795 unsigned section_line,
802 ExecContext *c = data;
812 if (isempty(rvalue)) {
813 /* An empty assignment resets the CPU list */
820 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
821 _cleanup_free_ char *t = NULL;
829 r = safe_atou(t, &cpu);
832 c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
837 if (r < 0 || cpu >= c->cpuset_ncpus) {
838 log_syntax(unit, LOG_ERR, filename, line, ERANGE,
839 "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
843 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
849 int config_parse_exec_capabilities(const char *unit,
850 const char *filename,
853 unsigned section_line,
860 ExecContext *c = data;
868 cap = cap_from_text(rvalue);
870 log_syntax(unit, LOG_ERR, filename, line, errno,
871 "Failed to parse capabilities, ignoring: %s", rvalue);
876 cap_free(c->capabilities);
877 c->capabilities = cap;
882 int config_parse_exec_secure_bits(const char *unit,
883 const char *filename,
886 unsigned section_line,
893 ExecContext *c = data;
903 if (isempty(rvalue)) {
904 /* An empty assignment resets the field */
909 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
910 if (first_word(w, "keep-caps"))
911 c->secure_bits |= 1<<SECURE_KEEP_CAPS;
912 else if (first_word(w, "keep-caps-locked"))
913 c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
914 else if (first_word(w, "no-setuid-fixup"))
915 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
916 else if (first_word(w, "no-setuid-fixup-locked"))
917 c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
918 else if (first_word(w, "noroot"))
919 c->secure_bits |= 1<<SECURE_NOROOT;
920 else if (first_word(w, "noroot-locked"))
921 c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
923 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
924 "Failed to parse secure bits, ignoring: %s", rvalue);
932 int config_parse_bounding_set(const char *unit,
933 const char *filename,
936 unsigned section_line,
943 uint64_t *capability_bounding_set_drop = data;
955 if (rvalue[0] == '~') {
960 /* Note that we store this inverted internally, since the
961 * kernel wants it like this. But we actually expose it
962 * non-inverted everywhere to have a fully normalized
965 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
966 _cleanup_free_ char *t = NULL;
974 r = cap_from_name(t, &cap);
976 log_syntax(unit, LOG_ERR, filename, line, errno,
977 "Failed to parse capability in bounding set, ignoring: %s", t);
981 sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
985 *capability_bounding_set_drop |= sum;
987 *capability_bounding_set_drop |= ~sum;
992 int config_parse_limit(const char *unit,
993 const char *filename,
996 unsigned section_line,
1003 struct rlimit **rl = data;
1004 unsigned long long u;
1013 if (streq(rvalue, "infinity"))
1014 u = (unsigned long long) RLIM_INFINITY;
1018 r = safe_atollu(rvalue, &u);
1020 log_syntax(unit, LOG_ERR, filename, line, -r,
1021 "Failed to parse resource value, ignoring: %s", rvalue);
1027 *rl = new(struct rlimit, 1);
1032 (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
1036 #ifdef HAVE_SYSV_COMPAT
1037 int config_parse_sysv_priority(const char *unit,
1038 const char *filename,
1040 const char *section,
1041 unsigned section_line,
1048 int *priority = data;
1056 r = safe_atoi(rvalue, &i);
1057 if (r < 0 || i < 0) {
1058 log_syntax(unit, LOG_ERR, filename, line, -r,
1059 "Failed to parse SysV start priority, ignoring: %s", rvalue);
1063 *priority = (int) i;
1068 DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
1070 int config_parse_kill_signal(const char *unit,
1071 const char *filename,
1073 const char *section,
1074 unsigned section_line,
1089 r = signal_from_string_try_harder(rvalue);
1091 log_syntax(unit, LOG_ERR, filename, line, -r,
1092 "Failed to parse kill signal, ignoring: %s", rvalue);
1100 int config_parse_exec_mount_flags(const char *unit,
1101 const char *filename,
1103 const char *section,
1104 unsigned section_line,
1111 ExecContext *c = data;
1115 unsigned long flags = 0;
1122 FOREACH_WORD_SEPARATOR(w, l, rvalue, ", ", state) {
1123 _cleanup_free_ char *t;
1129 if (streq(t, "shared"))
1131 else if (streq(t, "slave"))
1133 else if (streq(w, "private"))
1134 flags |= MS_PRIVATE;
1136 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1137 "Failed to parse mount flag %s, ignoring: %s",
1143 c->mount_flags = flags;
1147 int config_parse_exec_selinux_context(
1149 const char *filename,
1151 const char *section,
1152 unsigned section_line,
1159 ExecContext *c = data;
1170 if (isempty(rvalue)) {
1171 free(c->selinux_context);
1172 c->selinux_context = NULL;
1173 c->selinux_context_ignore = false;
1177 if (rvalue[0] == '-') {
1183 r = unit_name_printf(u, rvalue, &k);
1185 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1189 free(c->selinux_context);
1190 c->selinux_context = k;
1191 c->selinux_context_ignore = ignore;
1196 int config_parse_exec_apparmor_profile(
1198 const char *filename,
1200 const char *section,
1201 unsigned section_line,
1208 ExecContext *c = data;
1219 if (isempty(rvalue)) {
1220 free(c->apparmor_profile);
1221 c->apparmor_profile = NULL;
1222 c->apparmor_profile_ignore = false;
1226 if (rvalue[0] == '-') {
1232 r = unit_name_printf(u, rvalue, &k);
1234 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1238 free(c->apparmor_profile);
1239 c->apparmor_profile = k;
1240 c->apparmor_profile_ignore = ignore;
1245 int config_parse_timer(const char *unit,
1246 const char *filename,
1248 const char *section,
1249 unsigned section_line,
1260 CalendarSpec *c = NULL;
1268 if (isempty(rvalue)) {
1269 /* Empty assignment resets list */
1270 timer_free_values(t);
1274 b = timer_base_from_string(lvalue);
1276 log_syntax(unit, LOG_ERR, filename, line, -b,
1277 "Failed to parse timer base, ignoring: %s", lvalue);
1281 if (b == TIMER_CALENDAR) {
1282 if (calendar_spec_from_string(rvalue, &c) < 0) {
1283 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1284 "Failed to parse calendar specification, ignoring: %s",
1289 id = CLOCK_REALTIME;
1291 if (parse_sec(rvalue, &u) < 0) {
1292 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1293 "Failed to parse timer value, ignoring: %s",
1298 id = CLOCK_MONOTONIC;
1301 v = new0(TimerValue, 1);
1308 v->calendar_spec = c;
1310 LIST_PREPEND(value, t->values, v);
1315 int config_parse_trigger_unit(
1317 const char *filename,
1319 const char *section,
1320 unsigned section_line,
1327 _cleanup_free_ char *p = NULL;
1337 if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
1338 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1339 "Multiple units to trigger specified, ignoring: %s", rvalue);
1343 r = unit_name_printf(u, rvalue, &p);
1345 log_syntax(unit, LOG_ERR, filename, line, -r,
1346 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1348 type = unit_name_to_type(p ?: rvalue);
1350 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1351 "Unit type not valid, ignoring: %s", rvalue);
1355 if (type == u->type) {
1356 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1357 "Trigger cannot be of same type, ignoring: %s", rvalue);
1361 r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
1363 log_syntax(unit, LOG_ERR, filename, line, -r,
1364 "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
1371 int config_parse_path_spec(const char *unit,
1372 const char *filename,
1374 const char *section,
1375 unsigned section_line,
1385 _cleanup_free_ char *k = NULL;
1393 if (isempty(rvalue)) {
1394 /* Empty assignment clears list */
1399 b = path_type_from_string(lvalue);
1401 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1402 "Failed to parse path type, ignoring: %s", lvalue);
1406 r = unit_full_printf(UNIT(p), rvalue, &k);
1412 log_syntax(unit, LOG_ERR, filename, line, -r,
1413 "Failed to resolve unit specifiers on %s. Ignoring.",
1417 if (!path_is_absolute(k)) {
1418 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1419 "Path is not absolute, ignoring: %s", k);
1423 s = new0(PathSpec, 1);
1428 s->path = path_kill_slashes(k);
1433 LIST_PREPEND(spec, p->specs, s);
1438 int config_parse_socket_service(const char *unit,
1439 const char *filename,
1441 const char *section,
1442 unsigned section_line,
1449 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1453 _cleanup_free_ char *p = NULL;
1460 r = unit_name_printf(UNIT(s), rvalue, &p);
1462 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1466 if (!endswith(p, ".service")) {
1467 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1471 r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
1473 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1477 unit_ref_set(&s->service, x);
1482 int config_parse_service_sockets(const char *unit,
1483 const char *filename,
1485 const char *section,
1486 unsigned section_line,
1503 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1504 _cleanup_free_ char *t = NULL, *k = NULL;
1510 r = unit_name_printf(UNIT(s), t, &k);
1512 log_syntax(unit, LOG_ERR, filename, line, -r,
1513 "Failed to resolve specifiers, ignoring: %s", strerror(-r));
1515 if (!endswith(k ?: t, ".socket")) {
1516 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1517 "Unit must be of type socket, ignoring: %s", k ?: t);
1521 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k ?: t, NULL, true);
1523 log_syntax(unit, LOG_ERR, filename, line, -r,
1524 "Failed to add dependency on %s, ignoring: %s",
1525 k ?: t, strerror(-r));
1527 r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k ?: t, NULL, true);
1535 int config_parse_service_timeout(const char *unit,
1536 const char *filename,
1538 const char *section,
1539 unsigned section_line,
1546 Service *s = userdata;
1554 r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
1555 rvalue, data, userdata);
1559 if (streq(lvalue, "TimeoutSec")) {
1560 s->start_timeout_defined = true;
1561 s->timeout_stop_usec = s->timeout_start_usec;
1562 } else if (streq(lvalue, "TimeoutStartSec"))
1563 s->start_timeout_defined = true;
1568 int config_parse_busname_service(
1570 const char *filename,
1572 const char *section,
1573 unsigned section_line,
1580 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1584 _cleanup_free_ char *p = NULL;
1591 r = unit_name_printf(UNIT(n), rvalue, &p);
1593 log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
1597 if (!endswith(p, ".service")) {
1598 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
1602 r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
1604 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
1608 unit_ref_set(&n->service, x);
1613 int config_parse_unit_env_file(const char *unit,
1614 const char *filename,
1616 const char *section,
1617 unsigned section_line,
1626 _cleanup_free_ char *n = NULL;
1635 if (isempty(rvalue)) {
1636 /* Empty assignment frees the list */
1642 r = unit_full_printf(u, rvalue, &n);
1644 log_syntax(unit, LOG_ERR, filename, line, r,
1645 "Failed to resolve specifiers, ignoring: %s", rvalue);
1648 if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
1649 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1650 "Path '%s' is not absolute, ignoring.", s);
1654 r = strv_extend(env, s);
1661 int config_parse_environ(const char *unit,
1662 const char *filename,
1664 const char *section,
1665 unsigned section_line,
1673 char*** env = data, *w, *state;
1675 _cleanup_free_ char *k = NULL;
1683 if (isempty(rvalue)) {
1684 /* Empty assignment resets the list */
1691 r = unit_full_printf(u, rvalue, &k);
1693 log_syntax(unit, LOG_ERR, filename, line, -r,
1694 "Failed to resolve specifiers, ignoring: %s", rvalue);
1702 FOREACH_WORD_QUOTED(w, l, k, state) {
1703 _cleanup_free_ char *n;
1706 n = cunescape_length(w, l);
1710 if (!env_assignment_is_valid(n)) {
1711 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1712 "Invalid environment assignment, ignoring: %s", rvalue);
1716 x = strv_env_set(*env, n);
1727 int config_parse_ip_tos(const char *unit,
1728 const char *filename,
1730 const char *section,
1731 unsigned section_line,
1738 int *ip_tos = data, x;
1745 x = ip_tos_from_string(rvalue);
1747 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1748 "Failed to parse IP TOS value, ignoring: %s", rvalue);
1756 int config_parse_unit_condition_path(const char *unit,
1757 const char *filename,
1759 const char *section,
1760 unsigned section_line,
1767 ConditionType cond = ltype;
1769 bool trigger, negate;
1771 _cleanup_free_ char *p = NULL;
1779 if (isempty(rvalue)) {
1780 /* Empty assignment resets the list */
1781 condition_free_list(u->conditions);
1782 u->conditions = NULL;
1786 trigger = rvalue[0] == '|';
1790 negate = rvalue[0] == '!';
1794 r = unit_full_printf(u, rvalue, &p);
1796 log_syntax(unit, LOG_ERR, filename, line, -r,
1797 "Failed to resolve specifiers, ignoring: %s", rvalue);
1804 if (!path_is_absolute(p)) {
1805 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1806 "Path in condition not absolute, ignoring: %s", p);
1810 c = condition_new(cond, p, trigger, negate);
1814 LIST_PREPEND(conditions, u->conditions, c);
1818 int config_parse_unit_condition_string(const char *unit,
1819 const char *filename,
1821 const char *section,
1822 unsigned section_line,
1829 ConditionType cond = ltype;
1831 bool trigger, negate;
1833 _cleanup_free_ char *s = NULL;
1841 if (isempty(rvalue)) {
1842 /* Empty assignment resets the list */
1843 condition_free_list(u->conditions);
1844 u->conditions = NULL;
1848 trigger = rvalue[0] == '|';
1852 negate = rvalue[0] == '!';
1856 r = unit_full_printf(u, rvalue, &s);
1858 log_syntax(unit, LOG_ERR, filename, line, -r,
1859 "Failed to resolve specifiers, ignoring: %s", rvalue);
1866 c = condition_new(cond, s, trigger, negate);
1870 LIST_PREPEND(conditions, u->conditions, c);
1874 int config_parse_unit_condition_null(const char *unit,
1875 const char *filename,
1877 const char *section,
1878 unsigned section_line,
1887 bool trigger, negate;
1895 if (isempty(rvalue)) {
1896 /* Empty assignment resets the list */
1897 condition_free_list(u->conditions);
1898 u->conditions = NULL;
1902 trigger = rvalue[0] == '|';
1906 negate = rvalue[0] == '!';
1910 b = parse_boolean(rvalue);
1912 log_syntax(unit, LOG_ERR, filename, line, -b,
1913 "Failed to parse boolean value in condition, ignoring: %s",
1921 c = condition_new(CONDITION_NULL, NULL, trigger, negate);
1925 LIST_PREPEND(conditions, u->conditions, c);
1929 DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
1930 DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
1932 int config_parse_unit_requires_mounts_for(
1934 const char *filename,
1936 const char *section,
1937 unsigned section_line,
1954 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1956 _cleanup_free_ char *n;
1962 if (!utf8_is_valid(n)) {
1963 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1964 "Path is not UTF-8 clean, ignoring assignment: %s", rvalue);
1968 r = unit_require_mounts_for(u, n);
1970 log_syntax(unit, LOG_ERR, filename, line, r,
1971 "Failed to add required mount for, ignoring: %s", rvalue);
1979 int config_parse_documentation(const char *unit,
1980 const char *filename,
1982 const char *section,
1983 unsigned section_line,
1999 if (isempty(rvalue)) {
2000 /* Empty assignment resets the list */
2001 strv_free(u->documentation);
2002 u->documentation = NULL;
2006 r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
2007 rvalue, data, userdata);
2011 for (a = b = u->documentation; a && *a; a++) {
2013 if (is_valid_documentation_url(*a))
2016 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2017 "Invalid URL, ignoring: %s", *a);
2028 int config_parse_syscall_filter(
2030 const char *filename,
2032 const char *section,
2033 unsigned section_line,
2040 static const char default_syscalls[] =
2047 ExecContext *c = data;
2049 bool invert = false;
2059 if (isempty(rvalue)) {
2060 /* Empty assignment resets the list */
2061 set_free(c->syscall_filter);
2062 c->syscall_filter = NULL;
2063 c->syscall_whitelist = false;
2067 if (rvalue[0] == '~') {
2072 if (!c->syscall_filter) {
2073 c->syscall_filter = set_new(trivial_hash_func, trivial_compare_func);
2074 if (!c->syscall_filter)
2078 /* Allow everything but the ones listed */
2079 c->syscall_whitelist = false;
2083 /* Allow nothing but the ones listed */
2084 c->syscall_whitelist = true;
2086 /* Accept default syscalls if we are on a whitelist */
2087 NULSTR_FOREACH(i, default_syscalls) {
2090 id = seccomp_syscall_resolve_name(i);
2094 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2103 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2104 _cleanup_free_ char *t = NULL;
2111 id = seccomp_syscall_resolve_name(t);
2113 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call, ignoring: %s", t);
2117 /* If we previously wanted to forbid a syscall and now
2118 * we want to allow it, then remove it from the list
2120 if (!invert == c->syscall_whitelist) {
2121 r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
2127 set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
2130 c->no_new_privileges = true;
2135 int config_parse_syscall_archs(
2137 const char *filename,
2139 const char *section,
2140 unsigned section_line,
2152 if (isempty(rvalue)) {
2158 r = set_ensure_allocated(archs, trivial_hash_func, trivial_compare_func);
2162 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2163 _cleanup_free_ char *t = NULL;
2170 r = seccomp_arch_from_string(t, &a);
2172 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse system call architecture, ignoring: %s", t);
2176 r = set_put(*archs, UINT32_TO_PTR(a + 1));
2186 int config_parse_syscall_errno(
2188 const char *filename,
2190 const char *section,
2191 unsigned section_line,
2198 ExecContext *c = data;
2205 if (isempty(rvalue)) {
2206 /* Empty assignment resets to KILL */
2207 c->syscall_errno = 0;
2211 e = errno_from_name(rvalue);
2213 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse error number, ignoring: %s", rvalue);
2217 c->syscall_errno = e;
2221 int config_parse_address_families(
2223 const char *filename,
2225 const char *section,
2226 unsigned section_line,
2233 ExecContext *c = data;
2235 bool invert = false;
2245 if (isempty(rvalue)) {
2246 /* Empty assignment resets the list */
2247 set_free(c->address_families);
2248 c->address_families = NULL;
2249 c->address_families_whitelist = false;
2253 if (rvalue[0] == '~') {
2258 if (!c->address_families) {
2259 c->address_families = set_new(trivial_hash_func, trivial_compare_func);
2260 if (!c->address_families)
2263 c->address_families_whitelist = !invert;
2266 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2267 _cleanup_free_ char *t = NULL;
2274 af = af_from_name(t);
2276 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse address family, ignoring: %s", t);
2280 /* If we previously wanted to forbid an address family and now
2281 * we want to allow it, then remove it from the list
2283 if (!invert == c->address_families_whitelist) {
2284 r = set_put(c->address_families, INT_TO_PTR(af));
2290 set_remove(c->address_families, INT_TO_PTR(af));
2297 int config_parse_unit_slice(
2299 const char *filename,
2301 const char *section,
2302 unsigned section_line,
2309 _cleanup_free_ char *k = NULL;
2310 Unit *u = userdata, *slice;
2318 r = unit_name_printf(u, rvalue, &k);
2320 log_syntax(unit, LOG_ERR, filename, line, -r,
2321 "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
2328 r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
2330 log_syntax(unit, LOG_ERR, filename, line, -r,
2331 "Failed to load slice unit %s. Ignoring.", k);
2335 if (slice->type != UNIT_SLICE) {
2336 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2337 "Slice unit %s is not a slice. Ignoring.", k);
2341 unit_ref_set(&u->slice, slice);
2345 DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
2347 int config_parse_cpu_shares(
2349 const char *filename,
2351 const char *section,
2352 unsigned section_line,
2359 CGroupContext *c = data;
2367 if (isempty(rvalue)) {
2368 c->cpu_shares = 1024;
2372 r = safe_atolu(rvalue, &lu);
2373 if (r < 0 || lu <= 0) {
2374 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2375 "CPU shares '%s' invalid. Ignoring.", rvalue);
2383 int config_parse_memory_limit(
2385 const char *filename,
2387 const char *section,
2388 unsigned section_line,
2395 CGroupContext *c = data;
2399 if (isempty(rvalue)) {
2400 c->memory_limit = (uint64_t) -1;
2404 assert_cc(sizeof(uint64_t) == sizeof(off_t));
2406 r = parse_size(rvalue, 1024, &bytes);
2408 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
2412 c->memory_limit = (uint64_t) bytes;
2416 int config_parse_device_allow(
2418 const char *filename,
2420 const char *section,
2421 unsigned section_line,
2428 _cleanup_free_ char *path = NULL;
2429 CGroupContext *c = data;
2430 CGroupDeviceAllow *a;
2434 if (isempty(rvalue)) {
2435 while (c->device_allow)
2436 cgroup_context_free_device_allow(c, c->device_allow);
2441 n = strcspn(rvalue, WHITESPACE);
2442 path = strndup(rvalue, n);
2446 if (!startswith(path, "/dev/") &&
2447 !startswith(path, "block-") &&
2448 !startswith(path, "char-")) {
2449 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
2453 m = rvalue + n + strspn(rvalue + n, WHITESPACE);
2457 if (!in_charset(m, "rwm")) {
2458 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device rights '%s'. Ignoring.", m);
2462 a = new0(CGroupDeviceAllow, 1);
2468 a->r = !!strchr(m, 'r');
2469 a->w = !!strchr(m, 'w');
2470 a->m = !!strchr(m, 'm');
2472 LIST_PREPEND(device_allow, c->device_allow, a);
2476 int config_parse_blockio_weight(
2478 const char *filename,
2480 const char *section,
2481 unsigned section_line,
2488 CGroupContext *c = data;
2496 if (isempty(rvalue)) {
2497 c->blockio_weight = 1000;
2501 r = safe_atolu(rvalue, &lu);
2502 if (r < 0 || lu < 10 || lu > 1000) {
2503 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2504 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2508 c->blockio_weight = lu;
2513 int config_parse_blockio_device_weight(
2515 const char *filename,
2517 const char *section,
2518 unsigned section_line,
2525 _cleanup_free_ char *path = NULL;
2526 CGroupBlockIODeviceWeight *w;
2527 CGroupContext *c = data;
2537 if (isempty(rvalue)) {
2538 while (c->blockio_device_weights)
2539 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
2544 n = strcspn(rvalue, WHITESPACE);
2545 weight = rvalue + n;
2547 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2548 "Expected block device and device weight. Ignoring.");
2552 path = strndup(rvalue, n);
2556 if (!path_startswith(path, "/dev")) {
2557 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2558 "Invalid device node path '%s'. Ignoring.", path);
2562 weight += strspn(weight, WHITESPACE);
2563 r = safe_atolu(weight, &lu);
2564 if (r < 0 || lu < 10 || lu > 1000) {
2565 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2566 "Block IO weight '%s' invalid. Ignoring.", rvalue);
2571 w = new0(CGroupBlockIODeviceWeight, 1);
2580 LIST_PREPEND(device_weights, c->blockio_device_weights, w);
2584 int config_parse_blockio_bandwidth(
2586 const char *filename,
2588 const char *section,
2589 unsigned section_line,
2596 _cleanup_free_ char *path = NULL;
2597 CGroupBlockIODeviceBandwidth *b;
2598 CGroupContext *c = data;
2599 const char *bandwidth;
2609 read = streq("BlockIOReadBandwidth", lvalue);
2611 if (isempty(rvalue)) {
2612 CGroupBlockIODeviceBandwidth *next;
2614 LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
2615 if (b->read == read)
2616 cgroup_context_free_blockio_device_bandwidth(c, b);
2621 n = strcspn(rvalue, WHITESPACE);
2622 bandwidth = rvalue + n;
2623 bandwidth += strspn(bandwidth, WHITESPACE);
2626 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2627 "Expected space separated pair of device node and bandwidth. Ignoring.");
2631 path = strndup(rvalue, n);
2635 if (!path_startswith(path, "/dev")) {
2636 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2637 "Invalid device node path '%s'. Ignoring.", path);
2641 r = parse_size(bandwidth, 1000, &bytes);
2642 if (r < 0 || bytes <= 0) {
2643 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
2647 b = new0(CGroupBlockIODeviceBandwidth, 1);
2653 b->bandwidth = (uint64_t) bytes;
2656 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
2661 DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
2663 int config_parse_job_mode_isolate(
2665 const char *filename,
2667 const char *section,
2668 unsigned section_line,
2682 r = parse_boolean(rvalue);
2684 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse boolean, ignoring: %s", rvalue);
2688 *m = r ? JOB_ISOLATE : JOB_REPLACE;
2692 int config_parse_personality(
2694 const char *filename,
2696 const char *section,
2697 unsigned section_line,
2704 unsigned long *personality = data, p;
2709 assert(personality);
2711 p = personality_from_string(rvalue);
2712 if (p == 0xffffffffUL) {
2713 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
2714 "Failed to parse personality, ignoring: %s", rvalue);
2722 int config_parse_runtime_directory(
2724 const char *filename,
2726 const char *section,
2727 unsigned section_line,
2734 char***rt = data, *w, *state;
2743 if (isempty(rvalue)) {
2744 /* Empty assignment resets the list */
2750 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
2751 _cleanup_free_ char *n;
2757 if (!filename_is_safe(n)) {
2758 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
2762 r = strv_push(rt, n);
2772 int config_parse_set_status(
2774 const char *filename,
2776 const char *section,
2777 unsigned section_line,
2788 ExitStatusSet *status_set = data;
2795 if (isempty(rvalue)) {
2796 /* Empty assignment resets the list */
2798 set_free(status_set->signal);
2799 set_free(status_set->code);
2801 status_set->signal = status_set->code = NULL;
2805 FOREACH_WORD(w, l, rvalue, state) {
2806 _cleanup_free_ char *temp;
2809 temp = strndup(w, l);
2813 r = safe_atoi(temp, &val);
2815 val = signal_from_string_try_harder(temp);
2818 r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func);
2822 r = set_put(status_set->signal, INT_TO_PTR(val));
2824 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2828 log_syntax(unit, LOG_ERR, filename, line, -val, "Failed to parse value, ignoring: %s", w);
2832 if (val < 0 || val > 255)
2833 log_syntax(unit, LOG_ERR, filename, line, ERANGE, "Value %d is outside range 0-255, ignoring", val);
2835 r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func);
2839 r = set_put(status_set->code, INT_TO_PTR(val));
2841 log_syntax(unit, LOG_ERR, filename, line, -r, "Unable to store: %s", w);
2851 #define FOLLOW_MAX 8
2853 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
2864 /* This will update the filename pointer if the loaded file is
2865 * reached by a symlink. The old string will be freed. */
2868 char *target, *name;
2870 if (c++ >= FOLLOW_MAX)
2873 path_kill_slashes(*filename);
2875 /* Add the file name we are currently looking at to
2876 * the names of this unit, but only if it is a valid
2878 name = basename(*filename);
2880 if (unit_name_is_valid(name, TEMPLATE_VALID)) {
2882 id = set_get(names, name);
2888 r = set_consume(names, id);
2894 /* Try to open the file name, but don't if its a symlink */
2895 fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
2902 /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2903 r = readlink_and_make_absolute(*filename, &target);
2911 f = fdopen(fd, "re");
2914 close_nointr_nofail(fd);
2923 static int merge_by_names(Unit **u, Set *names, const char *id) {
2931 /* Let's try to add in all symlink names we found */
2932 while ((k = set_steal_first(names))) {
2934 /* First try to merge in the other name into our
2936 r = unit_merge_by_name(*u, k);
2940 /* Hmm, we couldn't merge the other unit into
2941 * ours? Then let's try it the other way
2944 other = manager_get_unit((*u)->manager, k);
2948 r = unit_merge(other, *u);
2951 return merge_by_names(u, names, NULL);
2959 unit_choose_id(*u, id);
2967 static int load_from_path(Unit *u, const char *path) {
2969 _cleanup_set_free_free_ Set *symlink_names = NULL;
2970 _cleanup_fclose_ FILE *f = NULL;
2971 _cleanup_free_ char *filename = NULL;
2979 symlink_names = set_new(string_hash_func, string_compare_func);
2983 if (path_is_absolute(path)) {
2985 filename = strdup(path);
2989 r = open_follow(&filename, &f, symlink_names, &id);
3001 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
3003 /* Instead of opening the path right away, we manually
3004 * follow all symlinks and add their name to our unit
3005 * name set while doing so */
3006 filename = path_make_absolute(path, *p);
3010 if (u->manager->unit_path_cache &&
3011 !set_get(u->manager->unit_path_cache, filename))
3014 r = open_follow(&filename, &f, symlink_names, &id);
3023 /* Empty the symlink names for the next run */
3024 set_clear_free(symlink_names);
3033 /* Hmm, no suitable file found? */
3037 r = merge_by_names(&merged, symlink_names, id);
3042 u->load_state = UNIT_MERGED;
3046 if (fstat(fileno(f), &st) < 0)
3049 if (null_or_empty(&st))
3050 u->load_state = UNIT_MASKED;
3052 u->load_state = UNIT_LOADED;
3054 /* Now, parse the file contents */
3055 r = config_parse(u->id, filename, f, UNIT_VTABLE(u)->sections,
3056 config_item_perf_lookup,
3057 (void*) load_fragment_gperf_lookup, false, true, u);
3062 free(u->fragment_path);
3063 u->fragment_path = filename;
3066 u->fragment_mtime = timespec_load(&st.st_mtim);
3068 if (u->source_path) {
3069 if (stat(u->source_path, &st) >= 0)
3070 u->source_mtime = timespec_load(&st.st_mtim);
3072 u->source_mtime = 0;
3078 int unit_load_fragment(Unit *u) {
3084 assert(u->load_state == UNIT_STUB);
3087 /* First, try to find the unit under its id. We always look
3088 * for unit files in the default directories, to make it easy
3089 * to override things by placing things in /etc/systemd/system */
3090 r = load_from_path(u, u->id);
3094 /* Try to find an alias we can load this with */
3095 if (u->load_state == UNIT_STUB)
3096 SET_FOREACH(t, u->names, i) {
3101 r = load_from_path(u, t);
3105 if (u->load_state != UNIT_STUB)
3109 /* And now, try looking for it under the suggested (originally linked) path */
3110 if (u->load_state == UNIT_STUB && u->fragment_path) {
3112 r = load_from_path(u, u->fragment_path);
3116 if (u->load_state == UNIT_STUB) {
3117 /* Hmm, this didn't work? Then let's get rid
3118 * of the fragment path stored for us, so that
3119 * we don't point to an invalid location. */
3120 free(u->fragment_path);
3121 u->fragment_path = NULL;
3125 /* Look for a template */
3126 if (u->load_state == UNIT_STUB && u->instance) {
3127 _cleanup_free_ char *k;
3129 k = unit_name_template(u->id);
3133 r = load_from_path(u, k);
3137 if (u->load_state == UNIT_STUB)
3138 SET_FOREACH(t, u->names, i) {
3139 _cleanup_free_ char *z = NULL;
3144 z = unit_name_template(t);
3148 r = load_from_path(u, z);
3152 if (u->load_state != UNIT_STUB)
3160 void unit_dump_config_items(FILE *f) {
3161 static const struct {
3162 const ConfigParserCallback callback;
3165 #if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
3166 { config_parse_warn_compat, "NOTSUPPORTED" },
3168 { config_parse_int, "INTEGER" },
3169 { config_parse_unsigned, "UNSIGNED" },
3170 { config_parse_iec_size, "SIZE" },
3171 { config_parse_iec_off, "SIZE" },
3172 { config_parse_si_size, "SIZE" },
3173 { config_parse_bool, "BOOLEAN" },
3174 { config_parse_string, "STRING" },
3175 { config_parse_path, "PATH" },
3176 { config_parse_unit_path_printf, "PATH" },
3177 { config_parse_strv, "STRING [...]" },
3178 { config_parse_exec_nice, "NICE" },
3179 { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
3180 { config_parse_exec_io_class, "IOCLASS" },
3181 { config_parse_exec_io_priority, "IOPRIORITY" },
3182 { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
3183 { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
3184 { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
3185 { config_parse_mode, "MODE" },
3186 { config_parse_unit_env_file, "FILE" },
3187 { config_parse_output, "OUTPUT" },
3188 { config_parse_input, "INPUT" },
3189 { config_parse_log_facility, "FACILITY" },
3190 { config_parse_log_level, "LEVEL" },
3191 { config_parse_exec_capabilities, "CAPABILITIES" },
3192 { config_parse_exec_secure_bits, "SECUREBITS" },
3193 { config_parse_bounding_set, "BOUNDINGSET" },
3194 { config_parse_limit, "LIMIT" },
3195 { config_parse_unit_deps, "UNIT [...]" },
3196 { config_parse_exec, "PATH [ARGUMENT [...]]" },
3197 { config_parse_service_type, "SERVICETYPE" },
3198 { config_parse_service_restart, "SERVICERESTART" },
3199 #ifdef HAVE_SYSV_COMPAT
3200 { config_parse_sysv_priority, "SYSVPRIORITY" },
3202 { config_parse_kill_mode, "KILLMODE" },
3203 { config_parse_kill_signal, "SIGNAL" },
3204 { config_parse_socket_listen, "SOCKET [...]" },
3205 { config_parse_socket_bind, "SOCKETBIND" },
3206 { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
3207 { config_parse_sec, "SECONDS" },
3208 { config_parse_nsec, "NANOSECONDS" },
3209 { config_parse_path_strv, "PATH [...]" },
3210 { config_parse_unit_requires_mounts_for, "PATH [...]" },
3211 { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
3212 { config_parse_unit_string_printf, "STRING" },
3213 { config_parse_trigger_unit, "UNIT" },
3214 { config_parse_timer, "TIMER" },
3215 { config_parse_path_spec, "PATH" },
3216 { config_parse_notify_access, "ACCESS" },
3217 { config_parse_ip_tos, "TOS" },
3218 { config_parse_unit_condition_path, "CONDITION" },
3219 { config_parse_unit_condition_string, "CONDITION" },
3220 { config_parse_unit_condition_null, "CONDITION" },
3221 { config_parse_unit_slice, "SLICE" },
3222 { config_parse_documentation, "URL" },
3223 { config_parse_service_timeout, "SECONDS" },
3224 { config_parse_start_limit_action, "ACTION" },
3225 { config_parse_set_status, "STATUS" },
3226 { config_parse_service_sockets, "SOCKETS" },
3227 { config_parse_environ, "ENVIRON" },
3229 { config_parse_syscall_filter, "SYSCALLS" },
3230 { config_parse_syscall_archs, "ARCHS" },
3231 { config_parse_syscall_errno, "ERRNO" },
3232 { config_parse_address_families, "FAMILIES" },
3234 { config_parse_cpu_shares, "SHARES" },
3235 { config_parse_memory_limit, "LIMIT" },
3236 { config_parse_device_allow, "DEVICE" },
3237 { config_parse_device_policy, "POLICY" },
3238 { config_parse_blockio_bandwidth, "BANDWIDTH" },
3239 { config_parse_blockio_weight, "WEIGHT" },
3240 { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
3241 { config_parse_long, "LONG" },
3242 { config_parse_socket_service, "SERVICE" },
3244 { config_parse_exec_selinux_context, "LABEL" },
3246 { config_parse_job_mode, "MODE" },
3247 { config_parse_job_mode_isolate, "BOOLEAN" },
3248 { config_parse_personality, "PERSONALITY" },
3251 const char *prev = NULL;
3256 NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
3257 const char *rvalue = "OTHER", *lvalue;
3261 const ConfigPerfItem *p;
3263 assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
3265 dot = strchr(i, '.');
3266 lvalue = dot ? dot + 1 : i;
3270 if (!prev || !strneq(prev, i, prefix_len+1)) {
3274 fprintf(f, "[%.*s]\n", (int) prefix_len, i);
3277 for (j = 0; j < ELEMENTSOF(table); j++)
3278 if (p->parse == table[j].callback) {
3279 rvalue = table[j].rvalue;
3283 fprintf(f, "%s=%s\n", lvalue, rvalue);