src/core/timer.h \
        src/core/path.c \
        src/core/path.h \
+       src/core/slice.c \
+       src/core/slice.h \
        src/core/load-dropin.c \
        src/core/load-dropin.h \
        src/core/execute.c \
        src/core/dbus-kill.h \
        src/core/dbus-path.c \
        src/core/dbus-path.h \
+       src/core/dbus-slice.c \
+       src/core/dbus-slice.h \
        src/core/cgroup.c \
        src/core/cgroup.h \
        src/core/selinux-access.c \
 
 
 Features:
 
+* when a service changes state make reflect that in the
+  RUNNING/LISTENING states of its socket
+
+* slices:
+  - fix libsystemd-login to handle slices properly
+  - add option to pam_systemd to move login session into a slice
+  - add call to logind's dbus intrface to register a machine (also, calls for listing them)
+
+* when recursively showing the cgroup hierarchy, optionally also show
+  the hierarchies of child processes
+
 * document logic of auto/noauto and fail/nofail in fstab in systemd.mount or systemd-fstab-generator man page
 
 * we should properly escape hostnames we add into dbus server strings
 
         }
 
         if (m->running_as == SYSTEMD_SYSTEM)
-                suffix = "/system";
+                suffix = NULL;
         else {
                 sprintf(suffix_buffer, "/systemd-%lu", (unsigned long) getpid());
                 suffix = suffix_buffer;
         }
 
         free(m->cgroup_hierarchy);
-        if (endswith(current, suffix)) {
+        if (!suffix || endswith(current, suffix)) {
                 /* We probably got reexecuted and can continue to use our root cgroup */
                 m->cgroup_hierarchy = current;
                 current = NULL;
 
--- /dev/null
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "dbus-unit.h"
+#include "dbus-slice.h"
+#include "dbus-common.h"
+#include "selinux-access.h"
+
+#define BUS_SLICE_INTERFACE                                             \
+        " <interface name=\"org.freedesktop.systemd1.Slice\">\n"        \
+        BUS_UNIT_CGROUP_INTERFACE                                       \
+        " </interface>\n"
+
+#define INTROSPECTION                                                   \
+        DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                       \
+        "<node>\n"                                                      \
+        BUS_UNIT_INTERFACE                                              \
+        BUS_SLICE_INTERFACE                                             \
+        BUS_PROPERTIES_INTERFACE                                        \
+        BUS_PEER_INTERFACE                                              \
+        BUS_INTROSPECTABLE_INTERFACE                                    \
+        "</node>\n"
+
+#define INTERFACES_LIST                              \
+        BUS_UNIT_INTERFACES_LIST                     \
+        "org.freedesktop.systemd1.Slice\0"
+
+const char bus_slice_interface[] _introspect_("Slice") = BUS_SLICE_INTERFACE;
+
+DBusHandlerResult bus_slice_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
+        const BusBoundProperties bps[] = {
+                { "org.freedesktop.systemd1.Unit",  bus_unit_properties,             u },
+                { "org.freedesktop.systemd1.Slice", bus_unit_cgroup_properties,      u },
+                { NULL, }
+        };
+
+        SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
+
+        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
+}
 
--- /dev/null
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dbus/dbus.h>
+
+#include "unit.h"
+
+DBusHandlerResult bus_slice_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
+
+extern const char bus_slice_interface[];
 
 $1.LimitNICE,                    config_parse_limit,                 RLIMIT_NICE,                   offsetof($1, exec_context.rlimit)
 $1.LimitRTPRIO,                  config_parse_limit,                 RLIMIT_RTPRIO,                 offsetof($1, exec_context.rlimit)
 $1.LimitRTTIME,                  config_parse_limit,                 RLIMIT_RTTIME,                 offsetof($1, exec_context.rlimit)
-$1.ControlGroup,                 config_parse_unit_cgroup,           0,                             0
-$1.ControlGroupAttribute,        config_parse_unit_cgroup_attr,      0,                             0
-$1.CPUShares,                    config_parse_unit_cgroup_attr_pretty, 0,                           0
-$1.MemoryLimit,                  config_parse_unit_cgroup_attr_pretty, 0,                           0
-$1.MemorySoftLimit,              config_parse_unit_cgroup_attr_pretty, 0,                           0
-$1.DeviceAllow,                  config_parse_unit_cgroup_attr_pretty, 0,                           0
-$1.DeviceDeny,                   config_parse_unit_cgroup_attr_pretty, 0,                           0
-$1.BlockIOWeight,                config_parse_unit_cgroup_attr_pretty, 0,                           0
-$1.BlockIOReadBandwidth,         config_parse_unit_cgroup_attr_pretty, 0,                           0
-$1.BlockIOWriteBandwidth,        config_parse_unit_cgroup_attr_pretty, 0,                           0
 $1.ReadWriteDirectories,         config_parse_path_strv,             0,                             offsetof($1, exec_context.read_write_dirs)
 $1.ReadOnlyDirectories,          config_parse_path_strv,             0,                             offsetof($1, exec_context.read_only_dirs)
 $1.InaccessibleDirectories,      config_parse_path_strv,             0,                             offsetof($1, exec_context.inaccessible_dirs)
 $1.KillMode,                     config_parse_kill_mode,             0,                             offsetof($1, kill_context.kill_mode)
 $1.KillSignal,                   config_parse_kill_signal,           0,                             offsetof($1, kill_context.kill_signal)'
 )m4_dnl
