[systemd-commits] 8 commits - TODO man/machinectl.xml man/systemd-nspawn.xml src/core src/cryptsetup src/dbus1-generator src/debug-generator src/escape src/fstab-generator src/getty-generator src/gpt-auto-generator src/hibernate-resume src/journal src/login src/machine src/run src/shared src/systemctl src/sysv-generator src/test

Lennart Poettering lennart at kemper.freedesktop.org
Tue May 5 15:20:06 PDT 2015


 TODO                                              |    6 
 man/machinectl.xml                                |    8 
 man/systemd-nspawn.xml                            |   18 
 src/core/automount.c                              |   19 
 src/core/busname.c                                |    9 
 src/core/dbus-unit.c                              |    4 
 src/core/device.c                                 |   19 
 src/core/load-fragment.c                          |   16 
 src/core/manager.c                                |   17 
 src/core/mount.c                                  |   23 
 src/core/slice.c                                  |   27 
 src/core/snapshot.c                               |    4 
 src/core/socket.c                                 |   23 
 src/core/swap.c                                   |   39 -
 src/core/unit-printf.c                            |   55 -
 src/core/unit.c                                   |  160 ++---
 src/cryptsetup/cryptsetup-generator.c             |   20 
 src/dbus1-generator/dbus1-generator.c             |    2 
 src/debug-generator/debug-generator.c             |   12 
 src/escape/escape.c                               |   40 -
 src/fstab-generator/fstab-generator.c             |   18 
 src/getty-generator/getty-generator.c             |   22 
 src/gpt-auto-generator/gpt-auto-generator.c       |   25 
 src/hibernate-resume/hibernate-resume-generator.c |    8 
 src/journal/journalctl.c                          |   17 
 src/login/logind-user.c                           |    8 
 src/machine/machinectl.c                          |   55 -
 src/run/run.c                                     |   44 -
 src/shared/cgroup-util.c                          |   23 
 src/shared/dropin.c                               |   15 
 src/shared/generator.c                            |   18 
 src/shared/install-printf.c                       |   16 
 src/shared/install.c                              |   59 -
 src/shared/unit-name.c                            |  675 ++++++++++++++--------
 src/shared/unit-name.h                            |   80 +-
 src/shared/util.c                                 |    2 
 src/systemctl/systemctl.c                         |  100 +--
 src/sysv-generator/sysv-generator.c               |    8 
 src/test/test-cgroup-util.c                       |    2 
 src/test/test-unit-name.c                         |  354 +++++++----
 40 files changed, 1215 insertions(+), 855 deletions(-)

New commits:
commit d89e647542a6ceeefac15fbe8e193de7418bf449
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue May 5 13:48:57 2015 -0700

    update TODO

diff --git a/TODO b/TODO
index 0a88cb1..430a354 100644
--- a/TODO
+++ b/TODO
@@ -49,10 +49,14 @@ Before 220:
 
 * introduce argv0array=
 
-* be stricter when validating slice names
+* rework log_unit_error() to always prefix output with unit name
 
 Features:
 
+* networkd: dhcp server: try to assign stable IP addresses based on client's MAC address
+
+* nspawn: a nice way to boot up without machine id set, so that it is set at boot automatically for supporting --ephemeral. Maybe hash the host machine id together with the machine name to generate the machine id for the container
+
 * logind: rename session scope so that it includes the UID. THat way
   the session scope can be arranged freely in slices and we don't have
   make assumptions about their slice anymore.

commit 3fe22bb4b6b5faf27683ad2e231b5a69b6e63a9e
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue May 5 13:48:28 2015 -0700

    man: document that nspawn -x, --template= and machinectl clone leave hostname and machine id unmodified

diff --git a/man/machinectl.xml b/man/machinectl.xml
index 59a6e14..50cbb1b 100644
--- a/man/machinectl.xml
+++ b/man/machinectl.xml
@@ -487,7 +487,13 @@
         images are cloned into subvolume images with this command.
         Note that cloning a container or VM image is optimized for
         btrfs file systems, and might not be efficient on others, due
-        to file system limitations.</para></listitem>
+        to file system limitations.</para>
+
+        <para>Note that this command leaves host name, machine ID and
+        all other settings that could identify the instance
+        unmodified. The original image and the cloned copy will hence
+        share these credentials, and it might be necessary to manually
+        change them in the copy.</para></listitem>
       </varlistentry>
 
       <varlistentry>
diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
index cb96661..fec51df 100644
--- a/man/systemd-nspawn.xml
+++ b/man/systemd-nspawn.xml
@@ -187,7 +187,11 @@
         system, so that the <literal>btrfs</literal> subvolume may be
         created. May not be specified together with
         <option>--image=</option> or
-        <option>--ephemeral</option>.</para></listitem>
+        <option>--ephemeral</option>.</para>
+
+        <para>Note that this switch leaves host name, machine ID and
+        all other settings that could identify the instance
+        unmodified.</para></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -201,7 +205,10 @@
         This option is only supported if the root file system is
         <literal>btrfs</literal>. May not be specified together with
         <option>--image=</option> or
-        <option>--template=</option>.</para></listitem>
+        <option>--template=</option>.</para>
+        <para>Note that this switch leaves host name, machine ID and
+        all other settings that could identify the instance
+        unmodified.</para></listitem>
       </varlistentry>
 
       <varlistentry>

commit 7de7ee62c5628a3c9e116f14aca63a35d06f5331
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue May 5 13:41:31 2015 -0700

    man: nspawn is used in production these days, admit that
    
    Previously, the man page suggested to only use nspawn for testing,
    building, and debugging things. However, it is nowadays used in
    production and used as building block for rocket, hence let's just admit
    that it's pretty much production ready.

diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
index cae067b..cb96661 100644
--- a/man/systemd-nspawn.xml
+++ b/man/systemd-nspawn.xml
@@ -84,13 +84,10 @@
     kernel modules may not be loaded from within the container.</para>
 
     <para>Note that even though these security precautions are taken
-    <command>systemd-nspawn</command> is not suitable for secure
+    <command>systemd-nspawn</command> is not suitable for fully secure
     container setups. Many of the security features may be
     circumvented and are hence primarily useful to avoid accidental
-    changes to the host system from the container. The intended use of
-    this program is debugging and testing as well as building of
-    packages, distributions and software involved with boot and
-    systems management.</para>
+    changes to the host system from the container.</para>
 
     <para>In contrast to
     <citerefentry project='man-pages'><refentrytitle>chroot</refentrytitle><manvolnum>1</manvolnum></citerefentry> <command>systemd-nspawn</command>

commit 93c474725c0fb2530f093c106de0bce956544d29
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue May 5 13:39:14 2015 -0700

    core: be more strict when manipulating slices names and unescaping paths from unit names
    
    Let's better be safe then sorry.

diff --git a/src/core/slice.c b/src/core/slice.c
index 0bebdbc..b965850 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -93,27 +93,28 @@ static int slice_add_default_dependencies(Slice *s) {
         return 0;
 }
 
