chiark / gitweb /
vconsole: add new utility to initialize the virtual console
[elogind.git] / src / load-fragment.c
index 1cc7c5cc3940c46e004877f6cffdf2d1c6dbb795..1190ef4accf50dd3645c91bd82a3193b11257c04 100644 (file)
@@ -1,4 +1,4 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 
 /***
   This file is part of systemd.
@@ -29,6 +29,7 @@
 #include <sys/prctl.h>
 #include <sys/mount.h>
 #include <linux/fs.h>
+#include <sys/stat.h>
 
 #include "unit.h"
 #include "strv.h"
@@ -39,8 +40,7 @@
 #include "securebits.h"
 #include "missing.h"
 #include "unit-name.h"
-
-#define COMMENTS "#;\n"
+#include "bus-errors.h"
 
 static int config_parse_deps(
                 const char *filename,
@@ -61,7 +61,7 @@ static int config_parse_deps(
         assert(lvalue);
         assert(rvalue);
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 char *t, *k;
                 int r;
 
@@ -75,10 +75,14 @@ static int config_parse_deps(
                         return -ENOMEM;
 
                 r = unit_add_dependency_by_name(u, d, k, NULL, true);
-                free(k);
 
-                if (r < 0)
-                        return r;
+                if (r < 0) {
+                        log_error("Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
+                        free(k);
+                        return 0;
+                }
+
+                free(k);
         }
 
         return 0;
@@ -103,7 +107,7 @@ static int config_parse_names(
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 char *t, *k;
                 int r;
 
@@ -117,10 +121,14 @@ static int config_parse_names(
                         return -ENOMEM;
 
                 r = unit_merge_by_name(u, k);
-                free(k);
 
-                if (r < 0)
-                        return r;
+                if (r < 0) {
+                        log_error("Failed to add name %s, ignoring: %s", k, strerror(-r));
+                        free(k);
+                        return 0;
+                }
+
+                free(k);
         }
 
         return 0;
@@ -195,9 +203,9 @@ static int config_parse_listen(
                 p->type = SOCKET_SOCKET;
 
                 if ((r = socket_address_parse(&p->address, rvalue)) < 0) {
-                        log_error("[%s:%u] Failed to parse address value: %s", filename, line, rvalue);
+                        log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
                         free(p);
-                        return r;
+                        return 0;
                 }
 
                 if (streq(lvalue, "ListenStream"))
@@ -210,8 +218,9 @@ static int config_parse_listen(
                 }
 
                 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
+                        log_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
                         free(p);
-                        return -EPROTONOSUPPORT;
+                        return 0;
                 }
         }
 
@@ -244,8 +253,8 @@ static int config_parse_socket_bind(
                 int r;
 
                 if ((r = parse_boolean(rvalue)) < 0) {
-                        log_error("[%s:%u] Failed to parse bind IPv6 only value: %s", filename, line, rvalue);
-                        return -EBADMSG;
+                        log_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, rvalue);
+                        return 0;
                 }
 
                 s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
@@ -273,13 +282,13 @@ static int config_parse_nice(
         assert(data);
 
         if ((r = safe_atoi(rvalue, &priority)) < 0) {
-                log_error("[%s:%u] Failed to parse nice priority: %s", filename, line, rvalue);
-                return r;
+                log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
+                return 0;
         }
 
         if (priority < PRIO_MIN || priority >= PRIO_MAX) {
-                log_error("[%s:%u] Nice priority out of range: %s", filename, line, rvalue);
-                return -ERANGE;
+                log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         c->nice = priority;
@@ -288,7 +297,7 @@ static int config_parse_nice(
         return 0;
 }
 
-static int config_parse_oom_adjust(
+static int config_parse_oom_score_adjust(
                 const char *filename,
                 unsigned line,
                 const char *section,
@@ -306,17 +315,17 @@ static int config_parse_oom_adjust(
         assert(data);
 
         if ((r = safe_atoi(rvalue, &oa)) < 0) {
-                log_error("[%s:%u] Failed to parse OOM adjust value: %s", filename, line, rvalue);
-                return r;
+                log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
-        if (oa < OOM_DISABLE || oa > OOM_ADJUST_MAX) {
-                log_error("[%s:%u] OOM adjust value out of range: %s", filename, line, rvalue);
-                return -ERANGE;
+        if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
+                log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
-        c->oom_adjust = oa;
-        c->oom_adjust_set = true;
+        c->oom_score_adjust = oa;
+        c->oom_score_adjust_set = true;
 
         return 0;
 }
@@ -342,13 +351,13 @@ static int config_parse_mode(
         errno = 0;
         l = strtol(rvalue, &x, 8);
         if (!x || *x || errno) {
-                log_error("[%s:%u] Failed to parse mode value: %s", filename, line, rvalue);
-                return errno ? -errno : -EINVAL;
+                log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         if (l < 0000 || l > 07777) {
-                log_error("[%s:%u] mode value out of range: %s", filename, line, rvalue);
-                return -ERANGE;
+                log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         *m = (mode_t) l;
@@ -364,73 +373,102 @@ static int config_parse_exec(
                 void *data,
                 void *userdata) {
 
-        ExecCommand **e = data, *nce = NULL;
-        char **n;
-        char *w;
+        ExecCommand **e = data, *nce;
+        char *path, **n;
         unsigned k;
-        size_t l;
-        char *state, *path = NULL;
-        bool honour_argv0, write_to_path;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
-        assert(data);
+        assert(e);
 
         /* We accept an absolute path as first argument, or
          * alternatively an absolute prefixed with @ to allow
          * overriding of argv[0]. */
 