+m4_define(`CGROUP_CONTEXT_CONFIG_ITEMS',
+`$1.ControlGroup,                 config_parse_unit_cgroup,          0,                             0
+$1.ControlGroupAttribute,        config_parse_unit_cgroup_attr,      0,                             0
+$1.CPUShares,                    config_parse_unit_cgroup_attr_pretty, 0,                           0
+$1.MemoryLimit,                  config_parse_unit_cgroup_attr_pretty, 0,                           0
+$1.MemorySoftLimit,              config_parse_unit_cgroup_attr_pretty, 0,                           0
+$1.DeviceAllow,                  config_parse_unit_cgroup_attr_pretty, 0,                           0
+$1.DeviceDeny,                   config_parse_unit_cgroup_attr_pretty, 0,                           0
+$1.BlockIOWeight,                config_parse_unit_cgroup_attr_pretty, 0,                           0
+$1.BlockIOReadBandwidth,         config_parse_unit_cgroup_attr_pretty, 0,                           0
+$1.BlockIOWriteBandwidth,        config_parse_unit_cgroup_attr_pretty, 0,                           0'
+)m4_dnl
 Unit.Description,                config_parse_unit_string_printf,    0,                             offsetof(Unit, description)
 Unit.Documentation,              config_parse_documentation,         0,                             offsetof(Unit, documentation)
 Unit.SourcePath,                 config_parse_path,                  0,                             offsetof(Unit, source_path)
 Unit.IgnoreOnIsolate,            config_parse_bool,                  0,                             offsetof(Unit, ignore_on_isolate)
 Unit.IgnoreOnSnapshot,           config_parse_bool,                  0,                             offsetof(Unit, ignore_on_snapshot)
 Unit.JobTimeoutSec,              config_parse_sec,                   0,                             offsetof(Unit, job_timeout)
+Unit.Slice,                      config_parse_unit_slice,            0,                             0
 Unit.ConditionPathExists,        config_parse_unit_condition_path,   CONDITION_PATH_EXISTS,         0
 Unit.ConditionPathExistsGlob,    config_parse_unit_condition_path,   CONDITION_PATH_EXISTS_GLOB,    0
 Unit.ConditionPathIsDirectory,   config_parse_unit_condition_path,   CONDITION_PATH_IS_DIRECTORY,   0
 Service.Sockets,                 config_parse_service_sockets,       0,                             0
 Service.FsckPassNo,              config_parse_fsck_passno,           0,                             offsetof(Service, fsck_passno)
 EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
+CGROUP_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
 KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
 m4_dnl
 Socket.ListenStream,             config_parse_socket_listen,         SOCKET_SOCKET,                 0
 Socket.SmackLabelIPIn,           config_parse_string,                0,                             offsetof(Socket, smack_ip_in)
 Socket.SmackLabelIPOut,          config_parse_string,                0,                             offsetof(Socket, smack_ip_out)
 EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
+CGROUP_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
 KILL_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
 m4_dnl
 Mount.What,                      config_parse_string,                0,                             offsetof(Mount, parameters_fragment.what)
 Mount.TimeoutSec,                config_parse_sec,                   0,                             offsetof(Mount, timeout_usec)
 Mount.DirectoryMode,             config_parse_mode,                  0,                             offsetof(Mount, directory_mode)
 EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