+
 static int slice_verify(Slice *s) {
+        _cleanup_free_ char *parent = NULL;
+        int r;
+
         assert(s);
 
         if (UNIT(s)->load_state != UNIT_LOADED)
                 return 0;
 
-        if (UNIT_DEREF(UNIT(s)->slice)) {
-                char *a, *dash;
+        if (!slice_name_is_valid(UNIT(s)->id)) {
+                log_unit_error(UNIT(s)->id, "Slice name %s is not valid. Refusing.", UNIT(s)->id);
+                return -EINVAL;
+        }
 
-                a = strdupa(UNIT(s)->id);
-                dash = strrchr(a, '-');
-                if (dash)
-                        strcpy(dash, ".slice");
-                else
-                        a = (char*) SPECIAL_ROOT_SLICE;
+        r = slice_build_parent_slice(UNIT(s)->id, &parent);
+        if (r < 0)
+                return log_unit_error_errno(UNIT(s)->id, r, "Failed to determine parent slice: %m");
 
-                if (!unit_has_name(UNIT_DEREF(UNIT(s)->slice), a)) {
-                        log_unit_error(UNIT(s)->id,
-                                       "%s located outside its parent slice. Refusing.", UNIT(s)->id);
-                        return -EINVAL;
-                }
+        if (parent ? !unit_has_name(UNIT_DEREF(UNIT(s)->slice), parent) : UNIT_ISSET(UNIT(s)->slice)) {
+                log_unit_error(UNIT(s)->id, "%s located outside its parent slice. Refusing.", UNIT(s)->id);
+                return -EINVAL;
         }
 
         return 0;
diff --git a/src/shared/unit-name.c b/src/shared/unit-name.c
index c41d7d8..b23e47a 100644
--- a/src/shared/unit-name.c
+++ b/src/shared/unit-name.c
@@ -339,7 +339,7 @@ int unit_name_unescape(const char *f, char **ret) {
                         if (b < 0)
                                 return -EINVAL;
 
-                        *(t++) = (char) ((a << 4) | b);
+                        *(t++) = (char) (((uint8_t) a << 4U) | (uint8_t) b);
                         f += 3;
                 } else
                         *(t++) = *f;
@@ -392,42 +392,48 @@ int unit_name_path_escape(const char *f, char **ret) {
 }
 
 int unit_name_path_unescape(const char *f, char **ret) {
-        char *s, *w;
+        char *s;
         int r;
 
         assert(f);
 
+        if (isempty(f))
+                return -EINVAL;
+
         if (streq(f, "-")) {
                 s = strdup("/");
                 if (!s)
                         return -ENOMEM;
+        } else {
+                char *w;
 
-                *ret = s;
-                return 0;
-        }
-
-        r = unit_name_unescape(f, &s);
-        if (r < 0)
-                return r;
-
-        /* Don't accept trailing or leading slashes */
-        if (startswith(s, "/") || endswith(s, "/")) {
-                free(s);
-                return -EINVAL;
-        }
+                r = unit_name_unescape(f, &w);
+                if (r < 0)
+                        return r;
 
-        /* Prefix a slash again */
-        w = strappend("/", s);
-        free(s);
-        if (!w)
-                return -ENOMEM;
+                /* Don't accept trailing or leading slashes */
+                if (startswith(w, "/") || endswith(w, "/")) {
+                        free(w);
+                        return -EINVAL;
+                }
 
-        if (!path_is_safe(w)) {
+                /* Prefix a slash again */
+                s = strappend("/", w);
                 free(w);
-                return -EINVAL;
+                if (!s)
+                        return -ENOMEM;
+
+                if (!path_is_safe(s)) {
+                        free(s);
+                        return -EINVAL;
+                }
         }
 
-        *ret = w;
+        if (ret)
+                *ret = s;
+        else
+                free(s);
+
         return 0;
 }
 
@@ -665,6 +671,39 @@ int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, c
         return 1;
 }
 
+int slice_build_parent_slice(const char *slice, char **ret) {
+        char *s, *dash;
+
+        assert(slice);
+        assert(ret);
+
+        if (!slice_name_is_valid(slice))
+                return -EINVAL;
+
+        if (streq(slice, "-.slice")) {
+                *ret = NULL;
+                return 0;
+        }
+
+        s = strdup(slice);
+        if (!s)
+                return -ENOMEM;
+
+        dash = strrchr(s, '-');
+        if (dash)
+                strcpy(dash, ".slice");
+        else {
+                free(s);
+
+                s = strdup("-.slice");
+                if (!s)
+                        return -ENOMEM;
+        }
+
+        *ret = s;
+        return 1;
+}
+
 int slice_build_subslice(const char *slice, const char*name, char **ret) {
         char *subslice;
 
@@ -672,7 +711,7 @@ int slice_build_subslice(const char *slice, const char*name, char **ret) {
         assert(name);
         assert(ret);
 
-        if (!unit_name_is_valid(slice, UNIT_NAME_PLAIN))
+        if (!slice_name_is_valid(slice))
                 return -EINVAL;
 
         if (!unit_prefix_is_valid(name))
@@ -683,9 +722,7 @@ int slice_build_subslice(const char *slice, const char*name, char **ret) {
         else {
                 char *e;
 
-                e = endswith(slice, ".slice");
-                if (!e)
-                        return -EINVAL;
+                assert_se(e = endswith(slice, ".slice"));
 
                 subslice = new(char, (e - slice) + 1 + strlen(name) + 6 + 1);
                 if (!subslice)
@@ -698,6 +735,44 @@ int slice_build_subslice(const char *slice, const char*name, char **ret) {
         return 0;
 }
 
+bool slice_name_is_valid(const char *name) {
+        const char *p, *e;
+        bool dash = false;
+
+        if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
+                return false;
+
+        if (streq(name, "-.slice"))
+                return true;
+
+        e = endswith(name, ".slice");
+        if (!e)
+                return false;
+
+        for (p = name; p < e; p++) {
+
+                if (*p == '-') {
+
+                        /* Don't allow initial dash */
+                        if (p == name)
+                                return false;
+
+                        /* Don't allow multiple dashes */
+                        if (dash)
+                                return false;
+
+                        dash = true;
+                } else
+                        dash = false;
+        }
+
+        /* Don't allow trailing hash */
+        if (dash)
+                return false;
+
+        return true;
+}
+
 static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
         [UNIT_SERVICE] = "service",
         [UNIT_SOCKET] = "socket",
diff --git a/src/shared/unit-name.h b/src/shared/unit-name.h
index 057512c..c2f31e3 100644
--- a/src/shared/unit-name.h
+++ b/src/shared/unit-name.h
@@ -161,7 +161,9 @@ static inline int unit_name_mangle(const char *name, UnitNameMangle allow_globs,
         return unit_name_mangle_with_suffix(name, allow_globs, ".service", ret);
 }
 
+int slice_build_parent_slice(const char *slice, char **ret);
 int slice_build_subslice(const char *slice, const char*name, char **subslice);
+bool slice_name_is_valid(const char *name);
 
 const char *unit_type_to_string(UnitType i) _const_;
 UnitType unit_type_from_string(const char *s) _pure_;
diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c
index 5e34f18..de8f7dd 100644
--- a/src/test/test-unit-name.c
+++ b/src/test/test-unit-name.c
@@ -328,6 +328,21 @@ static void test_unit_name_build(void) {
         free(t);
 }
 
+static void test_slice_name_is_valid(void) {
+        assert_se(slice_name_is_valid("-.slice"));
+        assert_se(slice_name_is_valid("foo.slice"));
+        assert_se(slice_name_is_valid("foo-bar.slice"));
+        assert_se(slice_name_is_valid("foo-bar-baz.slice"));
+        assert_se(!slice_name_is_valid("-foo-bar-baz.slice"));
+        assert_se(!slice_name_is_valid("foo-bar-baz-.slice"));
+        assert_se(!slice_name_is_valid("-foo-bar-baz-.slice"));
+        assert_se(!slice_name_is_valid("foo-bar--baz.slice"));
+        assert_se(!slice_name_is_valid("foo--bar--baz.slice"));
+        assert_se(!slice_name_is_valid(".slice"));
+        assert_se(!slice_name_is_valid(""));
+        assert_se(!slice_name_is_valid("foo.service"));
+}
+
 static void test_build_subslice(void) {
         char *a;
         char *b;
@@ -346,6 +361,25 @@ static void test_build_subslice(void) {
         assert_se(slice_build_subslice("foo", "bar", &a) < 0);
 }
 
+static void test_build_parent_slice_one(const char *name, const char *expect, int ret) {
+        _cleanup_free_ char *s = NULL;
+
+        assert_se(slice_build_parent_slice(name, &s) == ret);
+        assert_se(streq_ptr(s, expect));
+}
+
+static void test_build_parent_slice(void) {
+        test_build_parent_slice_one("-.slice", NULL, 0);
+        test_build_parent_slice_one("foo.slice", "-.slice", 1);
+        test_build_parent_slice_one("foo-bar.slice", "foo.slice", 1);
+        test_build_parent_slice_one("foo-bar-baz.slice", "foo-bar.slice", 1);
+        test_build_parent_slice_one("foo-bar--baz.slice", NULL, -EINVAL);
+        test_build_parent_slice_one("-foo-bar.slice", NULL, -EINVAL);
+        test_build_parent_slice_one("foo-bar-.slice", NULL, -EINVAL);
+        test_build_parent_slice_one("foo-bar.service", NULL, -EINVAL);
+        test_build_parent_slice_one(".slice", NULL, -EINVAL);
+}
+
 static void test_unit_name_to_instance(void) {
         char *instance;
         int r;
@@ -398,6 +432,29 @@ static void test_unit_name_template(void) {
         test_u_n_t_one("foo.mount", NULL, -EINVAL);
 }
 
+static void test_unit_name_path_unescape_one(const char *name, const char *path, int ret) {
+        _cleanup_free_ char *p = NULL;
+
+        assert_se(unit_name_path_unescape(name, &p) == ret);
+        assert_se(streq_ptr(path, p));
+}
+
+static void test_unit_name_path_unescape(void) {
+
+        test_unit_name_path_unescape_one("foo", "/foo", 0);
+        test_unit_name_path_unescape_one("foo-bar", "/foo/bar", 0);
+        test_unit_name_path_unescape_one("foo-.bar", "/foo/.bar", 0);
+        test_unit_name_path_unescape_one("foo-bar-baz", "/foo/bar/baz", 0);
+        test_unit_name_path_unescape_one("-", "/", 0);
+        test_unit_name_path_unescape_one("--", NULL, -EINVAL);
+        test_unit_name_path_unescape_one("-foo-bar", NULL, -EINVAL);
+        test_unit_name_path_unescape_one("foo--bar", NULL, -EINVAL);
+        test_unit_name_path_unescape_one("foo-bar-", NULL, -EINVAL);
+        test_unit_name_path_unescape_one(".-bar", NULL, -EINVAL);
+        test_unit_name_path_unescape_one("foo-..", NULL, -EINVAL);
+        test_unit_name_path_unescape_one("", NULL, -EINVAL);
+}
+
 int main(int argc, char* argv[]) {
         int rc = 0;
         test_unit_name_is_valid();
@@ -411,10 +468,13 @@ int main(int argc, char* argv[]) {
         test_unit_prefix_is_valid();
         test_unit_name_change_suffix();
         test_unit_name_build();
+        test_slice_name_is_valid();
         test_build_subslice();
+        test_build_parent_slice();
         test_unit_name_to_instance();
         test_unit_name_escape();
         test_unit_name_template();
+        test_unit_name_path_unescape();
 
         return rc;
 }

commit e05ad7bcc87f652cea321224f8eeb32e21d18e0c
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat May 2 17:42:55 2015 +0200

    core: bus name units should not allow aliases or instances

diff --git a/src/core/busname.c b/src/core/busname.c
index 8e92fb4..1278c96 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -1027,6 +1027,9 @@ const UnitVTable busname_vtable = {
                 "Install\0",
         .private_section = "BusName",
 
+        .no_alias = true,
+        .no_instances = true,
+
         .init = busname_init,
         .done = busname_done,
         .load = busname_load,

commit 7410616cd9dbbec97cf98d75324da5cda2b2f7a2
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Apr 30 20:21:00 2015 +0200

    core: rework unit name validation and manipulation logic
    
    A variety of changes:
    
    - Make sure all our calls distuingish OOM from other errors if OOM is
      not the only error possible.
    
    - Be much stricter when parsing escaped paths, do not accept trailing or
      leading escaped slashes.
    
    - Change unit validation to take a bit mask for allowing plain names,
      instance names or template names or an combination thereof.
    
    - Refuse manipulating invalid unit name

diff --git a/src/core/automount.c b/src/core/automount.c
index 73b75f1..1806fa3 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -167,8 +167,9 @@ static int automount_add_default_dependencies(Automount *a) {
 }
 
 static int automount_verify(Automount *a) {
-        bool b;
         _cleanup_free_ char *e = NULL;
+        int r;
+
         assert(a);
 
         if (UNIT(a)->load_state != UNIT_LOADED)
@@ -179,13 +180,11 @@ static int automount_verify(Automount *a) {
                 return -EINVAL;
         }
 
-        e = unit_name_from_path(a->where, ".automount");
-        if (!e)
-                return -ENOMEM;
-
-        b = unit_has_name(UNIT(a), e);
+        r = unit_name_from_path(a->where, ".automount", &e);
+        if (r < 0)
+                return log_unit_error(UNIT(a)->id, "Failed to generate unit name from path: %m");
 
-        if (!b) {
+        if (!unit_has_name(UNIT(a), e)) {
                 log_unit_error(UNIT(a)->id, "%s's Where setting doesn't match unit name. Refusing.", UNIT(a)->id);
                 return -EINVAL;
         }
@@ -209,9 +208,9 @@ static int automount_load(Unit *u) {
                 Unit *x;
 
                 if (!a->where) {
-                        a->where = unit_name_to_path(u->id);
-                        if (!a->where)
-                                return -ENOMEM;
+                        r = unit_name_to_path(u->id, &a->where);
+                        if (r < 0)
+                                return r;
                 }
 
                 path_kill_slashes(a->where);
diff --git a/src/core/busname.c b/src/core/busname.c
index 20d49fe..8e92fb4 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -163,9 +163,9 @@ static int busname_add_extras(BusName *n) {
         assert(n);
 
         if (!n->name) {
-                n->name = unit_name_to_prefix(u->id);
-                if (!n->name)
-                        return -ENOMEM;
+                r = unit_name_to_prefix(u->id, &n->name);
+                if (r < 0)
+                        return r;
         }
 
         if (!u->description) {
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 2699e81..056c711 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -940,7 +940,7 @@ static int bus_unit_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
+                if (!unit_name_is_valid(s, UNIT_NAME_PLAIN) || !endswith(s, ".slice"))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
 
                 if (isempty(s)) {
@@ -988,7 +988,7 @@ static int bus_unit_set_transient_property(
                         return r;
 
                 while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
-                        if (!unit_name_is_valid(other, TEMPLATE_INVALID))
+                        if (!unit_name_is_valid(other, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
 
                         if (mode != UNIT_CHECK) {
diff --git a/src/core/device.c b/src/core/device.c
index f8e65b8..2c56c5a 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -279,9 +279,9 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
                 memcpy(e, word, l);
                 e[l] = 0;
 
-                n = unit_name_mangle(e, MANGLE_NOGLOB);
-                if (!n)
-                        return log_oom();
+                r = unit_name_mangle(e, UNIT_NAME_NOGLOB, &n);
+                if (r < 0)
+                        return log_unit_error_errno(u->id, r, "Failed to mangle unit name: %m");
 
                 r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true);
                 if (r < 0)
@@ -308,9 +308,9 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
         if (!sysfs)
                 return 0;
 
-        e = unit_name_from_path(path, ".device");
-        if (!e)
-                return log_oom();
+        r = unit_name_from_path(path, ".device", &e);
+        if (r < 0)
+                return log_unit_error_errno(u->id, r, "Failed to generate device name: %m");
 
         u = manager_get_unit(m, e);
 
@@ -491,6 +491,7 @@ static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add,
 static int device_update_found_by_name(Manager *m, const char *path, bool add, DeviceFound found, bool now) {
         _cleanup_free_ char *e = NULL;
         Unit *u;
+        int r;
 
         assert(m);
         assert(path);
@@ -498,9 +499,9 @@ static int device_update_found_by_name(Manager *m, const char *path, bool add, D
         if (found == DEVICE_NOT_FOUND)
                 return 0;
 
-        e = unit_name_from_path(path, ".device");
-        if (!e)
-                return log_oom();
+        r = unit_name_from_path(path, ".device", &e);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate unit name from device path: %m");
 
         u = manager_get_unit(m, e);
         if (!u)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index b76656b..970120a 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3394,7 +3394,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
                  * unit name. */
                 name = basename(*filename);
 
-                if (unit_name_is_valid(name, TEMPLATE_VALID)) {
+                if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
 
                         id = set_get(names, name);
                         if (!id) {
@@ -3642,11 +3642,11 @@ int unit_load_fragment(Unit *u) {
 
         /* Look for a template */
         if (u->load_state == UNIT_STUB && u->instance) {
-                _cleanup_free_ char *k;
+                _cleanup_free_ char *k = NULL;
 
-                k = unit_name_template(u->id);
-                if (!k)
-                        return -ENOMEM;
+                r = unit_name_template(u->id, &k);
+                if (r < 0)
+                        return r;
 
                 r = load_from_path(u, k);
                 if (r < 0)
@@ -3659,9 +3659,9 @@ int unit_load_fragment(Unit *u) {
                                 if (t == u->id)
                                         continue;
 
-                                z = unit_name_template(t);
-                                if (!z)
-                                        return -ENOMEM;
+                                r = unit_name_template(t, &z);
+                                if (r < 0)
+                                        return r;
 
                                 r = load_from_path(u, z);
                                 if (r < 0)
diff --git a/src/core/manager.c b/src/core/manager.c
index b494521..8c8645b 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1306,7 +1306,7 @@ int manager_load_unit_prepare(
 
         t = unit_name_to_type(name);
 
-        if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, TEMPLATE_INVALID))
+        if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
                 return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
 
         ret = manager_get_unit(m, name);
@@ -2093,7 +2093,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
 #ifdef HAVE_AUDIT
         _cleanup_free_ char *p = NULL;
         const char *msg;
-        int audit_fd;
+        int audit_fd, r;
 
         audit_fd = get_audit_fd();
         if (audit_fd < 0)
@@ -2110,9 +2110,9 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
         if (u->type != UNIT_SERVICE)
                 return;
 
-        p = unit_name_to_prefix_and_instance(u->id);
-        if (!p) {
-                log_oom();
+        r = unit_name_to_prefix_and_instance(u->id, &p);
+        if (r < 0) {
+                log_error_errno(r, "Failed to extract prefix and instance of unit name: %m");
                 return;
         }
 
@@ -3027,15 +3027,16 @@ void manager_status_printf(Manager *m, StatusType type, const char *status, cons
 int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found) {
         _cleanup_free_ char *p = NULL;
         Unit *found;
+        int r;
 
         assert(m);
         assert(path);
         assert(suffix);
         assert(_found);
 
-        p = unit_name_from_path(path, suffix);
-        if (!p)
-                return -ENOMEM;
+        r = unit_name_from_path(path, suffix, &p);
+        if (r < 0)
+                return r;
 
         found = manager_get_unit(m, p);
         if (!found) {
diff --git a/src/core/mount.c b/src/core/mount.c
index d0c41a7..65a66b4 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -435,7 +435,7 @@ static int mount_add_default_dependencies(Mount *m) {
 
 static int mount_verify(Mount *m) {
         _cleanup_free_ char *e = NULL;
-        bool b;
+        int r;
 
         assert(m);
 
@@ -445,12 +445,11 @@ static int mount_verify(Mount *m) {
         if (!m->from_fragment && !m->from_proc_self_mountinfo)
                 return -ENOENT;
 
-        e = unit_name_from_path(m->where, ".mount");
-        if (!e)
-                return -ENOMEM;
+        r = unit_name_from_path(m->where, ".mount", &e);
+        if (r < 0)
+                return log_unit_error_errno(UNIT(m)->id, r, "Failed to generate unit name from mount path: %m");
 
-        b = unit_has_name(UNIT(m), e);
-        if (!b) {
+        if (!unit_has_name(UNIT(m), e)) {
                 log_unit_error(UNIT(m)->id, "%s's Where= setting doesn't match unit name. Refusing.", UNIT(m)->id);
                 return -EINVAL;
         }
@@ -483,9 +482,9 @@ static int mount_add_extras(Mount *m) {
                 m->from_fragment = true;
 
         if (!m->where) {
-                m->where = unit_name_to_path(u->id);
-                if (!m->where)
-                        return -ENOMEM;
+                r = unit_name_to_path(u->id, &m->where);
+                if (r < 0)
+                        return r;
         }
 
         path_kill_slashes(m->where);
@@ -1419,9 +1418,9 @@ static int mount_setup_unit(
         if (!is_path(where))
                 return 0;
 
-        e = unit_name_from_path(where, ".mount");
-        if (!e)
-                return -ENOMEM;
+        r = unit_name_from_path(where, ".mount", &e);
+        if (r < 0)
+                return r;
 
         u = manager_get_unit(m, e);
         if (!u) {
diff --git a/src/core/snapshot.c b/src/core/snapshot.c
index b70c3be..2c00680 100644
--- a/src/core/snapshot.c
+++ b/src/core/snapshot.c
@@ -201,10 +201,10 @@ int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e,
         assert(_s);
 
         if (name) {
-                if (!unit_name_is_valid(name, TEMPLATE_INVALID))
+                if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
                         return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
 
-                if (unit_name_to_type(name) != UNIT_SNAPSHOT)
+                if (!endswith(name, ".snapshot"))
                         return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name);
 
                 if (manager_get_unit(m, name))
diff --git a/src/core/socket.c b/src/core/socket.c
index 67beda4..55334e4 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -196,12 +196,15 @@ int socket_instantiate_service(Socket *s) {
          * here. For Accept=no this is mostly a NOP since the service
          * is figured out at load time anyway. */
 
-        if (UNIT_DEREF(s->service) || !s->accept)
+        if (UNIT_DEREF(s->service))
                 return 0;
 
-        prefix = unit_name_to_prefix(UNIT(s)->id);
-        if (!prefix)
-                return -ENOMEM;
+        if (!s->accept)
+                return 0;
+
+        r = unit_name_to_prefix(UNIT(s)->id, &prefix);
+        if (r < 0)
+                return r;
 
         if (asprintf(&name, "%s@%u.service", prefix, s->n_accepted) < 0)
                 return -ENOMEM;
@@ -1836,17 +1839,13 @@ static void socket_enter_running(Socket *s, int cfd) {
                         return;
                 }
 
-                prefix = unit_name_to_prefix(UNIT(s)->id);
-                if (!prefix) {
-                        r = -ENOMEM;
+                r = unit_name_to_prefix(UNIT(s)->id, &prefix);
+                if (r < 0)
                         goto fail;
-                }
 
-                name = unit_name_build(prefix, instance, ".service");
-                if (!name) {
-                        r = -ENOMEM;
+                r = unit_name_build(prefix, instance, ".service", &name);
+                if (r < 0)
                         goto fail;
-                }
 
                 r = unit_add_name(UNIT_DEREF(s->service), name);
                 if (r < 0)
diff --git a/src/core/swap.c b/src/core/swap.c
index a9834a7..3327cd9 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -222,18 +222,17 @@ static int swap_add_default_dependencies(Swap *s) {
 }
 
 static int swap_verify(Swap *s) {
-        bool b;
         _cleanup_free_ char *e = NULL;
+        int r;
 
         if (UNIT(s)->load_state != UNIT_LOADED)
                 return 0;
 
-        e = unit_name_from_path(s->what, ".swap");
-        if (!e)
-                return log_oom();
+        r = unit_name_from_path(s->what, ".swap", &e);
+        if (r < 0)
+                return log_unit_error_errno(UNIT(s)->id, r, "%s: failed to generate unit name from path: %m", UNIT(s)->id);
 
-        b = unit_has_name(UNIT(s), e);
-        if (!b) {
+        if (!unit_has_name(UNIT(s), e)) {
                 log_unit_error(UNIT(s)->id, "%s: Value of \"What\" and unit name do not match, not loading.", UNIT(s)->id);
                 return -EINVAL;
         }
@@ -289,8 +288,11 @@ static int swap_load(Unit *u) {
                                 s->what = strdup(s->parameters_fragment.what);
                         else if (s->parameters_proc_swaps.what)
                                 s->what = strdup(s->parameters_proc_swaps.what);
-                        else
-                                s->what = unit_name_to_path(u->id);
+                        else {
+                                r = unit_name_to_path(u->id, &s->what);
+                                if (r < 0)
+                                        return r;
+                        }
 
                         if (!s->what)
                                 return -ENOMEM;
@@ -355,9 +357,9 @@ static int swap_setup_unit(
         assert(what);
         assert(what_proc_swaps);
 
-        e = unit_name_from_path(what, ".swap");
-        if (!e)
-                return log_oom();
+        r = unit_name_from_path(what, ".swap", &e);
+        if (r < 0)
+                return log_unit_error_errno(u->id, r, "Failed to generate unit name from path: %m");
 
         u = manager_get_unit(m, e);
 
@@ -1329,9 +1331,9 @@ int swap_process_device_new(Manager *m, struct udev_device *dev) {
         if (!dn)
                 return 0;
 
-        e = unit_name_from_path(dn, ".swap");
-        if (!e)
-                return -ENOMEM;
+        r = unit_name_from_path(dn, ".swap", &e);
+        if (r < 0)
+                return r;
 
         s = hashmap_get(m->units, e);
         if (s)
@@ -1340,15 +1342,14 @@ int swap_process_device_new(Manager *m, struct udev_device *dev) {
         first = udev_device_get_devlinks_list_entry(dev);
         udev_list_entry_foreach(item, first) {
                 _cleanup_free_ char *n = NULL;
+                int q;
 
-                n = unit_name_from_path(udev_list_entry_get_name(item), ".swap");
-                if (!n)
-                        return -ENOMEM;
+                q = unit_name_from_path(udev_list_entry_get_name(item), ".swap", &n);
+                if (q < 0)
+                        return q;
 
                 s = hashmap_get(m->units, n);
                 if (s) {
-                        int q;
-
                         q = swap_set_devnode(s, dn);
                         if (q < 0)
                                 r = q;
diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c
index 5513fe7..8050e2f 100644
--- a/src/core/unit-printf.c
+++ b/src/core/unit-printf.c
@@ -30,83 +30,54 @@
 
 static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
         Unit *u = userdata;
-        char *n;
 
         assert(u);
 
-        n = unit_name_to_prefix_and_instance(u->id);
-        if (!n)
-                return -ENOMEM;
-
-        *ret = n;
-        return 0;
+        return unit_name_to_prefix_and_instance(u->id, ret);
 }
 
 static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) {
         Unit *u = userdata;
-        char *n;
 
         assert(u);
 
-        n = unit_name_to_prefix(u->id);
-        if (!n)
-                return -ENOMEM;
-
-        *ret = n;
-        return 0;
+        return unit_name_to_prefix(u->id, ret);
 }
 
 static int specifier_prefix_unescaped(char specifier, void *data, void *userdata, char **ret) {
-        Unit *u = userdata;
         _cleanup_free_ char *p = NULL;
-        char *n;
+        Unit *u = userdata;
+        int r;
 
         assert(u);
 
-        p = unit_name_to_prefix(u->id);
-        if (!p)
-                return -ENOMEM;
-
-        n = unit_name_unescape(p);
-        if (!n)
-                return -ENOMEM;
+        r = unit_name_to_prefix(u->id, &p);
+        if (r < 0)
+                return r;
 
-        *ret = n;
-        return 0;
+        return unit_name_unescape(p, ret);
 }
 
 static int specifier_instance_unescaped(char specifier, void *data, void *userdata, char **ret) {
         Unit *u = userdata;
-        char *n;
 
         assert(u);
 
         if (!u->instance)
-                return -EOPNOTSUPP;
-
-        n = unit_name_unescape(u->instance);
-        if (!n)
-                return -ENOMEM;
+                return -EINVAL;
 
-        *ret = n;
-        return 0;
+        return unit_name_unescape(u->instance, ret);
 }
 
 static int specifier_filename(char specifier, void *data, void *userdata, char **ret) {
         Unit *u = userdata;
-        char *n;
 
         assert(u);
 
         if (u->instance)
-                n = unit_name_path_unescape(u->instance);
+                return unit_name_path_unescape(u->instance, ret);
         else
-                n = unit_name_to_path(u->id);
-        if (!n)
-                return -ENOMEM;
-
-        *ret = n;
-        return 0;
+                return unit_name_to_path(u->id, ret);
 }
 
 static int specifier_cgroup(char specifier, void *data, void *userdata, char **ret) {
@@ -195,7 +166,7 @@ static int specifier_user_name(char specifier, void *data, void *userdata, char
 
         c = unit_get_exec_context(u);
         if (!c)
-                return -EOPNOTSUPP;
+                return -EINVAL;
 
         if (u->manager->running_as == SYSTEMD_SYSTEM) {
 
diff --git a/src/core/unit.c b/src/core/unit.c
index 6071bd5..6513bcb 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -143,21 +143,31 @@ int unit_add_name(Unit *u, const char *text) {
         assert(u);
         assert(text);
 
-        if (unit_name_is_template(text)) {
+        if (unit_name_is_valid(text, UNIT_NAME_TEMPLATE)) {
 
                 if (!u->instance)
                         return -EINVAL;
 
-                s = unit_name_replace_instance(text, u->instance);
-        } else
+                r = unit_name_replace_instance(text, u->instance, &s);
+                if (r < 0)
+                        return r;
+        } else {
                 s = strdup(text);
-        if (!s)
-                return -ENOMEM;
+                if (!s)
+                        return -ENOMEM;
+        }
 
-        if (!unit_name_is_valid(s, TEMPLATE_INVALID))
+        if (set_contains(u->names, s))
+                return 0;
+        if (hashmap_contains(u->manager->units, s))
+                return -EEXIST;
+
+        if (!unit_name_is_valid(s, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
                 return -EINVAL;
 
-        assert_se((t = unit_name_to_type(s)) >= 0);
+        t = unit_name_to_type(s);
+        if (t < 0)
+                return -EINVAL;
 
         if (u->type != _UNIT_TYPE_INVALID && t != u->type)
                 return -EINVAL;
@@ -170,25 +180,25 @@ int unit_add_name(Unit *u, const char *text) {
                 return -EINVAL;
 
         /* Ensure that this unit is either instanced or not instanced,
-         * but not both. */
+         * but not both. Note that we do allow names with different
+         * instance names however! */
         if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i)
                 return -EINVAL;
 
-        if (unit_vtable[t]->no_alias &&
-            !set_isempty(u->names) &&
-            !set_get(u->names, s))
+        if (unit_vtable[t]->no_alias && !set_isempty(u->names))
                 return -EEXIST;
 
         if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES)
                 return -E2BIG;
 
         r = set_put(u->names, s);
-        if (r <= 0)
+        if (r < 0)
                 return r;
+        assert(r > 0);
 
         r = hashmap_put(u->manager->units, s, u);
         if (r < 0) {
-                set_remove(u->names, s);
+                (void) set_remove(u->names, s);
                 return r;
         }
 
@@ -218,14 +228,14 @@ int unit_choose_id(Unit *u, const char *name) {
         assert(u);
         assert(name);
 
-        if (unit_name_is_template(name)) {
+        if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
 
                 if (!u->instance)
                         return -EINVAL;
 
-                t = unit_name_replace_instance(name, u->instance);
-                if (!t)
-                        return -ENOMEM;
+                r = unit_name_replace_instance(name, u->instance, &t);
+                if (r < 0)
+                        return r;
 
                 name = t;
         }
@@ -235,6 +245,7 @@ int unit_choose_id(Unit *u, const char *name) {
         if (!s)
                 return -ENOENT;
 
+        /* Determine the new instance from the new id */
         r = unit_name_to_instance(s, &i);
         if (r < 0)
                 return r;
@@ -748,24 +759,22 @@ int unit_merge_by_name(Unit *u, const char *name) {
         assert(u);
         assert(name);
 
-        if (unit_name_is_template(name)) {
+        if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
                 if (!u->instance)
                         return -EINVAL;
 
-                s = unit_name_replace_instance(name, u->instance);
-                if (!s)
-                        return -ENOMEM;
+                r = unit_name_replace_instance(name, u->instance, &s);
+                if (r < 0)
+                        return r;
 
                 name = s;
         }
 
         other = manager_get_unit(u->manager, name);
-        if (!other)
-                r = unit_add_name(u, name);
-        else
-                r = unit_merge(u, other);
+        if (other)
+                return unit_merge(u, other);
 
-        return r;
+        return unit_add_name(u, name);
 }
 
 Unit* unit_follow_merge(Unit *u) {
@@ -2294,58 +2303,55 @@ int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit
         if (r < 0)
                 return r;
 
-        r = unit_add_dependency(u, e, other, add_reference);
-        if (r < 0)
-                return r;
-
-        return 0;
+        return unit_add_dependency(u, e, other, add_reference);
 }
 
-static const char *resolve_template(Unit *u, const char *name, const char*path, char **p) {
-        char *s;
+static int resolve_template(Unit *u, const char *name, const char*path, char **buf, const char **ret) {
+        int r;
 
         assert(u);
         assert(name || path);
-        assert(p);
+        assert(buf);
+        assert(ret);
 
         if (!name)
                 name = basename(path);
 
-        if (!unit_name_is_template(name)) {
-                *p = NULL;
-                return name;
+        if (!unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
+                *buf = NULL;
+                *ret = name;
+                return 0;
         }
 
         if (u->instance)
-                s = unit_name_replace_instance(name, u->instance);
+                r = unit_name_replace_instance(name, u->instance, buf);
         else {
                 _cleanup_free_ char *i = NULL;
 
-                i = unit_name_to_prefix(u->id);
-                if (!i)
-                        return NULL;
+                r = unit_name_to_prefix(u->id, &i);
+                if (r < 0)
+                        return r;
 
-                s = unit_name_replace_instance(name, i);
+                r = unit_name_replace_instance(name, i, buf);
         }
+        if (r < 0)
+                return r;
 
-        if (!s)
-                return NULL;
-
-        *p = s;
-        return s;
+        *ret = *buf;
+        return 0;
 }
 
 int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
+        _cleanup_free_ char *buf = NULL;
         Unit *other;
         int r;
-        _cleanup_free_ char *s = NULL;
 
         assert(u);
         assert(name || path);
 
-        name = resolve_template(u, name, path, &s);
-        if (!name)
-                return -ENOMEM;
+        r = resolve_template(u, name, path, &buf, &name);
+        if (r < 0)
+                return r;
 
         r = manager_load_unit(u->manager, name, path, NULL, &other);
         if (r < 0)
@@ -2355,16 +2361,16 @@ int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, con
 }
 
 int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
-        _cleanup_free_ char *s = NULL;
+        _cleanup_free_ char *buf = NULL;
         Unit *other;
         int r;
 
         assert(u);
         assert(name || path);
 
-        name = resolve_template(u, name, path, &s);
-        if (!name)
-                return -ENOMEM;
+        r = resolve_template(u, name, path, &buf, &name);
+        if (r < 0)
+                return r;
 
         r = manager_load_unit(u->manager, name, path, NULL, &other);
         if (r < 0)
@@ -2374,16 +2380,16 @@ int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency
 }
 
 int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
+        _cleanup_free_ char *buf = NULL;
         Unit *other;
         int r;
-        _cleanup_free_ char *s = NULL;
 
         assert(u);
         assert(name || path);
 
-        name = resolve_template(u, name, path, &s);
-        if (!name)
-                return -ENOMEM;
+        r = resolve_template(u, name, path, &buf, &name);
+        if (r < 0)
+                return r;
 
         r = manager_load_unit(u->manager, name, path, NULL, &other);
         if (r < 0)
@@ -2393,26 +2399,22 @@ int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *n
 }
 
 int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
+        _cleanup_free_ char *buf = NULL;
         Unit *other;
         int r;
-        _cleanup_free_ char *s = NULL;
 
         assert(u);
         assert(name || path);
 
-        name = resolve_template(u, name, path, &s);
-        if (!name)
-                return -ENOMEM;
-
-        r = manager_load_unit(u->manager, name, path, NULL, &other);
+        r  = resolve_template(u, name, path, &buf, &name);
         if (r < 0)
                 return r;
 
-        r = unit_add_two_dependencies(other, d, e, u, add_reference);
+        r = manager_load_unit(u->manager, name, path, NULL, &other);
         if (r < 0)
                 return r;
 
-        return r;
+        return unit_add_two_dependencies(other, d, e, u, add_reference);
 }
 
 int set_unit_path(const char *p) {
@@ -2475,14 +2477,14 @@ int unit_add_default_slice(Unit *u, CGroupContext *c) {
                 /* Implicitly place all instantiated units in their
                  * own per-template slice */
 
-                prefix = unit_name_to_prefix(u->id);
-                if (!prefix)
-                        return -ENOMEM;
+                r = unit_name_to_prefix(u->id, &prefix);
+                if (r < 0)
+                        return r;
 
                 /* The prefix is already escaped, but it might include
                  * "-" which has a special meaning for slice units,
                  * hence escape it here extra. */
-                escaped = strreplace(prefix, "-", "\\x2d");
+                escaped = unit_name_escape(prefix);
                 if (!escaped)
                         return -ENOMEM;
 
@@ -2525,11 +2527,11 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
         assert(type);
         assert(_found);
 
-        t = unit_name_change_suffix(u->id, type);
-        if (!t)
-                return -ENOMEM;
-
-        assert(!unit_has_name(u, t));
+        r = unit_name_change_suffix(u->id, type, &t);
+        if (r < 0)
+                return r;
+        if (unit_has_name(u, t))
+                return -EINVAL;
 
         r = manager_load_unit(u->manager, t, NULL, NULL, _found);
         assert(r < 0 || *_found != u);
@@ -2858,9 +2860,9 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) {
         if (!unit_type_supported(UNIT_DEVICE))
                 return 0;
 
-        e = unit_name_from_path(what, ".device");
-        if (!e)
-                return -ENOMEM;
+        r = unit_name_from_path(what, ".device", &e);
+        if (r < 0)
+                return r;
 
         r = manager_load_unit(u->manager, e, NULL, NULL, &device);
         if (r < 0)
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index 5d234e6..755ee5d 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -78,9 +78,9 @@ static int create_disk(
         if (!e)
                 return log_oom();
 
-        n = unit_name_build("systemd-cryptsetup", e, ".service");
-        if (!n)
-                return log_oom();
+        r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate unit name: %m");
 
         p = strjoin(arg_dest, "/", n, NULL);
         if (!p)
@@ -90,9 +90,9 @@ static int create_disk(
         if (!u)
                 return log_oom();
 
-        d = unit_name_from_path(u, ".device");
-        if (!d)
-                return log_oom();
+        r = unit_name_from_path(u, ".device", &d);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate unit name: %m");
 
         f = fopen(p, "wxe");
         if (!f)
@@ -128,11 +128,11 @@ static int create_disk(
                         if (!path_equal(uu, "/dev/null")) {
 
                                 if (is_device_path(uu)) {
-                                        _cleanup_free_ char *dd;
+                                        _cleanup_free_ char *dd = NULL;
 
-                                        dd = unit_name_from_path(uu, ".device");
-                                        if (!dd)
-                                                return log_oom();
+                                        r = unit_name_from_path(uu, ".device", &dd);
+                                        if (r < 0)
+                                                return log_error_errno(r, "Failed to generate unit name: %m");
 
                                         fprintf(f, "After=%1$s\nRequires=%1$s\n", dd);
                                 } else
diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c
index 2e08af2..c909a4b 100644
--- a/src/dbus1-generator/dbus1-generator.c
+++ b/src/dbus1-generator/dbus1-generator.c
@@ -188,7 +188,7 @@ static int add_dbus(const char *path, const char *fname, const char *type) {
         }
 
         if (service) {
-                if (!unit_name_is_valid(service, TEMPLATE_INVALID)) {
+                if (!unit_name_is_valid(service, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) {
                         log_warning("Unit name %s is not valid, ignoring.", service);
                         return 0;
                 }
diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c
index 1b90193..9d0ab06 100644
--- a/src/debug-generator/debug-generator.c
+++ b/src/debug-generator/debug-generator.c
@@ -41,9 +41,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
                 else {
                         char *n;
 
-                        n = unit_name_mangle(value, MANGLE_NOGLOB);
-                        if (!n)
-                                return log_oom();
+                        r = unit_name_mangle(value, UNIT_NAME_NOGLOB, &n);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to glob unit name: %m");
 
                         r = strv_consume(&arg_mask, n);
                         if (r < 0)
@@ -57,9 +57,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
                 else {
                         char *n;
 
-                        n = unit_name_mangle(value, MANGLE_NOGLOB);
-                        if (!n)
-                                return log_oom();
+                        r = unit_name_mangle(value, UNIT_NAME_NOGLOB, &n);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to glob unit name: %m");
 
                         r = strv_consume(&arg_wants, n);
                         if (r < 0)
diff --git a/src/escape/escape.c b/src/escape/escape.c
index f2a0721..9ccb015 100644
--- a/src/escape/escape.c
+++ b/src/escape/escape.c
@@ -99,7 +99,7 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_TEMPLATE:
 
-                        if (!unit_name_is_valid(optarg, true) || !unit_name_is_template(optarg)) {
+                        if (!unit_name_is_valid(optarg, UNIT_NAME_TEMPLATE)) {
                                 log_error("Template name %s is not valid.", optarg);
                                 return -EINVAL;
                         }
@@ -166,22 +166,26 @@ int main(int argc, char *argv[]) {
                 switch (arg_action) {
 
                 case ACTION_ESCAPE:
-                        if (arg_path)
-                                e = unit_name_path_escape(*i);
-                        else
+                        if (arg_path) {
+                                r = unit_name_path_escape(*i, &e);
+                                if (r < 0) {
+                                        log_error_errno(r, "Failed to escape string: %m");
+                                        goto finish;
+                                }
+                        } else {
                                 e = unit_name_escape(*i);
-
-                        if (!e) {
-                                r = log_oom();
-                                goto finish;
+                                if (!e) {
+                                        r = log_oom();
+                                        goto finish;
+                                }
                         }
 
                         if (arg_template) {
                                 char *x;
 
-                                x = unit_name_replace_instance(arg_template, e);
-                                if (!x) {
-                                        r = log_oom();
+                                r = unit_name_replace_instance(arg_template, e, &x);
+                                if (r < 0) {
+                                        log_error_errno(r, "Failed to replace instance: %m");
                                         goto finish;
                                 }
 
@@ -204,20 +208,20 @@ int main(int argc, char *argv[]) {
 
                 case ACTION_UNESCAPE:
                         if (arg_path)
-                                e = unit_name_path_unescape(*i);
+                                r = unit_name_path_unescape(*i, &e);
                         else
-                                e = unit_name_unescape(*i);
+                                r = unit_name_unescape(*i, &e);
 
-                        if (!e) {
-                                r = log_oom();
+                        if (r < 0) {
+                                log_error_errno(r, "Failed to unescape string: %m");
                                 goto finish;
                         }
                         break;
 
                 case ACTION_MANGLE:
-                        e = unit_name_mangle(*i, MANGLE_NOGLOB);
-                        if (!e) {
-                                r = log_oom();
+                        r = unit_name_mangle(*i, UNIT_NAME_NOGLOB, &e);
+                        if (r < 0) {
+                                log_error_errno(r, "Failed to mangle name: %m");
                                 goto finish;
                         }
                         break;
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 664ee2a..167ec60 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -83,9 +83,9 @@ static int add_swap(
                 opts = filtered;
         }
 
-        name = unit_name_from_path(what, ".swap");
-        if (!name)
-                return log_oom();
+        r = unit_name_from_path(what, ".swap", &name);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate unit name: %m");
 
         unit = strjoin(arg_dest, "/", name, NULL);
         if (!unit)
@@ -224,9 +224,9 @@ static int add_mount(
                 noauto = nofail = automount = false;
         }
 
-        name = unit_name_from_path(where, ".mount");
-        if (!name)
-                return log_oom();
+        r = unit_name_from_path(where, ".mount", &name);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate unit name: %m");
 
         unit = strjoin(arg_dest, "/", name, NULL);
         if (!unit)
@@ -290,9 +290,9 @@ static int add_mount(
         }
 
         if (automount) {
-                automount_name = unit_name_from_path(where, ".automount");
-                if (!automount_name)
-                        return log_oom();
+                r = unit_name_from_path(where, ".automount", &automount_name);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to generate unit name: %m");
 
                 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
                 if (!automount_unit)
diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c
index d4688d3..d23caab 100644
--- a/src/getty-generator/getty-generator.c
+++ b/src/getty-generator/getty-generator.c
@@ -50,13 +50,11 @@ static int add_symlink(const char *fservice, const char *tservice) {
 
         r = symlink(from, to);
         if (r < 0) {
+                /* In case console=hvc0 is passed this will very likely result in EEXIST */
                 if (errno == EEXIST)
-                        /* In case console=hvc0 is passed this will very likely result in EEXIST */
                         return 0;
-                else {
-                        log_error_errno(errno, "Failed to create symlink %s: %m", to);
-                        return -errno;
-                }
+
+                return log_error_errno(errno, "Failed to create symlink %s: %m", to);
         }
 
         return 0;
@@ -64,28 +62,30 @@ static int add_symlink(const char *fservice, const char *tservice) {
 
 static int add_serial_getty(const char *tty) {
         _cleanup_free_ char *n = NULL;
+        int r;
 
         assert(tty);
 
         log_debug("Automatically adding serial getty for /dev/%s.", tty);
 
-        n = unit_name_from_path_instance("serial-getty", tty, ".service");
-        if (!n)
-                return log_oom();
+        r = unit_name_from_path_instance("serial-getty", tty, ".service", &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate service name: %m");
 
         return add_symlink("serial-getty at .service", n);
 }
 
 static int add_container_getty(const char *tty) {
         _cleanup_free_ char *n = NULL;
+        int r;
 
         assert(tty);
 
         log_debug("Automatically adding container getty for /dev/pts/%s.", tty);
 
-        n = unit_name_from_path_instance("container-getty", tty, ".service");
-        if (!n)
-                return log_oom();
+        r = unit_name_from_path_instance("container-getty", tty, ".service", &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate service name: %m");
 
         return add_symlink("container-getty at .service", n);
 }
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index 96a8447..b192526 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -49,14 +49,15 @@ static bool arg_root_rw = false;
 static int add_swap(const char *path) {
         _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
         _cleanup_fclose_ FILE *f = NULL;
+        int r;
 
         assert(path);
 
         log_debug("Adding swap: %s", path);
 
-        name = unit_name_from_path(path, ".swap");
-        if (!name)
-                return log_oom();
+        r = unit_name_from_path(path, ".swap", &name);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate unit name: %m");
 
         unit = strjoin(arg_dest, "/", name, NULL);
         if (!unit)
@@ -100,17 +101,17 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi
         assert(what);
         assert(device);
 
-        d = unit_name_from_path(what, ".device");
-        if (!d)
-                return log_oom();
+        r = unit_name_from_path(what, ".device", &d);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate unit name: %m");
 
         e = unit_name_escape(id);
         if (!e)
                 return log_oom();
 
-        n = unit_name_build("systemd-cryptsetup", e, ".service");
-        if (!n)
-                return log_oom();
+        r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate unit name: %m");
 
         p = strjoin(arg_dest, "/", n, NULL);
         if (!p)
@@ -224,9 +225,9 @@ static int add_mount(
                 fstype = NULL;
         }
 
-        unit = unit_name_from_path(where, ".mount");
-        if (!unit)
-                return log_oom();
+        r = unit_name_from_path(where, ".mount", &unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate unit name: %m");
 
         p = strjoin(arg_dest, "/", unit, NULL);
         if (!p)
diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c
index 0207346..9fb6233 100644
--- a/src/hibernate-resume/hibernate-resume-generator.c
+++ b/src/hibernate-resume/hibernate-resume-generator.c
@@ -32,6 +32,7 @@ static const char *arg_dest = "/tmp";
 static char *arg_resume_dev = NULL;
 
 static int parse_proc_cmdline_item(const char *key, const char *value) {
+
         if (streq(key, "resume") && value) {
                 free(arg_resume_dev);
                 arg_resume_dev = fstab_node_to_udev_node(value);
@@ -44,13 +45,14 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
 
 static int process_resume(void) {
         _cleanup_free_ char *name = NULL, *lnk = NULL;
+        int r;
 
         if (!arg_resume_dev)
                 return 0;
 
-        name = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_dev, ".service");
-        if (!name)
-                return log_oom();
+        r = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_dev, ".service", &name);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate unit name: %m");
 
         lnk = strjoin(arg_dest, "/" SPECIAL_SYSINIT_TARGET ".wants/", name, NULL);
         if (!lnk)
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 666aa20..627e43b 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -1135,9 +1135,9 @@ static int add_units(sd_journal *j) {
         STRV_FOREACH(i, arg_system_units) {
                 _cleanup_free_ char *u = NULL;
 
-                u = unit_name_mangle(*i, MANGLE_GLOB);
-                if (!u)
-                        return log_oom();
+                r = unit_name_mangle(*i, UNIT_NAME_GLOB, &u);
+                if (r < 0)
+                        return r;
 
                 if (string_is_glob(u)) {
                         r = strv_push(&patterns, u);
@@ -1181,9 +1181,9 @@ static int add_units(sd_journal *j) {
         STRV_FOREACH(i, arg_user_units) {
                 _cleanup_free_ char *u = NULL;
 
-                u = unit_name_mangle(*i, MANGLE_GLOB);
-                if (!u)
-                        return log_oom();
+                r = unit_name_mangle(*i, UNIT_NAME_GLOB, &u);
+                if (r < 0)
+                        return r;
 
                 if (string_is_glob(u)) {
                         r = strv_push(&patterns, u);
@@ -1840,9 +1840,8 @@ int main(int argc, char *argv[]) {
                 return EXIT_FAILURE;
 
         r = add_units(j);
-        strv_free(arg_system_units);
-        strv_free(arg_user_units);
-
+        arg_system_units = strv_free(arg_system_units);
+        arg_user_units = strv_free(arg_user_units);
         if (r < 0) {
                 log_error_errno(r, "Failed to add filter for units: %m");
                 return EXIT_FAILURE;
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index b00e9b1..71bff96 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -378,7 +378,7 @@ static int user_start_slice(User *u) {
                 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
                 sprintf(lu, UID_FMT, u->uid);
 
-                r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
+                r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &slice);
                 if (r < 0)
                         return r;
 
@@ -411,9 +411,9 @@ static int user_start_service(User *u) {
                 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
                 sprintf(lu, UID_FMT, u->uid);
 
-                service = unit_name_build("user", lu, ".service");
-                if (!service)
-                        return log_oom();
+                r = unit_name_build("user", lu, ".service", &service);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to build service name: %m");
 
                 r = manager_start_unit(u->manager, service, &error, &job);
                 if (r < 0) {
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index ed72218..9931e4f 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -1340,6 +1340,29 @@ static int read_only_image(int argc, char *argv[], void *userdata) {
         return 0;
 }
 
+static int make_service_name(const char *name, char **ret) {
+        _cleanup_free_ char *e = NULL;
+        int r;
+
+        assert(name);
+        assert(ret);
+
+        if (!machine_name_is_valid(name)) {
+                log_error("Invalid machine name %s.", name);
+                return -EINVAL;
+        }
+
+        e = unit_name_escape(name);
+        if (!e)
+                return log_oom();
+
+        r = unit_name_build("systemd-nspawn", e, ".service", ret);
+        if (r < 0)
+                return log_error_errno(r, "Failed to build unit name: %m");
+
+        return 0;
+}
+
 static int start_machine(int argc, char *argv[], void *userdata) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
@@ -1356,21 +1379,12 @@ static int start_machine(int argc, char *argv[], void *userdata) {
 
         for (i = 1; i < argc; i++) {
                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-                _cleanup_free_ char *e = NULL, *unit = NULL;
+                _cleanup_free_ char *unit = NULL;
                 const char *object;
 
-                if (!machine_name_is_valid(argv[i])) {
-                        log_error("Invalid machine name %s.", argv[i]);
-                        return -EINVAL;
-                }
-
-                e = unit_name_escape(argv[i]);
-                if (!e)
-                        return log_oom();
-
-                unit = unit_name_build("systemd-nspawn", e, ".service");
-                if (!unit)
-                        return log_oom();
+                r = make_service_name(argv[i], &unit);
+                if (r < 0)
+                        return r;
 
                 r = sd_bus_call_method(
                                 bus,
@@ -1433,18 +1447,9 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
         for (i = 1; i < argc; i++) {
                 _cleanup_free_ char *e = NULL, *unit = NULL;
 
-                if (!machine_name_is_valid(argv[i])) {
-                        log_error("Invalid machine name %s.", argv[i]);
-                        return -EINVAL;
-                }
-
-                e = unit_name_escape(argv[i]);
-                if (!e)
-                        return log_oom();
-
-                unit = unit_name_build("systemd-nspawn", e, ".service");
-                if (!unit)
-                        return log_oom();
+                r = make_service_name(argv[i], &unit);
+                if (r < 0)
+                        return r;
 
                 r = sd_bus_message_append(m, "s", unit);
                 if (r < 0)
diff --git a/src/run/run.c b/src/run/run.c
index db15ab6..fcd6b06 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -414,9 +414,9 @@ static int transient_cgroup_set_properties(sd_bus_message *m) {
         if (!isempty(arg_slice)) {
                 _cleanup_free_ char *slice;
 
-                slice = unit_name_mangle_with_suffix(arg_slice, MANGLE_NOGLOB, ".slice");
-                if (!slice)
-                        return -ENOMEM;
+                r = unit_name_mangle_with_suffix(arg_slice, UNIT_NAME_NOGLOB, ".slice", &slice);
+                if (r < 0)
+                        return r;
 
                 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
                 if (r < 0)
@@ -728,9 +728,9 @@ static int start_transient_service(
         }
 
         if (arg_unit) {
-                service = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".service");
-                if (!service)
-                        return log_oom();
+                r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to mangle unit name: %m");
         } else if (asprintf(&service, "run-"PID_FMT".service", getpid()) < 0)
                 return log_oom();
 
@@ -846,9 +846,9 @@ static int start_transient_scope(
                 return log_oom();
 
         if (arg_unit) {
-                scope = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".scope");
-                if (!scope)
-                        return log_oom();
+                r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".scope", &scope);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to mangle scope name: %m");
         } else if (asprintf(&scope, "run-"PID_FMT".scope", getpid()) < 0)
                 return log_oom();
 
@@ -980,16 +980,16 @@ static int start_transient_timer(
                 return log_oom();
 
         if (arg_unit) {
-                switch(unit_name_to_type(arg_unit)) {
+                switch (unit_name_to_type(arg_unit)) {
 
                 case UNIT_SERVICE:
                         service = strdup(arg_unit);
                         if (!service)
                                 return log_oom();
 
-                        timer = unit_name_change_suffix(service, ".timer");
-                        if (!timer)
-                                return log_oom();
+                        r = unit_name_change_suffix(service, ".timer", &timer);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to change unit suffix: %m");
                         break;
 
                 case UNIT_TIMER:
@@ -997,19 +997,19 @@ static int start_transient_timer(
                         if (!timer)
                                 return log_oom();
 
-                        service = unit_name_change_suffix(timer, ".service");
-                        if (!service)
-                                return log_oom();
+                        r = unit_name_change_suffix(timer, ".service", &service);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to change unit suffix: %m");
                         break;
 
                 default:
-                        service = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".service");
-                        if (!service)
-                                return log_oom();
+                        r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to mangle unit name: %m");
 
-                        timer = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".timer");
-                        if (!timer)
-                                return log_oom();
+                        r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".timer", &timer);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to mangle unit name: %m");
 
                         break;
                 }
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index b5e4094..c0b0ca4 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -1154,7 +1154,7 @@ int cg_path_decode_unit(const char *cgroup, char **unit){
         c = strndupa(cgroup, n);
         c = cg_unescape(c);
 
-        if (!unit_name_is_valid(c, TEMPLATE_INVALID))
+        if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
                 return -ENXIO;
 
         s = strdup(c);
@@ -1181,7 +1181,7 @@ static bool valid_slice_name(const char *p, size_t n) {
 
                 c = cg_unescape(buf);
 
-                return unit_name_is_valid(c, TEMPLATE_INVALID);
+                return unit_name_is_valid(c, UNIT_NAME_PLAIN);
         }
 
         return false;
@@ -1638,6 +1638,7 @@ bool cg_controller_is_valid(const char *p, bool allow_named) {
 int cg_slice_to_path(const char *unit, char **ret) {
         _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
         const char *dash;
+        int r;
 
         assert(unit);
         assert(ret);
@@ -1652,15 +1653,15 @@ int cg_slice_to_path(const char *unit, char **ret) {
                 return 0;
         }
 
-        if (!unit_name_is_valid(unit, TEMPLATE_INVALID))
+        if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN))
                 return -EINVAL;
 
         if (!endswith(unit, ".slice"))
                 return -EINVAL;
 
-        p = unit_name_to_prefix(unit);
-        if (!p)
-                return -ENOMEM;
+        r = unit_name_to_prefix(unit, &p);
+        if (r < 0)
+                return r;
 
         dash = strchr(p, '-');
 
@@ -1677,7 +1678,7 @@ int cg_slice_to_path(const char *unit, char **ret) {
                         return -EINVAL;
 
                 strcpy(stpncpy(n, p, dash - p), ".slice");
-                if (!unit_name_is_valid(n, TEMPLATE_INVALID))
+                if (!unit_name_is_valid(n, UNIT_NAME_PLAIN))
                         return -EINVAL;
 
                 escaped = cg_escape(n);
diff --git a/src/shared/dropin.c b/src/shared/dropin.c
index d1baad6..963d05d 100644
--- a/src/shared/dropin.c
+++ b/src/shared/dropin.c
@@ -164,7 +164,7 @@ static int iterate_dir(
 }
 
 int unit_file_process_dir(
-                Set * unit_path_cache,
+                Set *unit_path_cache,
                 const char *unit_path,
                 const char *name,
                 const char *suffix,
@@ -174,6 +174,7 @@ int unit_file_process_dir(
                 char ***strv) {
 
         _cleanup_free_ char *path = NULL;
+        int r;
 
         assert(unit_path);
         assert(name);
@@ -184,22 +185,22 @@ int unit_file_process_dir(
                 return log_oom();
 
         if (!unit_path_cache || set_get(unit_path_cache, path))
-                iterate_dir(path, dependency, consumer, arg, strv);
+                (void) iterate_dir(path, dependency, consumer, arg, strv);
 
-        if (unit_name_is_instance(name)) {
+        if (unit_name_is_valid(name, UNIT_NAME_INSTANCE)) {
                 _cleanup_free_ char *template = NULL, *p = NULL;
                 /* Also try the template dir */
 
-                template = unit_name_template(name);
-                if (!template)
-                        return log_oom();
+                r = unit_name_template(name, &template);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to generate template from unit name: %m");
 
                 p = strjoin(unit_path, "/", template, suffix, NULL);
                 if (!p)
                         return log_oom();
 
                 if (!unit_path_cache || set_get(unit_path_cache, p))
-                        iterate_dir(p, dependency, consumer, arg, strv);
+                        (void) iterate_dir(p, dependency, consumer, arg, strv);
         }
 
         return 0;
diff --git a/src/shared/generator.c b/src/shared/generator.c
index 7b2f846..2dc34bf 100644
--- a/src/shared/generator.c
+++ b/src/shared/generator.c
@@ -37,6 +37,8 @@ int generator_write_fsck_deps(
                 const char *where,
                 const char *fstype) {
 
+        int r;
+
         assert(f);
         assert(dir);
         assert(what);
@@ -48,7 +50,6 @@ int generator_write_fsck_deps(
         }
 
         if (!isempty(fstype) && !streq(fstype, "auto")) {
-                int r;
                 r = fsck_exists(fstype);
                 if (r == -ENOENT) {
                         /* treat missing check as essentially OK */
@@ -70,9 +71,9 @@ int generator_write_fsck_deps(
         } else {
                 _cleanup_free_ char *fsck = NULL;
 
-                fsck = unit_name_from_path_instance("systemd-fsck", what, ".service");
-                if (!fsck)
-                        return log_oom();
+                r = unit_name_from_path_instance("systemd-fsck", what, ".service", &fsck);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to create fsck service name: %m");
 
                 fprintf(f,
                         "RequiresOverridable=%1$s\n"
@@ -106,8 +107,7 @@ int generator_write_timeouts(
 
         r = parse_sec(timeout, &u);
         if (r < 0) {
-                log_warning("Failed to parse timeout for %s, ignoring: %s",
-                            where, timeout);
+                log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
                 return 0;
         }
 
@@ -115,9 +115,9 @@ int generator_write_timeouts(
         if (!node)
                 return log_oom();
 
-        unit = unit_name_from_path(node, ".device");
-        if (!unit)
-                return log_oom();
+        r = unit_name_from_path(node, ".device", &unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to make unit name from path: %m");
 
         return write_drop_in_format(dir, unit, 50, "device-timeout",
                                     "# Automatically generated by %s\n\n"
diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c
index 9996649..7c25d36 100644
--- a/src/shared/install-printf.c
+++ b/src/shared/install-printf.c
@@ -29,30 +29,18 @@
 
 static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
         InstallInfo *i = userdata;
-        char *n;
 
         assert(i);
 
-        n = unit_name_to_prefix_and_instance(i->name);
-        if (!n)
-                return -ENOMEM;
-
-        *ret = n;
-        return 0;
+        return unit_name_to_prefix_and_instance(i->name, ret);
 }
 
 static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) {
         InstallInfo *i = userdata;
-        char *n;
 
         assert(i);
 
-        n = unit_name_to_prefix(i->name);
-        if (!n)
-                return -ENOMEM;
-
-        *ret = n;
-        return 0;
+        return unit_name_to_prefix(i->name, ret);
 }
 
 static int specifier_instance(char specifier, void *data, void *userdata, char **ret) {
diff --git a/src/shared/install.c b/src/shared/install.c
index b121018..9648c64 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -258,10 +258,10 @@ static int remove_marked_symlinks_fd(
                         int q;
                         bool found;
 
-                        if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID))
+                        if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
                                 continue;
 
-                        if (unit_name_is_instance(de->d_name) &&
+                        if (unit_name_is_valid(de->d_name, UNIT_NAME_INSTANCE) &&
                             instance_whitelist &&
                             !strv_contains(instance_whitelist, de->d_name)) {
 
@@ -272,9 +272,9 @@ static int remove_marked_symlinks_fd(
                                  * the template of it might be
                                  * listed. */
 
-                                w = unit_name_template(de->d_name);
-                                if (!w)
-                                        return -ENOMEM;
+                                r = unit_name_template(de->d_name, &w);
+                                if (r < 0)
+                                        return r;
 
                                 if (!strv_contains(instance_whitelist, w))
                                         continue;
@@ -583,7 +583,7 @@ int unit_file_mask(
         STRV_FOREACH(i, files) {
                 _cleanup_free_ char *path = NULL;
 
-                if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
+                if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
                         if (r == 0)
                                 r = -EINVAL;
                         continue;
@@ -646,7 +646,7 @@ int unit_file_unmask(
         STRV_FOREACH(i, files) {
                 _cleanup_free_ char *path = NULL;
 
-                if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
+                if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
                         if (r == 0)
                                 r = -EINVAL;
                         continue;
@@ -717,7 +717,7 @@ int unit_file_link(
                 fn = basename(*i);
 
                 if (!path_is_absolute(*i) ||
-                    !unit_name_is_valid(fn, TEMPLATE_VALID)) {
+                    !unit_name_is_valid(fn, UNIT_NAME_ANY)) {
                         if (r == 0)
                                 r = -EINVAL;
                         continue;
@@ -856,7 +856,7 @@ static int install_info_add(
         if (!name)
                 name = basename(path);
 
-        if (!unit_name_is_valid(name, TEMPLATE_VALID))
+        if (!unit_name_is_valid(name, UNIT_NAME_ANY))
                 return -EINVAL;
 
         if (ordered_hashmap_get(c->have_installed, name) ||
@@ -1118,7 +1118,7 @@ static int unit_file_search(
                         return r;
         }
 
-        if (unit_name_is_instance(info->name)) {
+        if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
 
                 /* Unit file doesn't exist, however instance
                  * enablement was requested.  We will check if it is
@@ -1126,9 +1126,9 @@ static int unit_file_search(
 
                 _cleanup_free_ char *template = NULL;
 
-                template = unit_name_template(info->name);
-                if (!template)
-                        return -ENOMEM;
+                r = unit_name_template(info->name, &template);
+                if (r < 0)
+                        return r;
 
                 STRV_FOREACH(p, paths->unit_path) {
                         _cleanup_free_ char *path = NULL;
@@ -1274,7 +1274,7 @@ static int install_info_symlink_wants(
         assert(i);
         assert(config_path);
 
-        if (unit_name_is_template(i->name)) {
+        if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
 
                 /* Don't install any symlink if there's no default
                  * instance configured */
@@ -1282,9 +1282,9 @@ static int install_info_symlink_wants(
                 if (!i->default_instance)
                         return 0;
 
-                buf = unit_name_replace_instance(i->name, i->default_instance);
-                if (!buf)
-                        return -ENOMEM;
+                r = unit_name_replace_instance(i->name, i->default_instance, &buf);
+                if (r < 0)
+                        return r;
 
                 n = buf;
         } else
@@ -1297,7 +1297,7 @@ static int install_info_symlink_wants(
                 if (q < 0)
                         return q;
 
-                if (!unit_name_is_valid(dst, TEMPLATE_VALID)) {
+                if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) {
                         r = -EINVAL;
                         continue;
                 }
@@ -1462,13 +1462,13 @@ static int install_context_mark_for_removal(
                 } else if (r >= 0)
                         r += q;
 
-                if (unit_name_is_instance(i->name)) {
+                if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) {
                         char *unit_file;
 
                         if (i->path) {
                                 unit_file = basename(i->path);
 
-                                if (unit_name_is_instance(unit_file))
+                                if (unit_name_is_valid(unit_file, UNIT_NAME_INSTANCE))
                                         /* unit file named as instance exists, thus all symlinks
                                          * pointing to it will be removed */
                                         q = mark_symlink_for_removal(remove_symlinks_to, i->name);
@@ -1480,9 +1480,9 @@ static int install_context_mark_for_removal(
                                 /* If i->path is not set, it means that we didn't actually find
                                  * the unit file. But we can still remove symlinks to the
                                  * nonexistent template. */
-                                unit_file = unit_name_template(i->name);
-                                if (!unit_file)
-                                        return log_oom();
+                                r = unit_name_template(i->name, &unit_file);
+                                if (r < 0)
+                                        return r;
 
                                 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
                                 free(unit_file);
@@ -1797,7 +1797,7 @@ UnitFileState unit_file_lookup_state(
 
         assert(paths);
 
-        if (!unit_name_is_valid(name, TEMPLATE_VALID))
+        if (!unit_name_is_valid(name, UNIT_NAME_ANY))
                 return -EINVAL;
 
         STRV_FOREACH(i, paths->unit_path) {
@@ -1824,7 +1824,7 @@ UnitFileState unit_file_lookup_state(
                         if (errno != ENOENT)
                                 return r;
 
-                        if (!unit_name_is_instance(name))
+                        if (!unit_name_is_valid(name, UNIT_NAME_INSTANCE))
                                 continue;
                 } else {
                         if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
@@ -1834,8 +1834,7 @@ UnitFileState unit_file_lookup_state(
                         if (r < 0 && r != -ENOENT)
                                 return r;
                         else if (r > 0) {
-                                state = path_startswith(*i, "/run") ?
-                                        UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
+                                state = path_startswith(*i, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
                                 return state;
                         }
                 }
@@ -1995,7 +1994,7 @@ int unit_file_preset(
 
         STRV_FOREACH(i, files) {
 
-                if (!unit_name_is_valid(*i, TEMPLATE_VALID))
+                if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
                         return -EINVAL;
 
                 r = unit_file_query_preset(scope, root_dir, *i);
@@ -2091,7 +2090,7 @@ int unit_file_preset_all(
                         if (hidden_file(de->d_name))
                                 continue;
 
-                        if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID))
+                        if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
                                 continue;
 
                         dirent_ensure_type(d, de);
@@ -2203,7 +2202,7 @@ int unit_file_get_list(
                         if (hidden_file(de->d_name))
                                 continue;
 
-                        if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID))
+                        if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
                                 continue;
 
                         if (hashmap_get(h, de->d_name))
diff --git a/src/shared/unit-name.c b/src/shared/unit-name.c
index 86d6ce3..c41d7d8 100644
--- a/src/shared/unit-name.c
+++ b/src/shared/unit-name.c
@@ -33,45 +33,13 @@
         DIGITS LETTERS                          \
         ":-_.\\"
 
-static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
-        [UNIT_SERVICE] = "service",
-        [UNIT_SOCKET] = "socket",
-        [UNIT_BUSNAME] = "busname",
-        [UNIT_TARGET] = "target",
-        [UNIT_SNAPSHOT] = "snapshot",
-        [UNIT_DEVICE] = "device",
-        [UNIT_MOUNT] = "mount",
-        [UNIT_AUTOMOUNT] = "automount",
-        [UNIT_SWAP] = "swap",
-        [UNIT_TIMER] = "timer",
-        [UNIT_PATH] = "path",
-        [UNIT_SLICE] = "slice",
-        [UNIT_SCOPE] = "scope"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType);
-
-static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
-        [UNIT_STUB] = "stub",
-        [UNIT_LOADED] = "loaded",
-        [UNIT_NOT_FOUND] = "not-found",
-        [UNIT_ERROR] = "error",
-        [UNIT_MERGED] = "merged",
-        [UNIT_MASKED] = "masked"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
-
-bool unit_name_is_valid(const char *n, enum template_valid template_ok) {
+bool unit_name_is_valid(const char *n, UnitNameFlags flags) {
         const char *e, *i, *at;
 
-        /* Valid formats:
-         *
-         *         string at instance.suffix
-         *         string.suffix
-         */
+        assert((flags & ~(UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) == 0);
 
-        assert(IN_SET(template_ok, TEMPLATE_VALID, TEMPLATE_INVALID));
+        if (_unlikely_(flags == 0))
+                return false;
 
         if (isempty(n))
                 return false;
@@ -95,15 +63,32 @@ bool unit_name_is_valid(const char *n, enum template_valid template_ok) {
                         return false;
         }
 
-        if (at) {
-                if (at == n)
-                        return false;
+        if (at == n)
+                return false;
 
-                if (template_ok != TEMPLATE_VALID && at+1 == e)
-                        return false;
-        }
+        if (flags & UNIT_NAME_PLAIN)
+                if (!at)
+                        return true;
 
-        return true;
+        if (flags & UNIT_NAME_INSTANCE)
+                if (at && e > at + 1)
+                        return true;
+
+        if (flags & UNIT_NAME_TEMPLATE)
+                if (at && e == at + 1)
+                        return true;
+
+        return false;
+}
+
+bool unit_prefix_is_valid(const char *p) {
+
+        /* We don't allow additional @ in the prefix string */
+
+        if (isempty(p))
+                return false;
+
+        return in_charset(p, VALID_CHARS);
 }
 
 bool unit_instance_is_valid(const char *i) {
@@ -120,14 +105,41 @@ bool unit_instance_is_valid(const char *i) {
         return in_charset(i, "@" VALID_CHARS);
 }
 
-bool unit_prefix_is_valid(const char *p) {
+bool unit_suffix_is_valid(const char *s) {
+        if (isempty(s))
+                return false;
 
-        /* We don't allow additional @ in the instance string */
+        if (s[0] != '.')
+                return false;
 
-        if (isempty(p))
+        if (unit_type_from_string(s + 1) < 0)
                 return false;
 
-        return in_charset(p, VALID_CHARS);
+        return true;
+}
+
+int unit_name_to_prefix(const char *n, char **ret) {
+        const char *p;
+        char *s;
+
+        assert(n);
+        assert(ret);
+
+        if (!unit_name_is_valid(n, UNIT_NAME_ANY))
+                return -EINVAL;
+
+        p = strchr(n, '@');
+        if (!p)
+                p = strrchr(n, '.');
+
+        assert_se(p);
+
+        s = strndup(n, p - n);
+        if (!s)
+                return -ENOMEM;
+
+        *ret = s;
+        return 0;
 }
 
 int unit_name_to_instance(const char *n, char **instance) {
@@ -137,6 +149,9 @@ int unit_name_to_instance(const char *n, char **instance) {
         assert(n);
         assert(instance);
 
+        if (!unit_name_is_valid(n, UNIT_NAME_ANY))
+                return -EINVAL;
+
         /* Everything past the first @ and before the last . is the instance */
         p = strchr(n, '@');
         if (!p) {
@@ -144,13 +159,13 @@ int unit_name_to_instance(const char *n, char **instance) {
                 return 0;
         }
 
-        d = strrchr(n, '.');
+        p++;
+
+        d = strrchr(p, '.');
         if (!d)
                 return -EINVAL;
-        if (d < p)
-                return -EINVAL;
 
-        i = strndup(p+1, d-p-1);
+        i = strndup(p, d-p);
         if (!i)
                 return -ENOMEM;
 
@@ -158,55 +173,95 @@ int unit_name_to_instance(const char *n, char **instance) {
         return 1;
 }
 
-char *unit_name_to_prefix_and_instance(const char *n) {
+int unit_name_to_prefix_and_instance(const char *n, char **ret) {
         const char *d;
+        char *s;
 
         assert(n);
+        assert(ret);
+
+        if (!unit_name_is_valid(n, UNIT_NAME_ANY))
+                return -EINVAL;
 
-        assert_se(d = strrchr(n, '.'));
-        return strndup(n, d - n);
+        d = strrchr(n, '.');
+        if (!d)
+                return -EINVAL;
+
+        s = strndup(n, d - n);
+        if (!s)
+                return -ENOMEM;
+
+        *ret = s;
+        return 0;
 }
 
-char *unit_name_to_prefix(const char *n) {
-        const char *p;
+UnitType unit_name_to_type(const char *n) {
+        const char *e;
 
         assert(n);
 
-        p = strchr(n, '@');
-        if (p)
-                return strndup(n, p - n);
+        if (!unit_name_is_valid(n, UNIT_NAME_ANY))
+                return _UNIT_TYPE_INVALID;
 
-        return unit_name_to_prefix_and_instance(n);
+        assert_se(e = strrchr(n, '.'));
+
+        return unit_type_from_string(e + 1);
 }
 
-char *unit_name_change_suffix(const char *n, const char *suffix) {
-        char *e, *r;
+int unit_name_change_suffix(const char *n, const char *suffix, char **ret) {
+        char *e, *s;
         size_t a, b;
 
         assert(n);
         assert(suffix);
-        assert(suffix[0] == '.');
+        assert(ret);
+
+        if (!unit_name_is_valid(n, UNIT_NAME_ANY))
+                return -EINVAL;
+
+        if (!unit_suffix_is_valid(suffix))
+                return -EINVAL;
 
         assert_se(e = strrchr(n, '.'));
+
         a = e - n;
         b = strlen(suffix);
 
-        r = new(char, a + b + 1);
-        if (!r)
-                return NULL;
+        s = new(char, a + b + 1);
+        if (!s)
+                return -ENOMEM;
 
-        strcpy(mempcpy(r, n, a), suffix);
-        return r;
+        strcpy(mempcpy(s, n, a), suffix);
+        *ret = s;
+
+        return 0;
 }
 
-char *unit_name_build(const char *prefix, const char *instance, const char *suffix) {
+int unit_name_build(const char *prefix, const char *instance, const char *suffix, char **ret) {
+        char *s;
+
         assert(prefix);
         assert(suffix);
+        assert(ret);
+
+        if (!unit_prefix_is_valid(prefix))
+                return -EINVAL;
+
+        if (instance && !unit_instance_is_valid(instance))
+                return -EINVAL;
+
+        if (!unit_suffix_is_valid(suffix))
+                return -EINVAL;
 
         if (!instance)
-                return strappend(prefix, suffix);
+                s = strappend(prefix, suffix);
+        else
+                s = strjoin(prefix, "@", instance, suffix, NULL);
+        if (!s)
+                return -ENOMEM;
 
-        return strjoin(prefix, "@", instance, suffix, NULL);
+        *ret = s;
+        return 0;
 }
 
 static char *do_escape_char(char c, char *t) {
@@ -242,30 +297,6 @@ static char *do_escape(const char *f, char *t) {
         return t;
 }
 
-static char *do_escape_mangle(const char *f, enum unit_name_mangle allow_globs, char *t) {
-        const char *valid_chars;
-
-        assert(f);
-        assert(IN_SET(allow_globs, MANGLE_GLOB, MANGLE_NOGLOB));
-        assert(t);
-
-        /* We'll only escape the obvious characters here, to play
-         * safe. */
-
-        valid_chars = allow_globs == MANGLE_GLOB ? "@" VALID_CHARS "[]!-*?" : "@" VALID_CHARS;
-
-        for (; *f; f++) {
-                if (*f == '/')
-                        *(t++) = '-';
-                else if (!strchr(valid_chars, *f))
-                        t = do_escape_char(*f, t);
-                else
-                        *(t++) = *f;
-        }
-
-        return t;
-}
-
 char *unit_name_escape(const char *f) {
         char *r, *t;
 
@@ -281,14 +312,15 @@ char *unit_name_escape(const char *f) {
         return r;
 }
 
-char *unit_name_unescape(const char *f) {
-        char *r, *t;
+int unit_name_unescape(const char *f, char **ret) {
+        _cleanup_free_ char *r = NULL;
+        char *t;
 
         assert(f);
 
         r = strdup(f);
         if (!r)
-                return NULL;
+                return -ENOMEM;
 
         for (t = r; *f; f++) {
                 if (*f == '-')
@@ -296,180 +328,228 @@ char *unit_name_unescape(const char *f) {
                 else if (*f == '\\') {
                         int a, b;
 
-                        if (f[1] != 'x' ||
-                            (a = unhexchar(f[2])) < 0 ||
-                            (b = unhexchar(f[3])) < 0) {
-                                /* Invalid escape code, let's take it literal then */
-                                *(t++) = '\\';
-                        } else {
-                                *(t++) = (char) ((a << 4) | b);
-                                f += 3;
-                        }
+                        if (f[1] != 'x')
+                                return -EINVAL;
+
+                        a = unhexchar(f[2]);
+                        if (a < 0)
+                                return -EINVAL;
+
+                        b = unhexchar(f[3]);
+                        if (b < 0)
+                                return -EINVAL;
+
+                        *(t++) = (char) ((a << 4) | b);
+                        f += 3;
                 } else
                         *(t++) = *f;
         }
 
         *t = 0;
 
-        return r;
+        *ret = r;
+        r = NULL;
+
+        return 0;
 }
 
-char *unit_name_path_escape(const char *f) {
-        _cleanup_free_ char *p = NULL;
+int unit_name_path_escape(const char *f, char **ret) {
+        char *p, *s;
 
         assert(f);
+        assert(ret);
 
-        p = strdup(f);
+        p = strdupa(f);
         if (!p)
-                return NULL;
+                return -ENOMEM;
 
         path_kill_slashes(p);
 
         if (STR_IN_SET(p, "/", ""))
-                return strdup("-");
-
-        return unit_name_escape(p[0] == '/' ? p + 1 : p);
-}
+                s = strdup("-");
+        else {
+                char *e;
 
-char *unit_name_path_unescape(const char *f) {
-        char *e, *w;
+                if (!path_is_safe(p))
+                        return -EINVAL;
 
-        assert(f);
+                /* Truncate trailing slashes */
+                e = endswith(p, "/");
+                if (e)
+                        *e = 0;
 
-        e = unit_name_unescape(f);
-        if (!e)
-                return NULL;
+                /* Truncate leading slashes */
+                if (p[0] == '/')
+                        p++;
 
-        if (e[0] != '/') {
-                w = strappend("/", e);
-                free(e);
-                return w;
+                s = unit_name_escape(p);
         }
+        if (!s)
+                return -ENOMEM;
 
-        return e;
+        *ret = s;
+        return 0;
 }
 
-bool unit_name_is_template(const char *n) {
-        const char *p, *e;
-
-        assert(n);
+int unit_name_path_unescape(const char *f, char **ret) {
+        char *s, *w;
+        int r;
 
-        p = strchr(n, '@');
-        if (!p)
-                return false;
+        assert(f);
 
-        e = strrchr(p+1, '.');
-        if (!e)
-                return false;
+        if (streq(f, "-")) {
+                s = strdup("/");
+                if (!s)
+                        return -ENOMEM;
 
-        return e == p + 1;
-}
+                *ret = s;
+                return 0;
+        }
 
-bool unit_name_is_instance(const char *n) {
-        const char *p, *e;
+        r = unit_name_unescape(f, &s);
+        if (r < 0)
+                return r;
 
-        assert(n);
+        /* Don't accept trailing or leading slashes */
+        if (startswith(s, "/") || endswith(s, "/")) {
+                free(s);
+                return -EINVAL;
+        }
 
-        p = strchr(n, '@');
-        if (!p)
-                return false;
+        /* Prefix a slash again */
+        w = strappend("/", s);
+        free(s);
+        if (!w)
+                return -ENOMEM;
 
-        e = strrchr(p+1, '.');
-        if (!e)
-                return false;
+        if (!path_is_safe(w)) {
+                free(w);
+                return -EINVAL;
+        }
 
-        return e > p + 1;
+        *ret = w;
+        return 0;
 }
 
-char *unit_name_replace_instance(const char *f, const char *i) {
+int unit_name_replace_instance(const char *f, const char *i, char **ret) {
         const char *p, *e;
-        char *r;
+        char *s;
         size_t a, b;
 
         assert(f);
         assert(i);
+        assert(ret);
 
-        p = strchr(f, '@');
-        if (!p)
-                return strdup(f);
+        if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
+                return -EINVAL;
+        if (!unit_instance_is_valid(i))
+                return -EINVAL;
 
-        e = strrchr(f, '.');
-        if (!e)
-                e = strchr(f, 0);
+        assert_se(p = strchr(f, '@'));
+        assert_se(e = strrchr(f, '.'));
 
         a = p - f;
         b = strlen(i);
 
-        r = new(char, a + 1 + b + strlen(e) + 1);
-        if (!r)
-                return NULL;
+        s = new(char, a + 1 + b + strlen(e) + 1);
+        if (!s)
+                return -ENOMEM;
 
-        strcpy(mempcpy(mempcpy(r, f, a + 1), i, b), e);
-        return r;
+        strcpy(mempcpy(mempcpy(s, f, a + 1), i, b), e);
+
+        *ret = s;
+        return 0;
 }
 
-char *unit_name_template(const char *f) {
+int unit_name_template(const char *f, char **ret) {
         const char *p, *e;
-        char *r;
+        char *s;
         size_t a;
 
         assert(f);
+        assert(ret);
 
-        p = strchr(f, '@');
-        if (!p)
-                return strdup(f);
+        if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
+                return -EINVAL;
 
-        e = strrchr(f, '.');
-        if (!e)
-                e = strchr(f, 0);
+        assert_se(p = strchr(f, '@'));
+        assert_se(e = strrchr(f, '.'));
 
         a = p - f;
 
-        r = new(char, a + 1 + strlen(e) + 1);
-        if (!r)
-                return NULL;
+        s = new(char, a + 1 + strlen(e) + 1);
+        if (!s)
+                return -ENOMEM;
 
-        strcpy(mempcpy(r, f, a + 1), e);
-        return r;
+        strcpy(mempcpy(s, f, a + 1), e);
+
+        *ret = s;
+        return 0;
 }
 
-char *unit_name_from_path(const char *path, const char *suffix) {
+int unit_name_from_path(const char *path, const char *suffix, char **ret) {
         _cleanup_free_ char *p = NULL;
+        char *s = NULL;
+        int r;
 
         assert(path);
         assert(suffix);
+        assert(ret);
 
-        p = unit_name_path_escape(path);
-        if (!p)
-                return NULL;
+        if (!unit_suffix_is_valid(suffix))
+                return -EINVAL;
 
-        return strappend(p, suffix);
+        r = unit_name_path_escape(path, &p);
+        if (r < 0)
+                return r;
+
+        s = strappend(p, suffix);
+        if (!s)
+                return -ENOMEM;
+
+        *ret = s;
+        return 0;
 }
 
-char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix) {
+int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret) {
         _cleanup_free_ char *p = NULL;
+        char *s;
+        int r;
 
         assert(prefix);
         assert(path);
         assert(suffix);
+        assert(ret);
 
-        p = unit_name_path_escape(path);
-        if (!p)
-                return NULL;
+        if (!unit_prefix_is_valid(prefix))
+                return -EINVAL;
+
+        if (!unit_suffix_is_valid(suffix))
+                return -EINVAL;
+
+        r = unit_name_path_escape(path, &p);
+        if (r < 0)
+                return r;
+
+        s = strjoin(prefix, "@", p, suffix, NULL);
+        if (!s)
+                return -ENOMEM;
 
-        return strjoin(prefix, "@", p, suffix, NULL);
+        *ret = s;
+        return 0;
 }
 
-char *unit_name_to_path(const char *name) {
-        _cleanup_free_ char *w = NULL;
+int unit_name_to_path(const char *name, char **ret) {
+        _cleanup_free_ char *prefix = NULL;
+        int r;
 
         assert(name);
 
-        w = unit_name_to_prefix(name);
-        if (!w)
-                return NULL;
+        r = unit_name_to_prefix(name, &prefix);
+        if (r < 0)
+                return r;
 
-        return unit_name_path_unescape(w);
+        return unit_name_path_unescape(prefix, ret);
 }
 
 char *unit_dbus_path_from_name(const char *name) {
@@ -500,6 +580,30 @@ int unit_name_from_dbus_path(const char *path, char **name) {
         return 0;
 }
 
+static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t) {
+        const char *valid_chars;
+
+        assert(f);
+        assert(IN_SET(allow_globs, UNIT_NAME_GLOB, UNIT_NAME_NOGLOB));
+        assert(t);
+
+        /* We'll only escape the obvious characters here, to play
+         * safe. */
+
+        valid_chars = allow_globs == UNIT_NAME_GLOB ? "@" VALID_CHARS "[]!-*?" : "@" VALID_CHARS;
+
+        for (; *f; f++) {
+                if (*f == '/')
+                        *(t++) = '-';
+                else if (!strchr(valid_chars, *f))
+                        t = do_escape_char(*f, t);
+                else
+                        *(t++) = *f;
+        }
+
+        return t;
+}
+
 /**
  *  Convert a string to a unit name. /dev/blah is converted to dev-blah.device,
  *  /blah/blah is converted to blah-blah.mount, anything else is left alone,
@@ -507,54 +611,75 @@ int unit_name_from_dbus_path(const char *path, char **name) {
  *
  *  If @allow_globs, globs characters are preserved. Otherwise they are escaped.
  */
-char *unit_name_mangle_with_suffix(const char *name, enum unit_name_mangle allow_globs, const char *suffix) {
-        char *r, *t;
+int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret) {
+        char *s, *t;
+        int r;
 
         assert(name);
         assert(suffix);
-        assert(suffix[0] == '.');
+        assert(ret);
 
-        if (is_device_path(name))
-                return unit_name_from_path(name, ".device");
+        if (isempty(name)) /* We cannot mangle empty unit names to become valid, sorry. */
+                return -EINVAL;
 
-        if (path_is_absolute(name))
-                return unit_name_from_path(name, ".mount");
+        if (!unit_suffix_is_valid(suffix))
+                return -EINVAL;
 
-        r = new(char, strlen(name) * 4 + strlen(suffix) + 1);
-        if (!r)
-                return NULL;
+        if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
+                /* No mangling necessary... */
+                s = strdup(name);
+                if (!s)
+                        return -ENOMEM;
 
-        t = do_escape_mangle(name, allow_globs, r);
+                *ret = s;
+                return 0;
+        }
 
-        if (unit_name_to_type(name) < 0)
-                strcpy(t, suffix);
-        else
-                *t = 0;
+        if (is_device_path(name)) {
+                r = unit_name_from_path(name, ".device", ret);
+                if (r >= 0)
+                        return 1;
+                if (r != -EINVAL)
+                        return r;
+        }
 
-        return r;
-}
+        if (path_is_absolute(name)) {
+                r = unit_name_from_path(name, ".mount", ret);
+                if (r >= 0)
+                        return 1;
+                if (r != -EINVAL)
+                        return r;
+        }
 
-UnitType unit_name_to_type(const char *n) {
-        const char *e;
+        s = new(char, strlen(name) * 4 + strlen(suffix) + 1);
+        if (!s)
+                return -ENOMEM;
 
-        assert(n);
+        t = do_escape_mangle(name, allow_globs, s);
+        *t = 0;
 
-        e = strrchr(n, '.');
-        if (!e)
-                return _UNIT_TYPE_INVALID;
+        if (unit_name_to_type(s) < 0)
+                strcpy(t, suffix);
 
-        return unit_type_from_string(e + 1);
+        *ret = s;
+        return 1;
 }
 
-int build_subslice(const char *slice, const char*name, char **subslice) {
-        char *ret;
+int slice_build_subslice(const char *slice, const char*name, char **ret) {
+        char *subslice;
 
         assert(slice);
         assert(name);
-        assert(subslice);
+        assert(ret);
+
+        if (!unit_name_is_valid(slice, UNIT_NAME_PLAIN))
+                return -EINVAL;
+
+        if (!unit_prefix_is_valid(name))
+                return -EINVAL;
 
         if (streq(slice, "-.slice"))
-                ret = strappend(name, ".slice");
+                subslice = strappend(name, ".slice");
         else {
                 char *e;
 
@@ -562,17 +687,46 @@ int build_subslice(const char *slice, const char*name, char **subslice) {
                 if (!e)
                         return -EINVAL;
 
-                ret = new(char, (e - slice) + 1 + strlen(name) + 6 + 1);
-                if (!ret)
+                subslice = new(char, (e - slice) + 1 + strlen(name) + 6 + 1);
+                if (!subslice)
                         return -ENOMEM;
 
-                stpcpy(stpcpy(stpcpy(mempcpy(ret, slice, e - slice), "-"), name), ".slice");
+                stpcpy(stpcpy(stpcpy(mempcpy(subslice, slice, e - slice), "-"), name), ".slice");
         }
 
-        *subslice = ret;
+        *ret = subslice;
         return 0;
 }
 
+static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
+        [UNIT_SERVICE] = "service",
+        [UNIT_SOCKET] = "socket",
+        [UNIT_BUSNAME] = "busname",
+        [UNIT_TARGET] = "target",
+        [UNIT_SNAPSHOT] = "snapshot",
+        [UNIT_DEVICE] = "device",
+        [UNIT_MOUNT] = "mount",
+        [UNIT_AUTOMOUNT] = "automount",
+        [UNIT_SWAP] = "swap",
+        [UNIT_TIMER] = "timer",
+        [UNIT_PATH] = "path",
+        [UNIT_SLICE] = "slice",
+        [UNIT_SCOPE] = "scope"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType);
+
+static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
+        [UNIT_STUB] = "stub",
+        [UNIT_LOADED] = "loaded",
+        [UNIT_NOT_FOUND] = "not-found",
+        [UNIT_ERROR] = "error",
+        [UNIT_MERGED] = "merged",
+        [UNIT_MASKED] = "masked"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
+
 static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
         [UNIT_REQUIRES] = "Requires",
         [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable",
diff --git a/src/shared/unit-name.h b/src/shared/unit-name.h
index 6f139cc..057512c 100644
--- a/src/shared/unit-name.h
+++ b/src/shared/unit-name.h
@@ -107,61 +107,67 @@ enum UnitDependency {
         _UNIT_DEPENDENCY_INVALID = -1
 };
 
-const char *unit_type_to_string(UnitType i) _const_;
-UnitType unit_type_from_string(const char *s) _pure_;
+typedef enum UnitNameFlags {
+        UNIT_NAME_PLAIN = 1,      /* Allow foo.service */
+        UNIT_NAME_INSTANCE = 2,   /* Allow foo at bar.service */
+        UNIT_NAME_TEMPLATE = 4,   /* Allow foo at .service */
+        UNIT_NAME_ANY = UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE,
+} UnitNameFlags;
+
+bool unit_name_is_valid(const char *n, UnitNameFlags flags) _pure_;
+bool unit_prefix_is_valid(const char *p) _pure_;
+bool unit_instance_is_valid(const char *i) _pure_;
+bool unit_suffix_is_valid(const char *s) _pure_;
 
-const char *unit_load_state_to_string(UnitLoadState i) _const_;
-UnitLoadState unit_load_state_from_string(const char *s) _pure_;
+static inline int unit_prefix_and_instance_is_valid(const char *p) {
+        /* For prefix+instance and instance the same rules apply */
+        return unit_instance_is_valid(p);
+}
 
+int unit_name_to_prefix(const char *n, char **prefix);
 int unit_name_to_instance(const char *n, char **instance);
-char* unit_name_to_prefix(const char *n);
-char* unit_name_to_prefix_and_instance(const char *n);
-
-enum template_valid {
-        TEMPLATE_INVALID,
-        TEMPLATE_VALID,
-};
-
-bool unit_name_is_valid(const char *n, enum template_valid template_ok) _pure_;
-bool unit_prefix_is_valid(const char *p) _pure_;
-bool unit_instance_is_valid(const char *i) _pure_;
+int unit_name_to_prefix_and_instance(const char *n, char **ret);
 
 UnitType unit_name_to_type(const char *n) _pure_;
 
-char *unit_name_change_suffix(const char *n, const char *suffix);
+int unit_name_change_suffix(const char *n, const char *suffix, char **ret);
 
-char *unit_name_build(const char *prefix, const char *instance, const char *suffix);
+int unit_name_build(const char *prefix, const char *instance, const char *suffix, char **ret);
 
 char *unit_name_escape(const char *f);
-char *unit_name_unescape(const char *f);
-char *unit_name_path_escape(const char *f);
-char *unit_name_path_unescape(const char *f);
-
-bool unit_name_is_template(const char *n) _pure_;
-bool unit_name_is_instance(const char *n) _pure_;
+int unit_name_unescape(const char *f, char **ret);
+int unit_name_path_escape(const char *f, char **ret);
+int unit_name_path_unescape(const char *f, char **ret);
 
-char *unit_name_replace_instance(const char *f, const char *i);
+int unit_name_replace_instance(const char *f, const char *i, char **ret);
 
-char *unit_name_template(const char *f);
+int unit_name_template(const char *f, char **ret);
 
-char *unit_name_from_path(const char *path, const char *suffix);
-char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix);
-char *unit_name_to_path(const char *name);
+int unit_name_from_path(const char *path, const char *suffix, char **ret);
+int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret);
+int unit_name_to_path(const char *name, char **ret);
 
 char *unit_dbus_path_from_name(const char *name);
 int unit_name_from_dbus_path(const char *path, char **name);
 
-enum unit_name_mangle {
-        MANGLE_NOGLOB,
-        MANGLE_GLOB,
-};
+typedef enum UnitNameMangle {
+        UNIT_NAME_NOGLOB,
+        UNIT_NAME_GLOB,
+} UnitNameMangle;
 
-char *unit_name_mangle_with_suffix(const char *name, enum unit_name_mangle allow_globs, const char *suffix);
-static inline char *unit_name_mangle(const char *name, enum unit_name_mangle allow_globs) {
-        return unit_name_mangle_with_suffix(name, allow_globs, ".service");
+int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret);
+
+static inline int unit_name_mangle(const char *name, UnitNameMangle allow_globs, char **ret) {
+        return unit_name_mangle_with_suffix(name, allow_globs, ".service", ret);
 }
 
-int build_subslice(const char *slice, const char*name, char **subslice);
+int slice_build_subslice(const char *slice, const char*name, char **subslice);
+
+const char *unit_type_to_string(UnitType i) _const_;
+UnitType unit_type_from_string(const char *s) _pure_;
+
+const char *unit_load_state_to_string(UnitLoadState i) _const_;
+UnitLoadState unit_load_state_from_string(const char *s) _pure_;
 
 const char *unit_dependency_to_string(UnitDependency i) _const_;
 UnitDependency unit_dependency_from_string(const char *s) _pure_;
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index eb9737d..4f36ba8 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -1636,13 +1636,15 @@ static int list_dependencies(sd_bus *bus, char **args) {
         _cleanup_strv_free_ char **units = NULL;
         _cleanup_free_ char *unit = NULL;
         const char *u;
+        int r;
 
         assert(bus);
 
         if (args[1]) {
-                unit = unit_name_mangle(args[1], MANGLE_NOGLOB);
-                if (!unit)
-                        return log_oom();
+                r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &unit);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to mangle unit name: %m");
+
                 u = unit;
         } else
                 u = SPECIAL_DEFAULT_TARGET;
@@ -1938,9 +1940,9 @@ static int set_default(sd_bus *bus, char **args) {
         unsigned n_changes = 0;
         int r;
 
-        unit = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target");
-        if (!unit)
-                return log_oom();
+        r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
 
         if (!bus || avoid_bus()) {
                 r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes);
@@ -2257,7 +2259,7 @@ static int unit_find_paths(
         assert(fragment_path);
         assert(lp);
 
-        if (!avoid_bus_cache && !unit_name_is_template(unit_name)) {
+        if (!avoid_bus_cache && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
                 _cleanup_bus_message_unref_ sd_bus_message *unit_load_error = NULL;
                 _cleanup_free_ char *unit = NULL;
@@ -2323,24 +2325,23 @@ static int unit_find_paths(
 
                 names = set_new(NULL);
                 if (!names)
-                        return -ENOMEM;
+                        return log_oom();
 
                 r = set_put(names, unit_name);
                 if (r < 0)
-                        return r;
+                        return log_error_errno(r, "Failed to add unit name: %m");
 
                 r = unit_file_find_path(lp, unit_name, &path);
                 if (r < 0)
                         return r;
 
                 if (r == 0) {
-                        _cleanup_free_ char *template;
-
-                        template = unit_name_template(unit_name);
-                        if (!template)
-                                return log_oom();
+                        _cleanup_free_ char *template = NULL;
 
-                        if (!streq(template, unit_name)) {
+                        r = unit_name_template(unit_name, &template);
+                        if (r != -EINVAL)
+                                return log_error_errno(r, "Failed to determine template name: %m");
+                        if (r >= 0) {
                                 r = unit_file_find_path(lp, template, &path);
                                 if (r < 0)
                                         return r;
@@ -2382,9 +2383,9 @@ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states
 
         assert(name);
 
-        n = unit_name_mangle(name, MANGLE_NOGLOB);
-        if (!n)
-                return log_oom();
+        r = unit_name_mangle(name, UNIT_NAME_NOGLOB, &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
 
         /* We don't use unit_dbus_path_from_name() directly since we
          * don't want to load the unit if it isn't loaded. */
@@ -2439,9 +2440,9 @@ static int check_triggering_units(
         char **i;
         int r;
 
-        n = unit_name_mangle(name, MANGLE_NOGLOB);
-        if (!n)
-                return log_oom();
+        r = unit_name_mangle(name, UNIT_NAME_NOGLOB, &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
 
         path = unit_dbus_path_from_name(n);
         if (!path)
@@ -2595,17 +2596,17 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
 
         _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
         char **name;
-        int r = 0, i;
+        int r, i;
 
         STRV_FOREACH(name, names) {
                 char *t;
 
                 if (suffix)
-                        t = unit_name_mangle_with_suffix(*name, MANGLE_GLOB, suffix);
+                        r = unit_name_mangle_with_suffix(*name, UNIT_NAME_GLOB, suffix, &t);
                 else
-                        t = unit_name_mangle(*name, MANGLE_GLOB);
-                if (!t)
-                        return log_oom();
+                        r = unit_name_mangle(*name, UNIT_NAME_GLOB, &t);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to mangle name: %m");
 
                 if (string_is_glob(t))
                         r = strv_consume(&globs, t);
@@ -4673,9 +4674,9 @@ static int set_property(sd_bus *bus, char **args) {
         if (r < 0)
                 return bus_log_create_error(r);
 
-        n = unit_name_mangle(args[1], MANGLE_NOGLOB);
-        if (!n)
-                return log_oom();
+        r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
 
         r = sd_bus_message_append(m, "sb", n, arg_runtime);
         if (r < 0)
@@ -4721,12 +4722,15 @@ static int snapshot(sd_bus *bus, char **args) {
 
         polkit_agent_open_if_enabled();
 
-        if (strv_length(args) > 1)
-                n = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".snapshot");
-        else
+        if (strv_length(args) > 1) {
+                r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".snapshot", &n);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to generate unit name: %m");
+        } else {
                 n = strdup("");
-        if (!n)
-                return log_oom();
+                if (!n)
+                        return log_oom();
+        }
 
         r = sd_bus_call_method(
                         bus,
@@ -5217,25 +5221,29 @@ static int enable_sysv_units(const char *verb, char **args) {
 
 static int mangle_names(char **original_names, char ***mangled_names) {
         char **i, **l, **name;
+        int r;
 
-        l = new(char*, strv_length(original_names) + 1);
+        l = i = new(char*, strv_length(original_names) + 1);
         if (!l)
                 return log_oom();
 
-        i = l;
         STRV_FOREACH(name, original_names) {
 
                 /* When enabling units qualified path names are OK,
                  * too, hence allow them explicitly. */
 
-                if (is_path(*name))
+                if (is_path(*name)) {
                         *i = strdup(*name);
-                else
-                        *i = unit_name_mangle(*name, MANGLE_NOGLOB);
-
-                if (!*i) {
-                        strv_free(l);
-                        return log_oom();
+                        if (!*i) {
+                                strv_free(l);
+                                return log_oom();
+                        }
+                } else {
+                        r = unit_name_mangle(*name, UNIT_NAME_NOGLOB, i);
+                        if (r < 0) {
+                                strv_free(l);
+                                return log_error_errno(r, "Failed to mangle unit name: %m");
+                        }
                 }
 
                 i++;
@@ -5418,9 +5426,9 @@ static int add_dependency(sd_bus *bus, char **args) {
         if (!args[1])
                 return 0;
 
-        target = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target");
-        if (!target)
-                return log_oom();
+        r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &target);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
 
         r = mangle_names(args+2, &names);
         if (r < 0)
diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
index 714ce8f..0c839c2 100644
--- a/src/sysv-generator/sysv-generator.c
+++ b/src/sysv-generator/sysv-generator.c
@@ -310,11 +310,13 @@ static int sysv_translate_facility(const char *name, const char *filename, char
          * out whether something is a target or a service alias. */
 
         if (*name == '$') {
-                if (!unit_prefix_is_valid(n))
-                        return -EINVAL;
+                int k;
 
                 /* Facilities starting with $ are most likely targets */
-                r = unit_name_build(n, NULL, ".target");
+                k = unit_name_build(n, NULL, ".target", &r);
+                if (k < 0)
+                        return k;
+
         } else if (streq_ptr(n, filename))
                 /* Names equaling the file name of the services are redundant */
                 return 0;
diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c
index 7d882ae..5e34f18 100644
--- a/src/test/test-unit-name.c
+++ b/src/test/test-unit-name.c
@@ -33,79 +33,156 @@
 #include "specifier.h"
 #include "util.h"
 #include "macro.h"
+#include "path-util.h"
 #include "test-helper.h"
 
-static void test_replacements(void) {
-#define expect(pattern, repl, expected)                            \
-        {                                                          \
-                _cleanup_free_ char *t =                           \
-                        unit_name_replace_instance(pattern, repl); \
-                puts(t);                                           \
-                assert_se(streq(t, expected));                        \
-        }
+static void test_unit_name_is_valid(void) {
+        assert_se(unit_name_is_valid("foo.service", UNIT_NAME_ANY));
+        assert_se(unit_name_is_valid("foo.service", UNIT_NAME_PLAIN));
+        assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_INSTANCE));
+        assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_TEMPLATE));
+        assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
+
+        assert_se(unit_name_is_valid("foo at bar.service", UNIT_NAME_ANY));
+        assert_se(!unit_name_is_valid("foo at bar.service", UNIT_NAME_PLAIN));
+        assert_se(unit_name_is_valid("foo at bar.service", UNIT_NAME_INSTANCE));
+        assert_se(!unit_name_is_valid("foo at bar.service", UNIT_NAME_TEMPLATE));
+        assert_se(unit_name_is_valid("foo at bar.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
+
+        assert_se(unit_name_is_valid("foo at .service", UNIT_NAME_ANY));
+        assert_se(!unit_name_is_valid("foo at .service", UNIT_NAME_PLAIN));
+        assert_se(!unit_name_is_valid("foo at .service", UNIT_NAME_INSTANCE));
+        assert_se(unit_name_is_valid("foo at .service", UNIT_NAME_TEMPLATE));
+        assert_se(unit_name_is_valid("foo at .service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
+
+        assert_se(!unit_name_is_valid(".service", UNIT_NAME_ANY));
+        assert_se(!unit_name_is_valid("", UNIT_NAME_ANY));
+        assert_se(!unit_name_is_valid("foo.waldo", UNIT_NAME_ANY));
+        assert_se(!unit_name_is_valid("@.service", UNIT_NAME_ANY));
+        assert_se(!unit_name_is_valid("@piep.service", UNIT_NAME_ANY));
+}
 
-        expect("foo at .service", "waldo", "foo at waldo.service");
-        expect("foo at xyz.service", "waldo", "foo at waldo.service");
-        expect("xyz", "waldo", "xyz");
-        expect("", "waldo", "");
-        expect("foo.service", "waldo", "foo.service");
-        expect(".service", "waldo", ".service");
-        expect("foo@", "waldo", "foo at waldo");
-        expect("@bar", "waldo", "@waldo");
+static void test_u_n_r_i_one(const char *pattern, const char *repl, const char *expected, int ret) {
+        _cleanup_free_ char *t = NULL;
+        assert_se(unit_name_replace_instance(pattern, repl, &t) == ret);
+        puts(strna(t));
+        assert_se(streq_ptr(t, expected));
+}
 
+static void test_u_n_r_i(void) {
         puts("-------------------------------------------------");
-#undef expect
-#define expect(path, suffix, expected)                             \
-        {                                                          \
-                _cleanup_free_ char *k, *t =                       \
-                        unit_name_from_path(path, suffix);         \
-                puts(t);                                           \
-                k = unit_name_to_path(t);                          \
-                puts(k);                                           \
-                assert_se(streq(k, expected ? expected : path));      \
-        }
+        test_u_n_r_i_one("foo at .service", "waldo", "foo at waldo.service", 0);
+        test_u_n_r_i_one("foo at xyz.service", "waldo", "foo at waldo.service", 0);
+        test_u_n_r_i_one("xyz", "waldo", NULL, -EINVAL);
+        test_u_n_r_i_one("", "waldo", NULL, -EINVAL);
+        test_u_n_r_i_one("foo.service", "waldo", NULL, -EINVAL);
+        test_u_n_r_i_one(".service", "waldo", NULL, -EINVAL);
+        test_u_n_r_i_one("foo@", "waldo", NULL, -EINVAL);
+        test_u_n_r_i_one("@bar", "waldo", NULL, -EINVAL);
+}
 
-        expect("/waldo", ".mount", NULL);
-        expect("/waldo/quuix", ".mount", NULL);
-        expect("/waldo/quuix/", ".mount", "/waldo/quuix");
-        expect("/", ".mount", NULL);
-        expect("///", ".mount", "/");
+static void test_u_n_f_p_one(const char *path, const char *suffix, const char *expected, int ret) {
+        _cleanup_free_ char *t = NULL;
 
-        puts("-------------------------------------------------");
-#undef expect
-#define expect(pattern, path, suffix, expected)                              \
-        {                                                                    \
-                _cleanup_free_ char *t =                                     \
-                        unit_name_from_path_instance(pattern, path, suffix); \
-                puts(t);                                                     \
-                assert_se(streq(t, expected));                                  \
-        }
+        assert_se(unit_name_from_path(path, suffix, &t) == ret);
+        puts(strna(t));
+        assert_se(streq_ptr(t, expected));
 
-        expect("waldo", "/waldo", ".mount", "waldo at waldo.mount");
-        expect("waldo", "/waldo////quuix////", ".mount", "waldo at waldo-quuix.mount");
-        expect("waldo", "/", ".mount", "waldo at -.mount");
-        expect("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount");
+        if (t) {
+                _cleanup_free_ char *k = NULL;
+                assert_se(unit_name_to_path(t, &k) == 0);
+                puts(strna(k));
+                assert_se(path_equal(k, isempty(path) ? "/" : path));
+        }
+}
 
+static void test_u_n_f_p(void) {
         puts("-------------------------------------------------");
-#undef expect
-#define expect(pattern)                                                     \
-        {                                                                   \
-                _cleanup_free_ char *k, *t;                                 \
-                assert_se(t = unit_name_mangle(pattern, MANGLE_NOGLOB));    \
-                assert_se(k = unit_name_mangle(t, MANGLE_NOGLOB));          \
-                puts(t);                                                    \
-                assert_se(streq(t, k));                                     \
+        test_u_n_f_p_one("/waldo", ".mount", "waldo.mount", 0);
+        test_u_n_f_p_one("/waldo/quuix", ".mount", "waldo-quuix.mount", 0);
+        test_u_n_f_p_one("/waldo/quuix/", ".mount", "waldo-quuix.mount", 0);
+        test_u_n_f_p_one("", ".mount", "-.mount", 0);
+        test_u_n_f_p_one("/", ".mount", "-.mount", 0);
+        test_u_n_f_p_one("///", ".mount", "-.mount", 0);
+        test_u_n_f_p_one("/foo/../bar", ".mount", NULL, -EINVAL);
+        test_u_n_f_p_one("/foo/./bar", ".mount", NULL, -EINVAL);
+}
+
+static void test_u_n_f_p_i_one(const char *pattern, const char *path, const char *suffix, const char *expected, int ret) {
+        _cleanup_free_ char *t = NULL;
+
+        assert_se(unit_name_from_path_instance(pattern, path, suffix, &t) == ret);
+        puts(strna(t));
+        assert_se(streq_ptr(t, expected));
+
+        if (t) {
+                _cleanup_free_ char *k = NULL, *v = NULL;
+
+                assert_se(unit_name_to_instance(t, &k) > 0);
+                assert_se(unit_name_path_unescape(k, &v) == 0);
+                assert_se(path_equal(v, isempty(path) ? "/" : path));
         }
+}
 
-        expect("/home");
-        expect("/dev/sda");
-        expect("üxknürz.service");
-        expect("foobar-meh...waldi.service");
-        expect("_____####----.....service");
-        expect("_____##@;;;,,,##----.....service");
-        expect("xxx@@@@/////\\\\\\\\\\yyy.service");
+static void test_u_n_f_p_i(void) {
+        puts("-------------------------------------------------");
 
-#undef expect
+        test_u_n_f_p_i_one("waldo", "/waldo", ".mount", "waldo at waldo.mount", 0);
+        test_u_n_f_p_i_one("waldo", "/waldo////quuix////", ".mount", "waldo at waldo-quuix.mount", 0);
+        test_u_n_f_p_i_one("waldo", "/", ".mount", "waldo at -.mount", 0);
+        test_u_n_f_p_i_one("waldo", "", ".mount", "waldo at -.mount", 0);
+        test_u_n_f_p_i_one("waldo", "///", ".mount", "waldo at -.mount", 0);
+        test_u_n_f_p_i_one("waldo", "..", ".mount", NULL, -EINVAL);
+        test_u_n_f_p_i_one("waldo", "/foo", ".waldi", NULL, -EINVAL);
+        test_u_n_f_p_i_one("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount", 0);
+}
+
+static void test_u_n_t_p_one(const char *unit, const char *path, int ret) {
+        _cleanup_free_ char *p = NULL;
+
+        assert_se(unit_name_to_path(unit, &p) == ret);
+        assert_se(streq_ptr(path, p));
+}
+
+static void test_u_n_t_p(void) {
+        test_u_n_t_p_one("home.mount", "/home", 0);
+        test_u_n_t_p_one("home-lennart.mount", "/home/lennart", 0);
+        test_u_n_t_p_one("home-lennart-.mount", NULL, -EINVAL);
+        test_u_n_t_p_one("-home-lennart.mount", NULL, -EINVAL);
+        test_u_n_t_p_one("-home--lennart.mount", NULL, -EINVAL);
+        test_u_n_t_p_one("home-..-lennart.mount", NULL, -EINVAL);
+        test_u_n_t_p_one("", NULL, -EINVAL);
+        test_u_n_t_p_one("home/foo", NULL, -EINVAL);
+}
+
+static void test_u_n_m_one(const char *pattern, const char *expect, int ret) {
+        _cleanup_free_ char *t = NULL;
+
+        assert_se(unit_name_mangle(pattern, UNIT_NAME_NOGLOB, &t) == ret);
+        puts(strna(t));
+        assert_se(streq_ptr(t, expect));
+
+        if (t) {
+                _cleanup_free_ char *k = NULL;
+
+                assert_se(unit_name_is_valid(t, UNIT_NAME_ANY));
+
+                assert_se(unit_name_mangle(t, UNIT_NAME_NOGLOB, &k) == 0);
+                assert_se(streq_ptr(t, k));
+        }
+}
+
+static void test_u_n_m(void) {
+        puts("-------------------------------------------------");
+        test_u_n_m_one("foo.service", "foo.service", 0);
+        test_u_n_m_one("/home", "home.mount", 1);
+        test_u_n_m_one("/dev/sda", "dev-sda.device", 1);
+        test_u_n_m_one("üxknürz.service", "\\xc3\\xbcxkn\\xc3\\xbcrz.service", 1);
+        test_u_n_m_one("foobar-meh...waldi.service", "foobar-meh...waldi.service", 0);
+        test_u_n_m_one("_____####----.....service", "_____\\x23\\x23\\x23\\x23----.....service", 1);
+        test_u_n_m_one("_____##@;;;,,,##----.....service", "_____\\x23\\x23@\\x3b\\x3b\\x3b\\x2c\\x2c\\x2c\\x23\\x23----.....service", 1);
+        test_u_n_m_one("xxx@@@@/////\\\\\\\\\\yyy.service", "xxx@@@@-----\\\\\\\\\\yyy.service", 1);
+        test_u_n_m_one("", NULL, -EINVAL);
 }
 
 static int test_unit_printf(void) {
@@ -224,64 +301,49 @@ static void test_unit_prefix_is_valid(void) {
 }
 
 static void test_unit_name_change_suffix(void) {
-        char *r;
+        char *t;
 
-        r = unit_name_change_suffix("foo.bar", ".service");
-        assert_se(r);
-        assert_se(streq(r, "foo.service"));
-        free(r);
+        assert_se(unit_name_change_suffix("foo.mount", ".service", &t) == 0);
+        assert_se(streq(t, "foo.service"));
+        free(t);
 
-        r = unit_name_change_suffix("foo at stuff.bar", ".boo");
-        assert_se(r);
-        assert_se(streq(r, "foo at stuff.boo"));
-        free(r);
+        assert_se(unit_name_change_suffix("foo at stuff.service", ".socket", &t) == 0);
+        assert_se(streq(t, "foo at stuff.socket"));
+        free(t);
 }
 
 static void test_unit_name_build(void) {
-        char *r;
-
-        r = unit_name_build("foo", "bar", ".service");
-        assert_se(r);
-        assert_se(streq(r, "foo at bar.service"));
-        free(r);
+        char *t;
 
-        r = unit_name_build("fo0-stUff_b", "bar", ".mount");
-        assert_se(r);
-        assert_se(streq(r, "fo0-stUff_b at bar.mount"));
-        free(r);
-
-        r = unit_name_build("foo", NULL, ".service");
-        assert_se(r);
-        assert_se(streq(r, "foo.service"));
-        free(r);
-}
+        assert_se(unit_name_build("foo", "bar", ".service", &t) == 0);
+        assert_se(streq(t, "foo at bar.service"));
+        free(t);
 
-static void test_unit_name_is_instance(void) {
-        assert_se(unit_name_is_instance("a at b.service"));
-        assert_se(unit_name_is_instance("a-c_c01Aj at b05Dii_-oioi.service"));
+        assert_se(unit_name_build("fo0-stUff_b", "bar", ".mount", &t) == 0);
+        assert_se(streq(t, "fo0-stUff_b at bar.mount"));
+        free(t);
 
-        assert_se(!unit_name_is_instance("a.service"));
-        assert_se(!unit_name_is_instance("a at .service"));
-        assert_se(!unit_name_is_instance("junk"));
-        assert_se(!unit_name_is_instance(""));
+        assert_se(unit_name_build("foo", NULL, ".service", &t) == 0);
+        assert_se(streq(t, "foo.service"));
+        free(t);
 }
 
 static void test_build_subslice(void) {
         char *a;
         char *b;
 
-        assert_se(build_subslice("-.slice", "foo", &a) >= 0);
-        assert_se(build_subslice(a, "bar", &b) >= 0);
+        assert_se(slice_build_subslice("-.slice", "foo", &a) >= 0);
+        assert_se(slice_build_subslice(a, "bar", &b) >= 0);
         free(a);
-        assert_se(build_subslice(b, "barfoo", &a) >= 0);
+        assert_se(slice_build_subslice(b, "barfoo", &a) >= 0);
         free(b);
-        assert_se(build_subslice(a, "foobar", &b) >= 0);
+        assert_se(slice_build_subslice(a, "foobar", &b) >= 0);
         free(a);
         assert_se(streq(b, "foo-bar-barfoo-foobar.slice"));
         free(b);
 
-        assert_se(build_subslice("foo.service", "bar", &a) < 0);
-        assert_se(build_subslice("foo", "bar", &a) < 0);
+        assert_se(slice_build_subslice("foo.service", "bar", &a) < 0);
+        assert_se(slice_build_subslice("foo", "bar", &a) < 0);
 }
 
 static void test_unit_name_to_instance(void) {
@@ -298,13 +360,13 @@ static void test_unit_name_to_instance(void) {
         assert_se(streq(instance, ""));
         free(instance);
 
-        r = unit_name_to_instance("fo0-stUff_b at b.e", &instance);
+        r = unit_name_to_instance("fo0-stUff_b at b.service", &instance);
         assert_se(r >= 0);
         assert_se(streq(instance, "b"));
         free(instance);
 
-        r = unit_name_to_instance("foo.bar", &instance);
-        assert_se(r >= 0);
+        r = unit_name_to_instance("foo.service", &instance);
+        assert_se(r == 0);
         assert_se(!instance);
 
         r = unit_name_to_instance("fooj at unk", &instance);
@@ -322,43 +384,37 @@ static void test_unit_name_escape(void) {
         assert_se(streq(r, "ab\\x2b\\x2dc.a-bc\\x40foo.service"));
 }
 
-static void test_unit_name_template(void) {
-#define expect(name, expected) \
-        { \
-                _cleanup_free_ char *f = NULL; \
-                f = unit_name_template(name); \
-                assert_se(f); \
-                printf("got: %s, expected: %s\n", f, expected); \
-                assert_se(streq(f, expected)); \
-        }
-        expect("foo at bar.service", "foo at .service")
-        expect("foo.mount", "foo.mount")
-#undef expect
-}
 
-static void test_unit_name_is_template(void) {
-        assert_se(unit_name_is_template("foo at .service"));
-        assert_se(unit_name_is_template("bar at .path"));
+static void test_u_n_t_one(const char *name, const char *expected, int ret) {
+        _cleanup_free_ char *f = NULL;
 
-        assert_se(!unit_name_is_template("bar at i.mount"));
-        assert_se(!unit_name_is_template("bar at foobbbb.service"));
-        assert_se(!unit_name_is_template("barfoo.service"));
+        assert_se(unit_name_template(name, &f) == ret);
+        printf("got: %s, expected: %s\n", strna(f), strna(expected));
+        assert_se(streq_ptr(f, expected));
+}
+
+static void test_unit_name_template(void) {
+        test_u_n_t_one("foo at bar.service", "foo at .service", 0);
+        test_u_n_t_one("foo.mount", NULL, -EINVAL);
 }
 
 int main(int argc, char* argv[]) {
         int rc = 0;
-        test_replacements();
+        test_unit_name_is_valid();
+        test_u_n_r_i();
+        test_u_n_f_p();
+        test_u_n_f_p_i();
+        test_u_n_m();
+        test_u_n_t_p();
         TEST_REQ_RUNNING_SYSTEMD(rc = test_unit_printf());
         test_unit_instance_is_valid();
         test_unit_prefix_is_valid();
         test_unit_name_change_suffix();
         test_unit_name_build();
-        test_unit_name_is_instance();
         test_build_subslice();
         test_unit_name_to_instance();
         test_unit_name_escape();
         test_unit_name_template();
-        test_unit_name_is_template();
 
         return rc;
 }

commit 6442185ab674cc202d63c18605057b9a51ca2722
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Apr 30 19:44:10 2015 +0200

    util: be a bit safer in path_is_safe()
    
    We should be more strict when verifying paths with path_is_safe() for
    potentially dangerous constructs, and that includes lengths of
    PATH_MAX-1 and larger. Be more accurate here.

diff --git a/src/shared/util.c b/src/shared/util.c
index 2c7254e..d9bd34b 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -3917,7 +3917,7 @@ bool path_is_safe(const char *p) {
         if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
                 return false;
 
-        if (strlen(p) > PATH_MAX)
+        if (strlen(p)+1 > PATH_MAX)
                 return false;
 
         /* The following two checks are not really dangerous, but hey, they still are confusing */

commit e66e5b612a9e5921d79a6aedab4983e33dff8cb1
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Apr 30 19:42:48 2015 +0200

    cgroup-util: be more strict when processing slice unit names

diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index 1306cc1..b5e4094 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -1663,11 +1663,17 @@ int cg_slice_to_path(const char *unit, char **ret) {
                 return -ENOMEM;
 
         dash = strchr(p, '-');
+
+        /* Don't allow initial dashes */
+        if (dash == p)
+                return -EINVAL;
+
         while (dash) {
                 _cleanup_free_ char *escaped = NULL;
                 char n[dash - p + sizeof(".slice")];
 
-                if (isempty(dash + 1))
+                /* Don't allow trailing or double dashes */
+                if (dash[1] == 0 || dash[1] == '-')
                         return -EINVAL;
 
                 strcpy(stpncpy(n, p, dash - p), ".slice");
diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c
index efe99cb..4a89f64 100644
--- a/src/test/test-cgroup-util.c
+++ b/src/test/test-cgroup-util.c
@@ -274,7 +274,7 @@ static void test_slice_to_path(void) {
         test_slice_to_path_one("-foo-.slice", NULL, -EINVAL);
         test_slice_to_path_one("-foo.slice", NULL, -EINVAL);
         test_slice_to_path_one("foo-.slice", NULL, -EINVAL);
-        test_slice_to_path_one("foo--bar.slice", "foo.slice/foo-.slice/foo--bar.slice", 0);
+        test_slice_to_path_one("foo--bar.slice", NULL, -EINVAL);
         test_slice_to_path_one("foo.slice/foo--bar.slice", NULL, -EINVAL);
         test_slice_to_path_one("a-b.slice", "a.slice/a-b.slice", 0);
         test_slice_to_path_one("a-b-c-d-e.slice", "a.slice/a-b.slice/a-b-c.slice/a-b-c-d.slice/a-b-c-d-e.slice", 0);



More information about the systemd-commits mailing list