-        honour_argv0 = rvalue[0] == '@';
+        for (;;) {
+                char *w;
+                size_t l;
+                char *state;
+                bool honour_argv0 = false, ignore = false;
 
-        if (rvalue[honour_argv0 ? 1 : 0] != '/') {
-                log_error("[%s:%u] Invalid executable path in command line: %s", filename, line, rvalue);
-                return -EINVAL;
-        }
+                path = NULL;
+                nce = NULL;
+                n = NULL;
 
-        k = 0;
-        FOREACH_WORD_QUOTED(w, l, rvalue, state)
-                k++;
+                rvalue += strspn(rvalue, WHITESPACE);
 
-        if (!(n = new(char*, k + (honour_argv0 ? 0 : 1))))
-                return -ENOMEM;
+                if (rvalue[0] == 0)
+                        break;
 
-        k = 0;
-        write_to_path = honour_argv0;
-        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                if (write_to_path) {
-                        if (!(path = strndup(w+1, l-1)))
-                                goto fail;
-                        write_to_path = false;
-                } else {
-                        if (!(n[k++] = strndup(w, l)))
-                                goto fail;
+                if (rvalue[0] == '-') {
+                        ignore = true;
+                        rvalue ++;
                 }
-        }
 
-        n[k] = NULL;
+                if (rvalue[0] == '@') {
+                        honour_argv0 = true;
+                        rvalue ++;
+                }
 
-        if (!n[0]) {
-                log_error("[%s:%u] Invalid command line: %s", filename, line, rvalue);
-                strv_free(n);
-                return -EINVAL;
-        }
+                if (*rvalue != '/') {
+                        log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue);
+                        return 0;
+                }
 
-        if (!path)
-                if (!(path = strdup(n[0])))
-                        goto fail;
+                k = 0;
+                FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+                        if (strncmp(w, ";", l) == 0)
+                                break;
+
+                        k++;
+                }
+
+                if (!(n = new(char*, k + !honour_argv0)))
+                        return -ENOMEM;
+
+                k = 0;
+                FOREACH_WORD_QUOTED(w, l, rvalue, state) {
+                        if (strncmp(w, ";", l) == 0)
+                                break;
+
+                        if (honour_argv0 && w == rvalue) {
+                                assert(!path);
+                                if (!(path = cunescape_length(w, l)))
+                                        goto fail;
+                        } else {
+                                if (!(n[k++] = cunescape_length(w, l)))
+                                        goto fail;
+                        }
+                }
+
+                n[k] = NULL;
 
-        assert(path_is_absolute(path));
+                if (!n[0]) {
+                        log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
+                        strv_free(n);
+                        return 0;
+                }
+
+                if (!path)
+                        if (!(path = strdup(n[0])))
+                                goto fail;
 
-        if (!(nce = new0(ExecCommand, 1)))
-                goto fail;
+                assert(path_is_absolute(path));
 