+CGROUP_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
 KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
 m4_dnl
 Automount.Where,                 config_parse_path,                  0,                             offsetof(Automount, where)
 Swap.Priority,                   config_parse_int,                   0,                             offsetof(Swap, parameters_fragment.priority)
 Swap.TimeoutSec,                 config_parse_sec,                   0,                             offsetof(Swap, timeout_usec)
 EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
+CGROUP_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
 KILL_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
 m4_dnl
 Timer.OnCalendar,                config_parse_timer,                 0,                             0
 Path.Unit,                       config_parse_trigger_unit,          0,                             0
 Path.MakeDirectory,              config_parse_bool,                  0,                             offsetof(Path, make_directory)
 Path.DirectoryMode,              config_parse_mode,                  0,                             offsetof(Path, directory_mode)
+m4_dnl
+CGROUP_CONTEXT_CONFIG_ITEMS(Slice)m4_dnl
 m4_dnl The [Install] section is ignored here.
 Install.Alias,                   NULL,                               0,                             0
 Install.WantedBy,                NULL,                               0,                             0
 
         return 0;
 }
 
+int config_parse_unit_slice(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        _cleanup_free_ char *k = NULL;
+        Unit *u = userdata, *slice;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(u);
+
+        k = unit_name_printf(u, rvalue);
+        if (!k)
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
+
+        r = manager_load_unit(u->manager, k ? k : rvalue, NULL, NULL, &slice);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, -r,
+                           "Failed to load slice unit %s. Ignoring.", k ? k : rvalue);
+                return 0;
+        }
+
+        if (slice->type != UNIT_SLICE) {
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Slice unit %s is not a slice. Ignoring.", k ? k : rvalue);
+                return 0;
+        }
+
+        unit_ref_set(&u->slice, slice);
+        return 0;
+}
+
 #define FOLLOW_MAX 8
 
 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
                 { config_parse_unit_condition_path,   "CONDITION" },
                 { config_parse_unit_condition_string, "CONDITION" },
                 { config_parse_unit_condition_null,   "CONDITION" },
