chiark / gitweb /
reload: implement reload/reexec logic
[elogind.git] / unit.c
diff --git a/unit.c b/unit.c
index 7f147537e30e418da1c2dc50e4fc1248f2d1af51..0d459d6760d8e09661bace80dd12cad715df3e78 100644 (file)
--- a/unit.c
+++ b/unit.c
@@ -37,6 +37,7 @@
 #include "log.h"
 #include "unit-name.h"
 #include "specifier.h"
+#include "dbus-unit.h"
 
 const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
         [UNIT_SERVICE] = &service_vtable,
@@ -614,6 +615,16 @@ int unit_load_fragment_and_dropin_optional(Unit *u) {
         return 0;
 }
 
+/* Common implementation for multiple backends */
+int unit_load_nop(Unit *u) {
+        assert(u);
+
+        if (u->meta.load_state == UNIT_STUB)
+                u->meta.load_state = UNIT_LOADED;
+
+        return 0;
+}
+
 int unit_load(Unit *u) {
         int r;
 
@@ -1023,6 +1034,9 @@ int unit_watch_pid(Unit *u, pid_t pid) {
         assert(u);
         assert(pid >= 1);
 
+        /* Watch a specific PID. We only support one unit watching
+         * each PID for now. */
+
         return hashmap_put(u->meta.manager->watch_pids, UINT32_TO_PTR(pid), u);
 }
 
@@ -1030,7 +1044,7 @@ void unit_unwatch_pid(Unit *u, pid_t pid) {
         assert(u);
         assert(pid >= 1);
 
-        hashmap_remove(u->meta.manager->watch_pids, UINT32_TO_PTR(pid));
+        hashmap_remove_value(u->meta.manager->watch_pids, UINT32_TO_PTR(pid), u);
 }
 
 int unit_watch_timer(Unit *u, usec_t delay, Watch *w) {
@@ -1105,7 +1119,7 @@ void unit_unwatch_timer(Unit *u, Watch *w) {
         assert(w->type == WATCH_TIMER && w->data.unit == u);
 
         assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
-        assert_se(close_nointr(w->fd) == 0);
+        close_nointr_nofail(w->fd);
 
         w->fd = -1;
         w->type = WATCH_INVALID;
@@ -1339,13 +1353,22 @@ int unit_add_cgroup(Unit *u, CGroupBonding *b) {
 
 static char *default_cgroup_path(Unit *u) {
         char *p;
+        int r;
 
         assert(u);
 
-        if (asprintf(&p, "%s/%s", u->meta.manager->cgroup_hierarchy, u->meta.id) < 0)
-                return NULL;
+        if (u->meta.instance) {
+                char *t;
 
-        return p;
+                if (!(t = unit_name_template(u->meta.id)))
+                        return NULL;
+
+                r = asprintf(&p, "%s/%s/%s", u->meta.manager->cgroup_hierarchy, t, u->meta.instance);
+                free(t);
+        } else
+                r = asprintf(&p, "%s/%s", u->meta.manager->cgroup_hierarchy, u->meta.id);
+
+        return r < 0 ? NULL : p;
 }
 
 int unit_add_cgroup_from_text(Unit *u, const char *name) {
@@ -1482,6 +1505,29 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
         return r;
 }
 
+int unit_get_related_unit(Unit *u, const char *type, Unit **_found) {
+        Unit *found;
+        char *t;
+
+        assert(u);
+        assert(type);
+        assert(_found);
+
+        if (!(t = unit_name_change_suffix(u->meta.id, type)))
+                return -ENOMEM;
+
+        assert(!unit_has_name(u, t));
+
+        found = manager_get_unit(u->meta.manager, t);
+        free(t);
+
+        if (!found)
+                return -ENOENT;
+
+        *_found = found;
+        return 0;
+}
+
 static char *specifier_prefix_and_instance(char specifier, void *data, void *userdata) {
         Unit *u = userdata;
         assert(u);
@@ -1597,6 +1643,114 @@ fail:
         return NULL;
 }
 
+int unit_watch_bus_name(Unit *u, const char *name) {
+        assert(u);
+        assert(name);
+
+        /* Watch a specific name on the bus. We only support one unit
+         * watching each name for now. */
+
+        return hashmap_put(u->meta.manager->watch_bus, name, u);
+}
+
+void unit_unwatch_bus_name(Unit *u, const char *name) {
+        assert(u);
+        assert(name);
+
+        hashmap_remove_value(u->meta.manager->watch_bus, name, u);
+}
+
+bool unit_can_serialize(Unit *u) {
+        assert(u);
+
+        return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item;
+}
+
+int unit_serialize(Unit *u, FILE *f, FDSet *fds) {
+        int r;
+
+        assert(u);
+        assert(f);
+        assert(fds);
+
+        if (!unit_can_serialize(u))
+                return 0;
+
+        if ((r = UNIT_VTABLE(u)->serialize(u, f, fds)) < 0)
+                return r;
+
+        /* End marker */
+        fputc('\n', f);
+        return 0;
+}
+
+void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) {
+        va_list ap;
+
+        assert(u);
+        assert(f);
+        assert(key);
+        assert(format);
+
+        fputs(key, f);
+        fputc('=', f);
+
+        va_start(ap, format);
+        vfprintf(f, format, ap);
+        va_end(ap);
+
+        fputc('\n', f);
+}
+
+void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
+        assert(u);
+        assert(f);
+        assert(key);
+        assert(value);
+
+        fprintf(f, "%s=%s\n", key, value);
+}
+
+int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
+        int r;
+
+        assert(u);
+        assert(f);
+        assert(fds);
+
+        if (!unit_can_serialize(u))
+                return 0;
+
+        for (;;) {
+                char line[1024], *l, *v;
+                size_t k;
+
+                if (!fgets(line, sizeof(line), f)) {
+                        if (feof(f))
+                                return 0;
+                        return -errno;
+                }
+
+                l = strstrip(line);
+
+                /* End marker */
+                if (l[0] == 0)
+                        return 0;
+
+                k = strcspn(l, "=");
+
+                if (l[k] == '=') {
+                        l[k] = 0;
+                        v = l+k+1;
+                } else
+                        v = l+k;
+
+                if ((r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds)) < 0)
+                        return r;
+        }
+}
+
+
 static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
         [UNIT_SERVICE] = "service",
         [UNIT_TIMER] = "timer",