chiark / gitweb /
implement coldpluggin
authorLennart Poettering <lennart@poettering.net>
Fri, 29 Jan 2010 02:18:09 +0000 (03:18 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 29 Jan 2010 02:18:09 +0000 (03:18 +0100)
14 files changed:
Makefile
automount.c
device.c
job.c
load-fragment.c
load-fstab.c [deleted file]
load-fstab.h [deleted file]
main.c
manager.c
manager.h
mount.c
mount.h
unit.c
unit.h

index 22c84db..d35620e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,6 @@ COMMON= \
        snapshot.o \
        socket.o \
        timer.o \
-       load-fstab.o \
        load-dropin.o \
        execute.o
 
index eb9c3d3..5d4a240 100644 (file)
@@ -20,10 +20,6 @@ static int automount_init(Unit *u) {
         if ((r = unit_load_fragment(u)) < 0)
                 return r;
 
-        /* Load entry from /etc/fstab */
-        if ((r = unit_load_fstab(u)) < 0)
-                return r;
-
         /* Load drop-in directory data */
         if ((r = unit_load_dropin(u)) < 0)
                 return r;
index 6d7e2c6..34d760a 100644 (file)
--- a/device.c
+++ b/device.c
@@ -8,6 +8,16 @@
 #include "strv.h"
 #include "log.h"
 
+static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
+        [DEVICE_DEAD] = UNIT_INACTIVE,
+        [DEVICE_AVAILABLE] = UNIT_ACTIVE
+};
+
+static const char* const state_string_table[_DEVICE_STATE_MAX] = {
+        [DEVICE_DEAD] = "dead",
+        [DEVICE_AVAILABLE] = "available"
+};
+
 static void device_done(Unit *u) {
         Device *d = DEVICE(u);
 
@@ -15,13 +25,31 @@ static void device_done(Unit *u) {
         free(d->sysfs);
 }
 
-static void device_dump(Unit *u, FILE *f, const char *prefix) {
+static void device_set_state(Device *d, DeviceState state) {
+        DeviceState old_state;
+        assert(d);
 
-        static const char* const state_table[_DEVICE_STATE_MAX] = {
-                [DEVICE_DEAD] = "dead",
-                [DEVICE_AVAILABLE] = "available"
-        };
+        old_state = d->state;
+        d->state = state;
 
+        log_debug("%s changed %s → %s", unit_id(UNIT(d)), state_string_table[old_state], state_string_table[state]);
+
+        unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state]);
+}
+
+static int device_coldplug(Unit *u) {
+        Device *d = DEVICE(u);
+
+        assert(d);
+        assert(d->state == DEVICE_DEAD);
+
+        if (d->sysfs)
+                device_set_state(d, DEVICE_AVAILABLE);
+
+        return 0;
+}
+
+static void device_dump(Unit *u, FILE *f, const char *prefix) {
         Device *d = DEVICE(u);
 
         assert(d);
@@ -29,8 +57,14 @@ static void device_dump(Unit *u, FILE *f, const char *prefix) {
         fprintf(f,
                 "%sDevice State: %s\n"
                 "%sSysfs Path: %s\n",
-                prefix, state_table[d->state],
-                prefix, d->sysfs);
+                prefix, state_string_table[d->state],
+                prefix, strna(d->sysfs));
+}
+
+static UnitActiveState device_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[DEVICE(u)->state];
 }
 
 static int device_add_escaped_name(Unit *u, const char *prefix, const char *dn, bool make_id) {
@@ -108,11 +142,9 @@ static int device_process_device(Manager *m, struct udev_device *dev) {
                 }
 
                 if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) ||
-                     (model = udev_device_get_property_value(dev, "ID_MODEL")))
-                        if (!(u->meta.description = strdup(model))) {
-                                r = -ENOMEM;
+                    (model = udev_device_get_property_value(dev, "ID_MODEL")))
+                        if ((r = unit_set_description(u, model)) < 0)
                                 goto fail;
-                        }
 
         } else {
                 delete = false;
@@ -229,19 +261,17 @@ fail:
         return r;
 }
 