-        nce->argv = n;
-        nce->path = path;
+                if (!(nce = new0(ExecCommand, 1)))
+                        goto fail;
+
+                nce->argv = n;
+                nce->path = path;
+                nce->ignore = ignore;
 
-        path_kill_slashes(nce->path);
+                path_kill_slashes(nce->path);
 
-        exec_command_append_list(e, nce);
+                exec_command_append_list(e, nce);
+
+                rvalue = state;
+        }
 
         return 0;
 
@@ -461,8 +499,8 @@ static int config_parse_usec(
         assert(data);
 
         if ((r = parse_usec(rvalue, usec)) < 0) {
-                log_error("[%s:%u] Failed to parse time value: %s", filename, line, rvalue);
-                return r;
+                log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         return 0;
@@ -521,8 +559,8 @@ static int config_parse_facility(
         assert(data);
 
         if ((x = log_facility_from_string(rvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse log facility: %s", filename, line, rvalue);
-                return -EBADMSG;
+                log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         *o = LOG_MAKEPRI(x, LOG_PRI(*o));
@@ -548,8 +586,8 @@ static int config_parse_level(
         assert(data);
 
         if ((x = log_level_from_string(rvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse log level: %s", filename, line, rvalue);
-                return -EBADMSG;
+                log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         *o = LOG_MAKEPRI(LOG_FAC(*o), x);
@@ -574,8 +612,8 @@ static int config_parse_io_class(
         assert(data);
 
         if ((x = ioprio_class_from_string(rvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse IO scheduling class: %s", filename, line, rvalue);
-                return -EBADMSG;
+                log_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
@@ -602,8 +640,8 @@ static int config_parse_io_priority(
         assert(data);
 
         if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
-                log_error("[%s:%u] Failed to parse io priority: %s", filename, line, rvalue);
-                return -EBADMSG;
+                log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
@@ -631,8 +669,8 @@ static int config_parse_cpu_sched_policy(
         assert(data);
 
         if ((x = sched_policy_from_string(rvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse CPU scheduling policy: %s", filename, line, rvalue);
-                return -EBADMSG;
+                log_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         c->cpu_sched_policy = x;
@@ -660,8 +698,8 @@ static int config_parse_cpu_sched_prio(
 
         /* On Linux RR/FIFO have the same range */
         if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
-                log_error("[%s:%u] Failed to parse CPU scheduling priority: %s", filename, line, rvalue);
-                return -EBADMSG;
+                log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         c->cpu_sched_priority = i;
@@ -689,7 +727,7 @@ static int config_parse_cpu_affinity(
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 char *t;
                 int r;
                 unsigned cpu;
@@ -705,8 +743,8 @@ static int config_parse_cpu_affinity(
                                 return -ENOMEM;
 
                 if (r < 0 || cpu >= c->cpuset_ncpus) {
-                        log_error("[%s:%u] Failed to parse CPU affinity: %s", filename, line, rvalue);
-                        return -EBADMSG;
+                        log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
+                        return 0;
                 }
 
                 CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
@@ -736,8 +774,8 @@ static int config_parse_capabilities(
                 if (errno == ENOMEM)
                         return -ENOMEM;
 
-                log_error("[%s:%u] Failed to parse capabilities: %s", filename, line, rvalue);
-                return -EBADMSG;
+                log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         if (c->capabilities)
@@ -766,7 +804,7 @@ static int config_parse_secure_bits(
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 if (first_word(w, "keep-caps"))
                         c->secure_bits |= SECURE_KEEP_CAPS;
                 else if (first_word(w, "keep-caps-locked"))
@@ -780,8 +818,8 @@ static int config_parse_secure_bits(
                 else if (first_word(w, "noroot-locked"))
                         c->secure_bits |= SECURE_NOROOT_LOCKED;
                 else {
-                        log_error("[%s:%u] Failed to parse secure bits: %s", filename, line, rvalue);
-                        return -EBADMSG;
+                        log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
+                        return 0;
                 }
         }
 
@@ -807,7 +845,7 @@ static int config_parse_bounding_set(
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 char *t;
                 int r;
                 cap_value_t cap;
@@ -819,8 +857,8 @@ static int config_parse_bounding_set(
                 free(t);
 
                 if (r < 0) {
-                        log_error("[%s:%u] Failed to parse capability bounding set: %s", filename, line, rvalue);
-                        return -EBADMSG;
+                        log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
+                        return 0;
                 }
 
                 c->capability_bounding_set_drop |= 1 << cap;
@@ -848,8 +886,8 @@ static int config_parse_timer_slack_nsec(
         assert(data);
 
         if ((r = safe_atolu(rvalue, &u)) < 0) {
-                log_error("[%s:%u] Failed to parse time slack value: %s", filename, line, rvalue);
-                return r;
+                log_error("[%s:%u] Failed to parse time slack value, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         c->timer_slack_nsec = u;
@@ -876,8 +914,8 @@ static int config_parse_limit(
         assert(data);
 
         if ((r = safe_atollu(rvalue, &u)) < 0) {
-                log_error("[%s:%u] Failed to parse resource value: %s", filename, line, rvalue);
-                return r;
+                log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         if (!*rl)
@@ -902,18 +940,20 @@ static int config_parse_cgroup(
         size_t l;
         char *state;
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 char *t;
                 int r;
 
-                if (!(t = strndup(w, l)))
+                if (!(t = cunescape_length(w, l)))
                         return -ENOMEM;
 
                 r = unit_add_cgroup_from_text(u, t);
                 free(t);
 
-                if (r < 0)
-                        return r;
+                if (r < 0) {
+                        log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
+                        return 0;
+                }
         }
 
         return 0;
@@ -937,8 +977,8 @@ static int config_parse_sysv_priority(
         assert(data);
 
         if ((r = safe_atoi(rvalue, &i)) < 0 || i < 0) {
-                log_error("[%s:%u] Failed to parse SysV start priority: %s", filename, line, rvalue);
-                return r;
+                log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         *priority = (int) i;
@@ -947,6 +987,36 @@ static int config_parse_sysv_priority(
 
 static DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
 
+static int config_parse_kill_signal(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        int *sig = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(sig);
+
+        if ((r = signal_from_string(rvalue)) <= 0)
+                if (startswith(rvalue, "SIG"))
+                        r = signal_from_string(rvalue+3);
+
+        if (r <= 0) {
+                log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
+                return 0;
+        }
+
+        *sig = r;
+        return 0;
+}
+
 static int config_parse_mount_flags(
                 const char *filename,
                 unsigned line,
@@ -967,7 +1037,7 @@ static int config_parse_mount_flags(
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD(w, l, rvalue, state) {
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                 if (strncmp(w, "shared", l) == 0)
                         flags |= MS_SHARED;
                 else if (strncmp(w, "slave", l) == 0)
@@ -975,8 +1045,8 @@ static int config_parse_mount_flags(
                 else if (strncmp(w, "private", l) == 0)
                         flags |= MS_PRIVATE;
                 else {
-                        log_error("[%s:%u] Failed to parse mount flags: %s", filename, line, rvalue);
-                        return -EINVAL;
+                        log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
+                        return 0;
                 }
         }
 
@@ -1005,13 +1075,13 @@ static int config_parse_timer(
         assert(data);
 
         if ((b = timer_base_from_string(lvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse timer base: %s", filename, line, lvalue);
-                return -EINVAL;
+                log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
+                return 0;
         }
 
         if ((r = parse_usec(rvalue, &u)) < 0) {
-                log_error("[%s:%u] Failed to parse timer value: %s", filename, line, rvalue);
-                return r;
+                log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         if (!(v = new0(TimerValue, 1)))
@@ -1036,15 +1106,24 @@ static int config_parse_timer_unit(
 
         Timer *t = data;
         int r;
+        DBusError error;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        dbus_error_init(&error);
 
         if (endswith(rvalue, ".timer")) {
-                log_error("[%s:%u] Unit cannot be of type timer: %s", filename, line, rvalue);
-                return -EINVAL;
+                log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
-        if ((r = manager_load_unit(t->meta.manager, rvalue, NULL, &t->unit)) < 0) {
-                log_error("[%s:%u] Failed to load unit: %s", filename, line, rvalue);
-                return r;
+        if ((r = manager_load_unit(t->meta.manager, rvalue, NULL, NULL, &t->unit)) < 0) {
+                log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
+                dbus_error_free(&error);
+                return 0;
         }
 
         return 0;
@@ -1069,13 +1148,13 @@ static int config_parse_path_spec(
         assert(data);
 
         if ((b = path_type_from_string(lvalue)) < 0) {
-                log_error("[%s:%u] Failed to parse path type: %s", filename, line, lvalue);
-                return -EINVAL;
+                log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
+                return 0;
         }
 
         if (!path_is_absolute(rvalue)) {
-                log_error("[%s:%u] Path is not absolute: %s", filename, line, rvalue);
-                return -EINVAL;
+                log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
         if (!(s = new0(PathSpec, 1)))
@@ -1107,15 +1186,24 @@ static int config_parse_path_unit(
 
         Path *t = data;
         int r;
+        DBusError error;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        dbus_error_init(&error);
 
         if (endswith(rvalue, ".path")) {
-                log_error("[%s:%u] Unit cannot be of type path: %s", filename, line, rvalue);
-                return -EINVAL;
+                log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
+                return 0;
         }
 
-        if ((r = manager_load_unit(t->meta.manager, rvalue, NULL, &t->unit)) < 0) {
-                log_error("[%s:%u] Failed to load unit: %s", filename, line, rvalue);
-                return r;
+        if ((r = manager_load_unit(t->meta.manager, rvalue, NULL, &error, &t->unit)) < 0) {
+                log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
+                dbus_error_free(&error);
+                return 0;
         }
 
         return 0;
@@ -1140,8 +1228,8 @@ static int config_parse_env_file(
         assert(data);
 
         if (!(f = fopen(rvalue, "re"))) {
-                log_error("[%s:%u] Failed to open environment file '%s': %m", filename, line, rvalue);
-                return -errno;
+                log_error("[%s:%u] Failed to open environment file '%s', ignoring: %m", filename, line, rvalue);
+                return 0;
         }
 
         while (!feof(f)) {
@@ -1153,7 +1241,8 @@ static int config_parse_env_file(
                                 break;
 
                         r = -errno;
-                        log_error("[%s:%u] Failed to read environment file '%s': %m", filename, line, rvalue);
+                        log_error("[%s:%u] Failed to read environment file '%s', ignoring: %m", filename, line, rvalue);
+                        r = 0;
                         goto finish;
                 }
 
@@ -1198,8 +1287,8 @@ static int config_parse_ip_tos(
 
         if ((x = ip_tos_from_string(rvalue)) < 0)
                 if ((r = safe_atoi(rvalue, &x)) < 0) {
-                        log_error("[%s:%u] Failed to parse IP TOS value: %s", filename, line, rvalue);
-                        return r;
+                        log_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
+                        return 0;
                 }
 
         *ip_tos = x;
@@ -1233,16 +1322,20 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
                 path_kill_slashes(*filename);
 
                 /* Add the file name we are currently looking at to
-                 * the names of this unit */
+                 * the names of this unit, but only if it is a valid
+                 * unit name. */
                 name = file_name_from_path(*filename);
-                if (!(id = set_get(names, name))) {
 
-                        if (!(id = strdup(name)))
-                                return -ENOMEM;
+                if (unit_name_is_valid(name)) {
+                        if (!(id = set_get(names, name))) {
 
-                        if ((r = set_put(names, id)) < 0) {
-                                free(id);
-                                return r;
+                                if (!(id = strdup(name)))
+                                        return -ENOMEM;
+
+                                if ((r = set_put(names, id)) < 0) {
+                                        free(id);
+                                        return r;
+                                }
                         }
                 }
 
@@ -1261,7 +1354,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
                 *filename = target;
         }
 
-        if (!(f = fdopen(fd, "r"))) {
+        if (!(f = fdopen(fd, "re"))) {
                 r = -errno;
                 close_nointr_nofail(fd);
                 return r;
@@ -1330,7 +1423,7 @@ static void dump_items(FILE *f, const ConfigItem *items) {
                 { config_parse_path,             "PATH" },
                 { config_parse_strv,             "STRING [...]" },
                 { config_parse_nice,             "NICE" },
-                { config_parse_oom_adjust,       "OOMADJUST" },
+                { config_parse_oom_score_adjust, "OOMSCOREADJUST" },
                 { config_parse_io_class,         "IOCLASS" },
                 { config_parse_io_priority,      "IOPRIORITY" },
                 { config_parse_cpu_sched_policy, "CPUSCHEDPOLICY" },
@@ -1355,6 +1448,7 @@ static void dump_items(FILE *f, const ConfigItem *items) {
                 { config_parse_service_restart,  "SERVICERESTART" },
                 { config_parse_sysv_priority,    "SYSVPRIORITY" },
                 { config_parse_kill_mode,        "KILLMODE" },
+                { config_parse_kill_signal,      "SIGNAL" },
                 { config_parse_listen,           "SOCKET [...]" },
                 { config_parse_socket_bind,      "SOCKETBIND" },
                 { config_parse_bindtodevice,     "NETWORKINTERFACE" },
@@ -1419,7 +1513,7 @@ static int load_from_path(Unit *u, const char *path) {
                 { "Group",                  config_parse_string_printf,   &(context).group,                                section   }, \
                 { "SupplementaryGroups",    config_parse_strv,            &(context).supplementary_groups,                 section   }, \
                 { "Nice",                   config_parse_nice,            &(context),                                      section   }, \
-                { "OOMAdjust",              config_parse_oom_adjust,      &(context),                                      section   }, \
+                { "OOMScoreAdjust",         config_parse_oom_score_adjust,&(context),                                      section   }, \
                 { "IOSchedulingClass",      config_parse_io_class,        &(context),                                      section   }, \
                 { "IOSchedulingPriority",   config_parse_io_priority,     &(context),                                      section   }, \
                 { "CPUSchedulingPolicy",    config_parse_cpu_sched_policy,&(context),                                      section   }, \
@@ -1464,7 +1558,9 @@ static int load_from_path(Unit *u, const char *path) {
                 { "PrivateTmp",             config_parse_bool,            &(context).private_tmp,                          section   }, \
                 { "MountFlags",             config_parse_mount_flags,     &(context),                                      section   }, \
                 { "TCPWrapName",            config_parse_string_printf,   &(context).tcpwrap_name,                         section   }, \
-                { "PAMName",                config_parse_string_printf,   &(context).pam_name,                             section   }
+                { "PAMName",                config_parse_string_printf,   &(context).pam_name,                             section   }, \
+                { "KillMode",               config_parse_kill_mode,       &(context).kill_mode,                            section   }, \
+                { "KillSignal",             config_parse_kill_signal,     &(context).kill_signal,                          section   }
 
         const ConfigItem items[] = {
                 { "Names",                  config_parse_names,           u,                                               "Unit"    },
@@ -1477,10 +1573,15 @@ static int load_from_path(Unit *u, const char *path) {
                 { "Conflicts",              config_parse_deps,            UINT_TO_PTR(UNIT_CONFLICTS),                     "Unit"    },
                 { "Before",                 config_parse_deps,            UINT_TO_PTR(UNIT_BEFORE),                        "Unit"    },
                 { "After",                  config_parse_deps,            UINT_TO_PTR(UNIT_AFTER),                         "Unit"    },
+                { "OnFailure",              config_parse_deps,            UINT_TO_PTR(UNIT_ON_FAILURE),                    "Unit"    },
                 { "RecursiveStop",          config_parse_bool,            &u->meta.recursive_stop,                         "Unit"    },
                 { "StopWhenUnneeded",       config_parse_bool,            &u->meta.stop_when_unneeded,                     "Unit"    },
-                { "OnlyByDependency",       config_parse_bool,            &u->meta.only_by_dependency,                     "Unit"    },
+                { "RefuseManualStart",      config_parse_bool,            &u->meta.refuse_manual_start,                    "Unit"    },
+                { "RefuseManualStop",       config_parse_bool,            &u->meta.refuse_manual_stop,                     "Unit"    },
+                { "AllowIsolate",           config_parse_bool,            &u->meta.allow_isolate,                          "Unit"    },
                 { "DefaultDependencies",    config_parse_bool,            &u->meta.default_dependencies,                   "Unit"    },
+                { "IgnoreDependencyFailure",config_parse_bool,            &u->meta.ignore_dependency_failure,              "Unit"    },
+                { "JobTimeoutSec",          config_parse_usec,            &u->meta.job_timeout,                            "Unit"    },
 
                 { "PIDFile",                config_parse_path,            &u->service.pid_file,                            "Service" },
                 { "ExecStartPre",           config_parse_exec,            u->service.exec_command+SERVICE_EXEC_START_PRE,  "Service" },
@@ -1495,9 +1596,8 @@ static int load_from_path(Unit *u, const char *path) {
                 { "Restart",                config_parse_service_restart, &u->service.restart,                             "Service" },
                 { "PermissionsStartOnly",   config_parse_bool,            &u->service.permissions_start_only,              "Service" },
                 { "RootDirectoryStartOnly", config_parse_bool,            &u->service.root_directory_start_only,           "Service" },
-                { "ValidNoProcess",         config_parse_bool,            &u->service.valid_no_process,                    "Service" },
+                { "RemainAfterExit",        config_parse_bool,            &u->service.remain_after_exit,                   "Service" },
                 { "SysVStartPriority",      config_parse_sysv_priority,   &u->service.sysv_start_priority,                 "Service" },
-                { "KillMode",               config_parse_kill_mode,       &u->service.kill_mode,                           "Service" },
                 { "NonBlocking",            config_parse_bool,            &u->service.exec_context.non_blocking,           "Service" },
                 { "BusName",                config_parse_string_printf,   &u->service.bus_name,                            "Service" },
                 { "NotifyAccess",           config_parse_notify_access,   &u->service.notify_access,                       "Service" },
@@ -1517,7 +1617,6 @@ static int load_from_path(Unit *u, const char *path) {
                 { "TimeoutSec",             config_parse_usec,            &u->socket.timeout_usec,                         "Socket"  },
                 { "DirectoryMode",          config_parse_mode,            &u->socket.directory_mode,                       "Socket"  },
                 { "SocketMode",             config_parse_mode,            &u->socket.socket_mode,                          "Socket"  },
-                { "KillMode",               config_parse_kill_mode,       &u->socket.kill_mode,                            "Socket"  },
                 { "Accept",                 config_parse_bool,            &u->socket.accept,                               "Socket"  },
                 { "MaxConnections",         config_parse_unsigned,        &u->socket.max_connections,                      "Socket"  },
                 { "KeepAlive",              config_parse_bool,            &u->socket.keep_alive,                           "Socket"  },
@@ -1529,6 +1628,7 @@ static int load_from_path(Unit *u, const char *path) {
                 { "Mark",                   config_parse_int,             &u->socket.mark,                                 "Socket"  },
                 { "PipeSize",               config_parse_size,            &u->socket.pipe_size,                            "Socket"  },
                 { "FreeBind",               config_parse_bool,            &u->socket.free_bind,                            "Socket"  },
+                { "TCPCongestion",          config_parse_string,          &u->socket.tcp_congestion,                       "Socket"  },
                 EXEC_CONTEXT_CONFIG_ITEMS(u->socket.exec_context, "Socket"),
 
                 { "What",                   config_parse_string,          &u->mount.parameters_fragment.what,              "Mount"   },
@@ -1536,7 +1636,6 @@ static int load_from_path(Unit *u, const char *path) {
                 { "Options",                config_parse_string,          &u->mount.parameters_fragment.options,           "Mount"   },
                 { "Type",                   config_parse_string,          &u->mount.parameters_fragment.fstype,            "Mount"   },
                 { "TimeoutSec",             config_parse_usec,            &u->mount.timeout_usec,                          "Mount"   },
-                { "KillMode",               config_parse_kill_mode,       &u->mount.kill_mode,                             "Mount"   },
                 { "DirectoryMode",          config_parse_mode,            &u->mount.directory_mode,                        "Mount"   },
                 EXEC_CONTEXT_CONFIG_ITEMS(u->mount.exec_context, "Mount"),
 
@@ -1574,6 +1673,7 @@ static int load_from_path(Unit *u, const char *path) {
         FILE *f = NULL;
         char *filename = NULL, *id = NULL;
         Unit *merged;
+        struct stat st;
 
         if (!u) {
                 /* Dirty dirty hack. */
@@ -1620,7 +1720,13 @@ static int load_from_path(Unit *u, const char *path) {
                                 goto finish;
                         }
 
-                        if ((r = open_follow(&filename, &f, symlink_names, &id)) < 0) {
+                        if (u->meta.manager->unit_path_cache &&
+                            !set_get(u->meta.manager->unit_path_cache, filename))
+                                r = -ENOENT;
+                        else
+                                r = open_follow(&filename, &f, symlink_names, &id);
+
+                        if (r < 0) {
                                 char *sn;
 
                                 free(filename);
@@ -1641,6 +1747,7 @@ static int load_from_path(Unit *u, const char *path) {
         }
 
         if (!filename) {
+                /* Hmm, no suitable file found? */
                 r = 0;
                 goto finish;
         }
@@ -1655,6 +1762,12 @@ static int load_from_path(Unit *u, const char *path) {
                 goto finish;
         }
 
+        zero(st);
+        if (fstat(fileno(f), &st) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
         /* Now, parse the file contents */
         if ((r = config_parse(filename, f, sections, items, false, u)) < 0)
                 goto finish;
@@ -1663,6 +1776,8 @@ static int load_from_path(Unit *u, const char *path) {
         u->meta.fragment_path = filename;
         filename = NULL;
 
+        u->meta.fragment_mtime = timespec_load(&st.st_mtim);
+
         u->meta.load_state = UNIT_LOADED;
         r = 0;
 
@@ -1678,68 +1793,69 @@ finish:
 
 int unit_load_fragment(Unit *u) {
         int r;
+        Iterator i;
+        const char *t;
 
         assert(u);
+        assert(u->meta.load_state == UNIT_STUB);
+        assert(u->meta.id);
+
+        /* First, try to find the unit under its id. We always look
+         * for unit files in the default directories, to make it easy
+         * to override things by placing things in /etc/systemd/system */
+        if ((r = load_from_path(u, u->meta.id)) < 0)
+                return r;
 
-        if (u->meta.fragment_path) {
+        /* Try to find an alias we can load this with */
+        if (u->meta.load_state == UNIT_STUB)
+                SET_FOREACH(t, u->meta.names, i) {
 
+                        if (t == u->meta.id)
+                                continue;
+
+                        if ((r = load_from_path(u, t)) < 0)
+                                return r;
+
+                        if (u->meta.load_state != UNIT_STUB)
+                                break;
+                }
+
+        /* And now, try looking for it under the suggested (originally linked) path */
+        if (u->meta.load_state == UNIT_STUB && u->meta.fragment_path)
                 if ((r = load_from_path(u, u->meta.fragment_path)) < 0)
                         return r;
 
-        } else {
-                Iterator i;
-                const char *t;
+        /* Look for a template */
+        if (u->meta.load_state == UNIT_STUB && u->meta.instance) {
+                char *k;
 
-                /* Try to find the unit under its id */
-                if ((r = load_from_path(u, u->meta.id)) < 0)
+                if (!(k = unit_name_template(u->meta.id)))
+                        return -ENOMEM;
+
+                r = load_from_path(u, k);
+                free(k);
+
+                if (r < 0)
                         return r;
 
-                /* Try to find an alias we can load this with */
                 if (u->meta.load_state == UNIT_STUB)
                         SET_FOREACH(t, u->meta.names, i) {
 
                                 if (t == u->meta.id)
                                         continue;
 
-                                if ((r = load_from_path(u, t)) < 0)
+                                if (!(k = unit_name_template(t)))
+                                        return -ENOMEM;
+
+                                r = load_from_path(u, k);
+                                free(k);
+
+                                if (r < 0)
                                         return r;
 
                                 if (u->meta.load_state != UNIT_STUB)
                                         break;
                         }
-
-                /* Now, follow the same logic, but look for a template */
-                if (u->meta.load_state == UNIT_STUB && u->meta.instance) {
-                        char *k;
-
-                        if (!(k = unit_name_template(u->meta.id)))
-                                return -ENOMEM;
-
-                        r = load_from_path(u, k);
-                        free(k);
-
-                        if (r < 0)
-                                return r;
-
-                        if (u->meta.load_state == UNIT_STUB)
-                                SET_FOREACH(t, u->meta.names, i) {
-
-                                        if (t == u->meta.id)
-                                                continue;
-
-                                        if (!(k = unit_name_template(t)))
-                                                return -ENOMEM;
-
-                                        r = load_from_path(u, k);
-                                        free(k);
-
-                                        if (r < 0)
-                                                return r;
-
-                                        if (u->meta.load_state != UNIT_STUB)
-                                                break;
-                                }
-                }
         }
 
         return 0;