+                { config_parse_unit_slice,            "SLICE" },
         };
 
         const char *prev = NULL;
 
 int config_parse_unit_requires_mounts_for(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_syscall_filter(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 int config_parse_environ(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unit_slice(const char *unit, const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
 
 /* gperf prototypes */
 const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
 
                         return r;
         }
 
+        r = unit_add_default_slice(u);
+        if (r < 0)
+                return r;
+
         r = unit_add_default_cgroups(u);
         if (r < 0)
                 return r;
 
                 if (r < 0)
                         return r;
 
+                r = unit_add_default_slice(u);
+                if (r < 0)
+                        return r;
+
                 r = unit_add_default_cgroups(u);
                 if (r < 0)
                         return r;
 
--- /dev/null
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "unit.h"
+#include "slice.h"
+#include "load-fragment.h"
+#include "log.h"
+#include "dbus-slice.h"
+#include "special.h"
+#include "unit-name.h"
+
+static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
+        [SLICE_DEAD] = UNIT_INACTIVE,
+        [SLICE_ACTIVE] = UNIT_ACTIVE
+};
+
+static void slice_set_state(Slice *t, SliceState state) {
+        SliceState old_state;
+        assert(t);
+
+        old_state = t->state;
+        t->state = state;
+
+        if (state != old_state)
+                log_debug("%s changed %s -> %s",
+                          UNIT(t)->id,
+                          slice_state_to_string(old_state),
+                          slice_state_to_string(state));
+
+        unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
+}
+
+static int slice_add_slice_link(Slice *s) {
+        char *a, *dash;
+        int r;
+        Unit *parent;
+
+        assert(s);
+
+        if (UNIT_DEREF(UNIT(s)->slice))
+                return 0;
+
+        a = strdupa(UNIT(s)->id);
+
+        dash = strrchr(a, '-');
+        if (!dash)
+                return 0;
+
+        strcpy(dash, ".slice");
+
+        r = manager_load_unit(UNIT(s)->manager, a, NULL, NULL, &parent);
+        if (r < 0)
+                return r;
+
+        unit_ref_set(&UNIT(s)->slice, parent);
+        return 0;
+}
+
+static int slice_add_default_dependencies(Slice *s) {
+        int r;
+
+        assert(s);
+
+        /* Make sure slices are unloaded on shutdown */
+        r = unit_add_dependency_by_name(UNIT(s), UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int slice_verify(Slice *s) {
+        assert(s);
+
+        if (UNIT(s)->load_state != UNIT_LOADED)
+                return 0;
+
+        if (UNIT_DEREF(UNIT(s)->slice)) {
+                char *a, *dash;
+
+                a = strdupa(UNIT(s)->id);
+                dash = strrchr(a, '-');
+                if (dash) {
+                        strcpy(dash, ".slice");
+
+                        if (!unit_has_name(UNIT_DEREF(UNIT(s)->slice), a)) {
+                                log_error_unit(UNIT(s)->id,
+                                               "%s located outside its parent slice. Refusing.", UNIT(s)->id);
+                                return -EINVAL;
+                        }
+                }
+        }
+
+        return 0;
+}
+
+static int slice_load(Unit *u) {
+        Slice *s = SLICE(u);
+        int r;
+
+        assert(s);
+
+        r = unit_load_fragment_and_dropin(u);
+        if (r < 0)
+                return r;
+
+        /* This is a new unit? Then let's add in some extras */
+        if (u->load_state == UNIT_LOADED) {
+
+                r = slice_add_slice_link(s);
+                if (r < 0)
+                        return r;
+
+                if (u->default_dependencies) {
+                        r = slice_add_default_dependencies(s);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = unit_add_default_cgroups(UNIT(s));
+                if (r < 0)
+                        return r;
+        }
+
+        return slice_verify(s);
+}
+
+static int slice_coldplug(Unit *u) {
+        Slice *t = SLICE(u);
+
+        assert(t);
+        assert(t->state == SLICE_DEAD);
+
+        if (t->deserialized_state != t->state)
+                slice_set_state(t, t->deserialized_state);
+
+        return 0;
+}
+
+static void slice_dump(Unit *u, FILE *f, const char *prefix) {
+        Slice *t = SLICE(u);
+
+        assert(t);
+        assert(f);
+
+        fprintf(f,
+                "%sSlice State: %s\n",
+                prefix, slice_state_to_string(t->state));
+}
+
+static int slice_start(Unit *u) {
+        Slice *t = SLICE(u);
+        int r;
+
+        assert(t);
+        assert(t->state == SLICE_DEAD);
+
+        r = cgroup_bonding_realize_list(u->cgroup_bondings);
+        if (r < 0)
+                return r;
+
+        cgroup_attribute_apply_list(u->cgroup_attributes, u->cgroup_bondings);
+
+        slice_set_state(t, SLICE_ACTIVE);
+        return 0;
+}
+
+static int slice_stop(Unit *u) {
+        Slice *t = SLICE(u);
+
+        assert(t);
+        assert(t->state == SLICE_ACTIVE);
+
+        /* We do not need to trim the cgroup explicitly, unit_notify()
+         * will do that for us anyway. */
+
+        slice_set_state(t, SLICE_DEAD);
+        return 0;
+}
+
+static int slice_kill(Unit *u, KillWho who, int signo, DBusError *error) {
+        return unit_kill_common(u, who, signo, -1, -1, error);
+}
+
+static int slice_serialize(Unit *u, FILE *f, FDSet *fds) {
+        Slice *s = SLICE(u);
+
+        assert(s);
+        assert(f);
+        assert(fds);
+
+        unit_serialize_item(u, f, "state", slice_state_to_string(s->state));
+        return 0;
+}
+
+static int slice_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
+        Slice *s = SLICE(u);
+
+        assert(u);
+        assert(key);
+        assert(value);
+        assert(fds);
+
+        if (streq(key, "state")) {
+                SliceState state;
+
+                state = slice_state_from_string(value);
+                if (state < 0)
+                        log_debug("Failed to parse state value %s", value);
+                else
+                        s->deserialized_state = state;
+
+        } else
+                log_debug("Unknown serialization key '%s'", key);
+
+        return 0;
+}
+
+_pure_ static UnitActiveState slice_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[SLICE(u)->state];
+}
+
+_pure_ static const char *slice_sub_state_to_string(Unit *u) {
+        assert(u);
+
+        return slice_state_to_string(SLICE(u)->state);
+}
+
+static const char* const slice_state_table[_SLICE_STATE_MAX] = {
+        [SLICE_DEAD] = "dead",
+        [SLICE_ACTIVE] = "active"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState);
+
+const UnitVTable slice_vtable = {
+        .object_size = sizeof(Slice),
+        .sections =
+                "Unit\0"
+                "Slice\0"
+                "Install\0",
+
+        .no_alias = true,
+        .no_instances = true,
+
+        .load = slice_load,
+        .coldplug = slice_coldplug,
+
+        .dump = slice_dump,
+
+        .start = slice_start,
+        .stop = slice_stop,
+
+        .kill = slice_kill,
+
+        .serialize = slice_serialize,
+        .deserialize_item = slice_deserialize_item,
+
+        .active_state = slice_active_state,
+        .sub_state_to_string = slice_sub_state_to_string,
+
+        .bus_interface = "org.freedesktop.systemd1.Slice",
+        .bus_message_handler = bus_slice_message_handler,
+
+        .status_message_formats = {
+                .finished_start_job = {
+                        [JOB_DONE]       = "Installed slice %s.",
+                        [JOB_DEPENDENCY] = "Dependency failed for %s.",
+                },
+                .finished_stop_job = {
+                        [JOB_DONE]       = "Deinstalled slice %s.",
+                },
+        },
+};
 
--- /dev/null
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef struct Slice Slice;
+
+#include "unit.h"
+
+typedef enum SliceState {
+        SLICE_DEAD,
+        SLICE_ACTIVE,
+        _SLICE_STATE_MAX,
+        _SLICE_STATE_INVALID = -1
+} SliceState;
+
+struct Slice {
+        Unit meta;
+
+        SliceState state, deserialized_state;
+};
+
+extern const UnitVTable slice_vtable;
+
+const char* slice_state_to_string(SliceState i) _const_;
+SliceState slice_state_from_string(const char *s) _pure_;
 
                         if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
                                 return r;
 
-                if ((r = unit_add_default_cgroups(u)) < 0)
+                r = unit_add_default_slice(u);
+                if (r < 0)
+                        return r;
+
+                r = unit_add_default_cgroups(u);
+                if (r < 0)
                         return r;
 
                 if (UNIT(s)->default_dependencies)
 
 #define SPECIAL_RUNLEVEL3_TARGET "runlevel3.target"
 #define SPECIAL_RUNLEVEL4_TARGET "runlevel4.target"
 #define SPECIAL_RUNLEVEL5_TARGET "runlevel5.target"
+
+/* Where we add all our system units by default */
+#define SPECIAL_SYSTEM_SLICE "system.slice"
 
                 if (r < 0)
                         return r;
 
+                r = unit_add_default_slice(u);
+                if (r < 0)
+                        return r;
+
                 r = unit_add_default_cgroups(u);
                 if (r < 0)
                         return r;
 
         [UNIT_AUTOMOUNT] = &automount_vtable,
         [UNIT_SNAPSHOT] = &snapshot_vtable,
         [UNIT_SWAP] = &swap_vtable,
-        [UNIT_PATH] = &path_vtable
+        [UNIT_PATH] = &path_vtable,
+        [UNIT_SLICE] = &slice_vtable
 };
 
 Unit *unit_new(Manager *m, size_t size) {
 }
 
 static int unit_add_default_dependencies(Unit *u) {
+
         static const UnitDependency deps[] = {
                 UNIT_REQUIRED_BY,
                 UNIT_REQUIRED_BY_OVERRIDABLE,
         assert(u);
 
         for (k = 0; k < ELEMENTSOF(deps); k++)
-                SET_FOREACH(target, u->dependencies[deps[k]], i)
-                        if ((r = unit_add_default_target_dependency(u, target)) < 0)
+                SET_FOREACH(target, u->dependencies[deps[k]], i) {
+                        r = unit_add_default_target_dependency(u, target);
+                        if (r < 0)
                                 return r;
+                }
+
+        if (u->default_dependencies && UNIT_DEREF(u->slice)) {
+                r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, UNIT_DEREF(u->slice), true);
+                if (r < 0)
+                        return r;
+        }
 
         return 0;
 }
 }
 
 char *unit_default_cgroup_path(Unit *u) {
-        _cleanup_free_ char *escaped_instance = NULL;
+        _cleanup_free_ char *escaped_instance = NULL, *slice = NULL;
+        int r;
 
         assert(u);
 
+        if (UNIT_DEREF(u->slice)) {
+                r = cg_slice_to_path(UNIT_DEREF(u->slice)->id, &slice);
+                if (r < 0)
+                        return NULL;
+        }
+
         escaped_instance = cg_escape(u->id);
         if (!escaped_instance)
                 return NULL;
                 if (!escaped_template)
                         return NULL;
 
-                return strjoin(u->manager->cgroup_hierarchy, "/", escaped_template, "/", escaped_instance, NULL);
+                return strjoin(u->manager->cgroup_hierarchy, "/",
+                               slice ? slice : "", slice ? "/" : "",
+                               escaped_template, "/", escaped_instance, NULL);
         } else
-                return strjoin(u->manager->cgroup_hierarchy, "/", escaped_instance, NULL);
+                return strjoin(u->manager->cgroup_hierarchy, "/",
+                               slice ? slice : "", slice ? "/" : "",
+                               escaped_instance, NULL);
 }
 
 int unit_add_cgroup_from_text(Unit *u, const char *name, bool overwrite, CGroupBonding **ret) {
         return r;
 }
 