-static UnitActiveState device_active_state(Unit *u) {
-        return DEVICE(u)->state == DEVICE_DEAD ? UNIT_INACTIVE : UNIT_ACTIVE;
-}
-
 const UnitVTable device_vtable = {
         .suffix = ".device",
 
         .init = unit_load_fragment_and_dropin,
         .done = device_done,
+        .coldplug = device_coldplug,
+
         .dump = device_dump,
 
-        .enumerate = device_enumerate,
-        .shutdown = device_shutdown,
+        .active_state = device_active_state,
 
-        .active_state = device_active_state
+        .enumerate = device_enumerate,
+        .shutdown = device_shutdown
 };
diff --git a/job.c b/job.c
index ff30864..148c745 100644 (file)
--- a/job.c
+++ b/job.c
@@ -5,6 +5,7 @@
 
 #include "macro.h"
 #include "job.h"
+#include "log.h"
 
 Job* job_new(Manager *m, JobType type, Unit *unit) {
         Job *j;
@@ -405,10 +406,18 @@ int job_finish_and_invalidate(Job *j, bool success) {
         assert(j);
         assert(j->installed);
 
+        log_debug("Job %s/%s finished, success=%s", unit_id(j->unit), job_type_to_string(j->type), yes_no(success));
+
         /* Patch restart jobs so that they become normal start jobs */
         if (success && (j->type == JOB_RESTART || j->type == JOB_TRY_RESTART)) {
+
+                log_debug("Converting job %s/%s → %s/%s",
+                          unit_id(j->unit), job_type_to_string(j->type),
+                          unit_id(j->unit), job_type_to_string(JOB_START));
+
                 j->state = JOB_RUNNING;
                 j->type = JOB_START;
+
                 job_schedule_run(j);
                 return 0;
         }
index 94bdf17..0cdaaa2 100644 (file)
@@ -807,10 +807,11 @@ static int load_from_path(Unit *u, const char *path) {
                         goto finish;
 
 
+                if (id == k)
+                        unit_choose_id(u, id);
                 free(k);
         }
 
-        unit_choose_id(u, id);
 
         free(u->meta.load_path);
         u->meta.load_path = filename;
@@ -860,10 +861,10 @@ int unit_load_fragment(Unit *u) {
                 /* If syslog or kernel logging is requested, make sure
                  * our own logging daemon is run first. */
 
-                if ((k = unit_add_dependency(u, UNIT_AFTER, u->meta.manager->special_units[SPECIAL_LOGGER_SOCKET])) < 0)
+                if ((k = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_LOGGER_SOCKET)) < 0)
                         return k;
 
-                if ((k = unit_add_dependency(u, UNIT_REQUIRES, u->meta.manager->special_units[SPECIAL_LOGGER_SOCKET])) < 0)
+                if ((k = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_LOGGER_SOCKET)) < 0)
                         return k;
         }
 