+int unit_add_default_slice(Unit *u) {
+        Unit *slice;
+        int r;
+
+        assert(u);
+
+        if (UNIT_DEREF(u->slice))
+                return 0;
+
+        if (u->manager->running_as != SYSTEMD_SYSTEM)
+                return 0;
+
+        r = manager_load_unit(u->manager, SPECIAL_SYSTEM_SLICE, NULL, NULL, &slice);
+        if (r < 0)
+                return r;
+
+        unit_ref_set(&u->slice, slice);
+        return 0;
+}
+
 int unit_add_default_cgroups(Unit *u) {
         CGroupAttribute *a;
         char **c;
 
 #include "cgroup.h"
 #include "cgroup-attr.h"
 
+struct UnitRef {
+        /* Keeps tracks of references to a unit. This is useful so
+         * that we can merge two units if necessary and correct all
+         * references to them */
+
+        Unit* unit;
+        LIST_FIELDS(UnitRef, refs);
+};
+
 struct Unit {
         Manager *manager;
 
         CGroupBonding *cgroup_bondings;
         CGroupAttribute *cgroup_attributes;
 
+        UnitRef slice;
+
         /* Per type list */
         LIST_FIELDS(Unit, units_by_type);
 
         bool in_audit:1;
 };
 
-struct UnitRef {
-        /* Keeps tracks of references to a unit. This is useful so
-         * that we can merge two units if necessary and correct all
-         * references to them */
-
-        Unit* unit;
-        LIST_FIELDS(UnitRef, refs);
-};
-
 struct UnitStatusMessageFormats {
         const char *starting_stopping[2];
         const char *finished_start_job[_JOB_RESULT_MAX];
 #include "snapshot.h"
 #include "swap.h"
 #include "path.h"
+#include "slice.h"
 
 struct UnitVTable {
         /* How much memory does an object of this unit type need */
 DEFINE_CAST(SNAPSHOT, Snapshot);
 DEFINE_CAST(SWAP, Swap);
 DEFINE_CAST(PATH, Path);
+DEFINE_CAST(SLICE, Slice);
 
 Unit *unit_new(Manager *m, size_t size);
 void unit_free(Unit *u);
 int unit_load_fragment_and_dropin_optional(Unit *u);
 int unit_load(Unit *unit);
 
+int unit_add_default_slice(Unit *u);
+
 const char *unit_description(Unit *u) _pure_;
 
 bool unit_has_name(Unit *u, const char *name);
 
 
         return true;
 }
+
+int cg_slice_to_path(const char *unit, char **ret) {
+        _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
+        const char *dash;
+
+        assert(unit);
+        assert(ret);
+
+        if (!unit_name_is_valid(unit, false))
+                return -EINVAL;
+
+        if (!endswith(unit, ".slice"))
+                return -EINVAL;
+
+        p = unit_name_to_prefix(unit);
+        if (!p)
+                return -ENOMEM;
+
+        dash = strchr(p, '-');
+        while (dash) {
+                _cleanup_free_ char *escaped = NULL;
+                char n[dash - p + sizeof(".slice")];
+
+                strcpy(stpncpy(n, p, dash - p), ".slice");
+
+                if (!unit_name_is_valid(n, false))
+                        return -EINVAL;
+
+                escaped = cg_escape(n);
+                if (!escaped)
+                        return -ENOMEM;
+
+                if (!strextend(&s, escaped, "/", NULL))
+                        return -ENOMEM;
+
+                dash = strchr(dash+1, '-');
+        }
+
+        e = cg_escape(unit);
+        if (!e)
+                return -ENOMEM;
+
+        if (!strextend(&s, e, NULL))
+                return -ENOMEM;
+
+        *ret = s;
+        s = NULL;
+
+        return 0;
+}
 
 char *cg_unescape(const char *p) _pure_;
 
 bool cg_controller_is_valid(const char *p, bool allow_named);
+
+int cg_slice_to_path(const char *unit, char **ret);
 
         [UNIT_TIMER] = "timer",
         [UNIT_SWAP] = "swap",
         [UNIT_PATH] = "path",
+        [UNIT_SLICE] = "slice"
 };
 
 DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType);
         assert(n);
         assert(unit_name_is_valid(n, true));
         assert(suffix);