diff --git a/load-fstab.c b/load-fstab.c
deleted file mode 100644 (file)
index d611426..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#include "load-fstab.h"
-
-int unit_load_fstab(Unit *u) {
-        assert(u);
-
-        /* Load dependencies from /etc/fstab */
-
-        return 0;
-}
diff --git a/load-fstab.h b/load-fstab.h
deleted file mode 100644 (file)
index b0cef7d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
-
-#ifndef fooloadfstabhfoo
-#define fooloadfstabhfoo
-
-#include "unit.h"
-
-/* Read service data from /etc/fstab */
-
-int unit_load_fstab(Unit *u);
-
-#endif
diff --git a/main.c b/main.c
index 2486f06..be733f0 100644 (file)
--- a/main.c
+++ b/main.c
@@ -21,7 +21,12 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        if ((r = manager_load_unit(m, "default.target", &target)) < 0) {
+        if ((r = manager_coldplug(m)) < 0) {
+                log_error("Failed to retrieve coldplug information: %s", strerror(-r));
+                goto finish;
+        }
+
+        if ((r = manager_load_unit(m, SPECIAL_DEFAULT_TARGET, &target)) < 0) {
                 log_error("Failed to load default target: %s", strerror(-r));
                 goto finish;
         }
@@ -37,10 +42,10 @@ int main(int argc, char *argv[]) {
         printf("→ By jobs:\n");
         manager_dump_jobs(m, stdout, "\t");
 
-        if ((r = manager_loop(m)) < 0) {
-                log_error("Failed to run mainloop: %s", strerror(-r));
-                goto finish;
-        }
+        /* if ((r = manager_loop(m)) < 0) { */
+        /*         log_error("Failed to run mainloop: %s", strerror(-r)); */
+        /*         goto finish; */
+        /* } */
 
         retval = 0;
 
index 23d450d..9355a6a 100644 (file)
--- a/manager.c
+++ b/manager.c
 #include "log.h"
 #include "util.h"
 
-static const char * const special_table[_SPECIAL_UNIT_MAX] = {
-        [SPECIAL_SYSLOG_SERVICE] = "syslog.service",
-        [SPECIAL_DBUS_SERVICE] = "messagebus.service",
-        [SPECIAL_LOGGER_SOCKET] = "systemd-logger.socket",
-        [SPECIAL_KBREQUEST_TARGET] = "kbrequest.target",
-        [SPECIAL_CTRL_ALT_DEL_TARGET] = "ctrl-alt-del.target"
-};
-
 static int manager_setup_signals(Manager *m) {
         sigset_t mask;
         struct epoll_event ev;
@@ -58,35 +50,6 @@ static int manager_setup_signals(Manager *m) {
         return 0;
 }
 
-static int manager_load_special_units(Manager *m) {
-        SpecialUnit c;
-        int r;
-
-        assert(m);
-
-        /* Loads all 'special' units, so that we have easy access to them later */
-
-        for (c = 0; c < _SPECIAL_UNIT_MAX; c++)
-                if ((r = manager_load_unit(m, special_table[c], m->special_units+c)) < 0)
-                        return r;
-
-        return 0;
-}
-
-static int manager_enumerate(Manager *m) {
-        int r;
-        UnitType c;
-
-        assert(m);
-
-        for (c = 0; c < _UNIT_TYPE_MAX; c++)
-                if (unit_vtable[c]->enumerate)
-                        if ((r = unit_vtable[c]->enumerate(m)) < 0)
-                                return r;
-
-        return 0;
-}
-
 Manager* manager_new(void) {
         Manager *m;
 
@@ -113,12 +76,6 @@ Manager* manager_new(void) {
         if (manager_setup_signals(m) < 0)
                 goto fail;
 
-        if (manager_load_special_units(m) < 0)
-                goto fail;
-
-        if (manager_enumerate(m) < 0)
-                goto fail;
-
         return m;
 
 fail:
@@ -156,6 +113,39 @@ void manager_free(Manager *m) {
         free(m);
 }
 
+int manager_coldplug(Manager *m) {
+        int r;
+        UnitType c;
+        Iterator i;
+        Unit *u;
+        char *k;
+
+        assert(m);
+
+        /* First, let's ask every type to load all units from
+         * disk/kernel that it might know */
+        for (c = 0; c < _UNIT_TYPE_MAX; c++)
+                if (unit_vtable[c]->enumerate)
+                        if ((r = unit_vtable[c]->enumerate(m)) < 0)
+                                return r;
+
+        manager_dispatch_load_queue(m);
+
+        /* Then, let's set up their initial state. */
+        HASHMAP_FOREACH_KEY(u, k, m->units, i) {
+
+                /* ignore aliases */
+                if (unit_id(u) != k)
+                        continue;
+
+                if (UNIT_VTABLE(u)->coldplug)
+                        if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0)
+                                return r;
+        }
+
+        return 0;
+}
+
 static void transaction_delete_job(Manager *m, Job *j) {
         assert(m);
         assert(j);
@@ -874,6 +864,8 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool for
         if ((r = transaction_activate(m, mode)) < 0)
                 return r;
 
+        log_debug("Enqueued job %s/%s", unit_id(unit), job_type_to_string(type));
+
         if (_ret)
                 *_ret = ret;
 
@@ -893,7 +885,7 @@ Unit *manager_get_unit(Manager *m, const char *name) {
         return hashmap_get(m->units, name);
 }
 
-static void dispatch_load_queue(Manager *m) {
+void manager_dispatch_load_queue(Manager *m) {
         Meta *meta;
 
         assert(m);
@@ -951,7 +943,7 @@ int manager_load_unit(Manager *m, const char *path, Unit **_ret) {
         }
 
         unit_add_to_load_queue(ret);
-        dispatch_load_queue(m);
+        manager_dispatch_load_queue(m);
 
         *_ret = ret;
         return 0;
index 64c9b80..793a55f 100644 (file)
--- a/manager.h
+++ b/manager.h
@@ -30,14 +30,12 @@ struct Watch {
 #include "list.h"
 #include "set.h"
 
-typedef enum SpecialUnit {
-        SPECIAL_SYSLOG_SERVICE,
-        SPECIAL_DBUS_SERVICE,
-        SPECIAL_LOGGER_SOCKET,
-        SPECIAL_CTRL_ALT_DEL_TARGET,
-        SPECIAL_KBREQUEST_TARGET,
-        _SPECIAL_UNIT_MAX
-} SpecialUnit;
+#define SPECIAL_DEFAULT_TARGET "default.target"
+#define SPECIAL_SYSLOG_SERVICE "syslog.service"
+#define SPECIAL_DBUS_SERVICE "messagebus.service"
+#define SPECIAL_LOGGER_SOCKET "systemd-logger.socket"
+#define SPECIAL_KBREQUEST_TARGET "kbrequest.target"
+#define SPECIAL_CTRL_ALT_DEL_TARGET "ctrl-alt-del.target"
 
 struct Manager {
         uint32_t current_job_id;
@@ -69,14 +67,14 @@ struct Manager {
 
         Watch signal_watch;
 
-        Unit *special_units[_SPECIAL_UNIT_MAX]; /* some special units */
-
         struct udev* udev;
 };
 
 Manager* manager_new(void);
 void manager_free(Manager *m);
 
+int manager_coldplug(Manager *m);
+
 Job *manager_get_job(Manager *m, uint32_t id);
 Unit *manager_get_unit(Manager *m, const char *name);
 
@@ -90,7 +88,9 @@ void manager_transaction_unlink_job(Manager *m, Job *j);
 
 void manager_clear_jobs(Manager *m);
 
+void manager_dispatch_load_queue(Manager *m);
 void manager_dispatch_run_queue(Manager *m);
+
 int manager_loop(Manager *m);
 
 #endif
diff --git a/mount.c b/mount.c
index ddf0520..d9d461a 100644 (file)
--- a/mount.c
+++ b/mount.c
@@ -7,30 +7,24 @@
 #include "unit.h"
 #include "mount.h"
 #include "load-fragment.h"
-#include "load-fstab.h"
 #include "load-dropin.h"
 #include "log.h"
 
-static int mount_init(Unit *u) {
-        int r;
-        Mount *m = MOUNT(u);
-
-        assert(m);
-
-        /* Load a .mount file */
-        if ((r = unit_load_fragment(u)) < 0)
-                return r;
-
-        /* Load entry from /etc/fstab */
-        if ((r = unit_load_fstab(u)) < 0)
-                return r;
-
-        /* Load drop-in directory data */
-        if ((r = unit_load_dropin(u)) < 0)
-                return r;
+static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
+        [MOUNT_DEAD] = UNIT_INACTIVE,
+        [MOUNT_MOUNTING] = UNIT_ACTIVATING,
+        [MOUNT_MOUNTED] = UNIT_ACTIVE,
+        [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
+        [MOUNT_MAINTAINANCE] = UNIT_INACTIVE,
+};
 
-        return r;
-}
+static const char* const state_string_table[_MOUNT_STATE_MAX] = {
+        [MOUNT_DEAD] = "dead",
+        [MOUNT_MOUNTING] = "mounting",
+        [MOUNT_MOUNTED] = "mounted",
+        [MOUNT_UNMOUNTING] = "unmounting",
+        [MOUNT_MAINTAINANCE] = "maintainance"
+};
 
 static void mount_done(Unit *u) {
         Mount *d = MOUNT(u);
@@ -40,16 +34,31 @@ static void mount_done(Unit *u) {
         free(d->where);
 }
 
-static void mount_dump(Unit *u, FILE *f, const char *prefix) {
+static void mount_set_state(Mount *m, MountState state) {
+        MountState old_state;
+        assert(m);
+
+        old_state = m->state;
+        m->state = state;
+
+        log_debug("%s changed %s → %s", unit_id(UNIT(m)), state_string_table[old_state], state_string_table[state]);
+
+        unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state]);
+}
+
+static int mount_coldplug(Unit *u) {
+        Mount *m = MOUNT(u);
+
+        assert(m);
+        assert(m->state == MOUNT_DEAD);
 
-        static const char* const state_table[_MOUNT_STATE_MAX] = {
-                [MOUNT_DEAD] = "dead",
-                [MOUNT_MOUNTING] = "mounting",
-                [MOUNT_MOUNTED] = "mounted",
-                [MOUNT_UNMOUNTING] = "unmounting",
-                [MOUNT_MAINTAINANCE] = "maintainance"
-        };
+        if (m->from_proc_self_mountinfo)
+                mount_set_state(m, MOUNT_MOUNTED);
 
+        return 0;
+}
+
+static void mount_dump(Unit *u, FILE *f, const char *prefix) {
         Mount *s = MOUNT(u);
 
         assert(s);
@@ -57,10 +66,20 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
         fprintf(f,
                 "%sMount State: %s\n"
                 "%sWhere: %s\n"
-                "%sWhat: %s\n",
-                prefix, state_table[s->state],
+                "%sWhat: %s\n"
+                "%sFrom /etc/fstab: %s\n"
+                "%sFrom /proc/self/mountinfo: %s\n",
+                prefix, state_string_table[s->state],
                 prefix, s->where,
-                prefix, s->what);
+                prefix, s->what,
+                prefix, yes_no(s->from_etc_fstab),
+                prefix, yes_no(s->from_proc_self_mountinfo));
+}
+
+static UnitActiveState mount_active_state(Unit *u) {
+        assert(u);
+
+        return state_translation_table[MOUNT(u)->state];
 }
 
 static void mount_shutdown(Manager *m) {
@@ -136,12 +155,13 @@ static int mount_add_path_links(Mount *m) {
         return 0;
 }
 
-static int mount_add_one(Manager *m, const char *what, const char *where) {
+static int mount_add_one(Manager *m, const char *what, const char *where, bool live) {
         char *e;
         int r;
         Unit *u;
         bool delete;
 
+        assert(m);
         assert(what);
         assert(where);
 
@@ -172,16 +192,23 @@ static int mount_add_one(Manager *m, const char *what, const char *where) {
                         goto fail;
 
                 if (!(MOUNT(u)->what = strdup(what)) ||
-                    !(MOUNT(u)->where = strdup(where)) ||
-                    !(u->meta.description = strdup(where))) {
-                        r = -ENOMEM;
+                    !(MOUNT(u)->where = strdup(where))) {
+                            r = -ENOMEM;
+                            goto fail;
+                    }
+
+                if ((r = unit_set_description(u, where)) < 0)
                         goto fail;
-                }
         } else {
                 delete = false;
                 free(e);
         }
 
+        if (live)
+                MOUNT(u)->from_proc_self_mountinfo = true;
+        else
+                MOUNT(u)->from_etc_fstab = true;
+
         if ((r = mount_add_node_links(MOUNT(u))) < 0)
                 goto fail;
 
@@ -189,6 +216,7 @@ static int mount_add_one(Manager *m, const char *what, const char *where) {
                 goto fail;
 
         unit_add_to_load_queue(u);
+
         return 0;
 
 fail:
@@ -207,10 +235,10 @@ static char *fstab_node_to_udev_node(char *p) {
 
         if (startswith(p, "LABEL=")) {
 
-                if (!(t = strdup(p+6)))
+                if (!(t = xescape(p+6, "/ ")))
                         return NULL;
 
-                r = asprintf(&dn, "/dev/disk/by-label/%s", xescape(t, "/ "));
+                r = asprintf(&dn, "/dev/disk/by-label/%s", t);
                 free(t);
 
                 if (r < 0)
@@ -221,10 +249,10 @@ static char *fstab_node_to_udev_node(char *p) {
 
         if (startswith(p, "UUID=")) {
 
-                if (!(t = strdup(p+5)))
+                if (!(t = xescape(p+5, "/ ")))
                         return NULL;
 
-                r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(xescape(t, "/ ")));
+                r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(t));
                 free(t);
 
                 if (r < 0)
@@ -267,7 +295,7 @@ static int mount_load_etc_fstab(Manager *m) {
                 if (where[0] == '/')
                         path_kill_slashes(where);
 
-                r = mount_add_one(m, what, where);
+                r = mount_add_one(m, what, where, false);
                 free(what);
                 free(where);
 
@@ -282,7 +310,7 @@ finish:
         return r;
 }
 
-static int mount_load_proc_mounts(Manager *m) {
+static int mount_load_proc_self_mountinfo(Manager *m) {
         FILE *f;
         int r;
 
@@ -338,7 +366,7 @@ static int mount_load_proc_mounts(Manager *m) {
                 }
                 free(path);
 
-                r = mount_add_one(m, d, p);
+                r = mount_add_one(m, d, p, true);
                 free(d);
                 free(p);
 
@@ -361,7 +389,7 @@ static int mount_enumerate(Manager *m) {
         if ((r = mount_load_etc_fstab(m)) < 0)
                 goto fail;
 
-        if ((r = mount_load_proc_mounts(m)) < 0)
+        if ((r = mount_load_proc_self_mountinfo(m)) < 0)
                 goto fail;
 
         return 0;
@@ -371,28 +399,17 @@ fail:
         return r;
 }
 
-static UnitActiveState mount_active_state(Unit *u) {
-
-        static const UnitActiveState table[_MOUNT_STATE_MAX] = {
-                [MOUNT_DEAD] = UNIT_INACTIVE,
-                [MOUNT_MOUNTING] = UNIT_ACTIVATING,
-                [MOUNT_MOUNTED] = UNIT_ACTIVE,
-                [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
-                [MOUNT_MAINTAINANCE] = UNIT_INACTIVE,
-        };
-
-        return table[MOUNT(u)->state];
-}
-
 const UnitVTable mount_vtable = {
         .suffix = ".mount",
 
-        .init = mount_init,
+        .init = unit_load_fragment_and_dropin,
         .done = mount_done,
+        .coldplug = mount_coldplug,
+
         .dump = mount_dump,
 
-        .enumerate = mount_enumerate,
-        .shutdown = mount_shutdown,
+        .active_state = mount_active_state,
 
-        .active_state = mount_active_state
+        .enumerate = mount_enumerate,
+        .shutdown = mount_shutdown
 };
diff --git a/mount.h b/mount.h
index 5b5d5a3..9a8079f 100644 (file)
--- a/mount.h
+++ b/mount.h
@@ -22,6 +22,9 @@ struct Mount {
         MountState state;
 
         char *what, *where;
+
+        bool from_etc_fstab:1;
+        bool from_proc_self_mountinfo:1;
 };
 
 extern const UnitVTable mount_vtable;
diff --git a/unit.c b/unit.c
index 7723393..7954c04 100644 (file)
--- a/unit.c
+++ b/unit.c
@@ -170,6 +170,19 @@ int unit_choose_id(Unit *u, const char *name) {
         return 0;
 }
 
+int unit_set_description(Unit *u, const char *description) {
+        char *s;
+
+        assert(u);
+
+        if (!(s = strdup(description)))
+                return -ENOMEM;
+
+        free(u->meta.description);
+        u->meta.description = s;
+        return 0;
+}
+
 void unit_add_to_load_queue(Unit *u) {
         assert(u);
 
@@ -586,7 +599,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
                 else {
                         assert(u->meta.job->state == JOB_RUNNING);
 
-                        /* Let's check of this state change
+                        /* Let's check whether this state change
                          * constitutes a finished job, or maybe
                          * cotradicts a running job and hence needs to
                          * invalidate jobs. */
diff --git a/unit.h b/unit.h
index 0cd09fe..3e42ebe 100644 (file)
--- a/unit.h
+++ b/unit.h
@@ -144,6 +144,7 @@ struct UnitVTable {
 
         int (*init)(Unit *u);
         void (*done)(Unit *u);
+        int (*coldplug)(Unit *u);
 
         void (*dump)(Unit *u, FILE *f, const char *prefix);
 
@@ -161,7 +162,14 @@ struct UnitVTable {
         void (*sigchld_event)(Unit *u, pid_t pid, int code, int status);
         void (*timer_event)(Unit *u, uint64_t n_elapsed, Watch *w);
 
+        /* This is called for each unit type and should be used to
+         * enumerate existing devices and load them. However,
+         * everything that is loaded here should still stay in
+         * inactive state. It is the job of the coldplug() call above
+         * to put the units into the initial state.  */
         int (*enumerate)(Manager *m);
+
+        /* Type specific cleanups. */
         void (*shutdown)(Manager *m);
 };
 
@@ -202,6 +210,7 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other);
 int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name);
 
 int unit_choose_id(Unit *u, const char *name);
+int unit_set_description(Unit *u, const char *description);
 
 void unit_add_to_load_queue(Unit *u);