+        assert(suffix[0] == '.');
 
         assert_se(e = strrchr(n, '.'));
         a = e - n;
         return r;
 }
 
-char *snapshot_name_mangle(const char *name) {
+char *unit_name_mangle_with_suffix(const char *name, const char *suffix) {
         char *r, *t;
         const char *f;
 
         assert(name);
+        assert(suffix);
+        assert(suffix[0] == '.');
 
         /* Similar to unit_name_mangle(), but is called when we know
          * that this is about snapshot units. */
 
-        r = new(char, strlen(name) * 4 + 1 + sizeof(".snapshot")-1);
+        r = new(char, strlen(name) * 4 + strlen(suffix) + 1);
         if (!r)
                 return NULL;
 
                         *(t++) = *f;
         }
 
-        if (!endswith(name, ".snapshot"))
-                strcpy(t, ".snapshot");
+        if (!endswith(name, suffix))
+                strcpy(t, suffix);
         else
                 *t = 0;
 
 
         UNIT_TIMER,
         UNIT_SWAP,
         UNIT_PATH,
+        UNIT_SLICE,
         _UNIT_TYPE_MAX,
         _UNIT_TYPE_INVALID = -1
 };
 char *unit_dbus_path_from_name(const char *name);
 
 char *unit_name_mangle(const char *name);
-char *snapshot_name_mangle(const char *name);
+char *unit_name_mangle_with_suffix(const char *name, const char *suffix);
 
         dbus_error_init(&error);
 
         if (strv_length(args) > 1)
-                n = snapshot_name_mangle(args[1]);
+                n = unit_name_mangle_with_suffix(args[1], ".snapshot");
         else
                 n = strdup("");
         if (!n)
                 _cleanup_free_ char *n = NULL;
                 int r;
 
-                n = snapshot_name_mangle(*name);
+                n = unit_name_mangle_with_suffix(*name, ".snapshot");
                 if (!n)
                         return log_oom();
 
 
         assert_se(!cg_controller_is_valid("tatü", false));
 }
 
+static void test_slice_to_path_one(const char *unit, const char *path, int error) {
+        _cleanup_free_ char *ret = NULL;
+
+        assert_se(cg_slice_to_path(unit, &ret) == error);
+        assert_se(streq_ptr(ret, path));
+}
+
+static void test_slice_to_path(void) {
+
+        test_slice_to_path_one("foobar.slice", "foobar.slice", 0);
+        test_slice_to_path_one("foobar-waldo.slice", "foobar.slice/foobar-waldo.slice", 0);
+        test_slice_to_path_one("foobar-waldo.service", NULL, -EINVAL);
+        test_slice_to_path_one("-.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("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);
+}
+
 int main(void) {
         test_path_decode_unit();
         test_path_get_unit();
         test_proc();
         test_escape();
         test_controller_is_valid();
+        test_slice_to_path();
 
         return 0;
 }