diff options
author | kraxel <kraxel> | 2005-12-08 11:17:50 +0000 |
---|---|---|
committer | kraxel <kraxel> | 2005-12-08 11:17:50 +0000 |
commit | e22cc1e84130dfe1086088c0452efc6596e5b855 (patch) | |
tree | 95045ace03f576aa357b079a780853f66044c0ad /xs_store.c | |
download | xenwatch-e22cc1e84130dfe1086088c0452efc6596e5b855.tar.gz |
Initial revision
Diffstat (limited to 'xs_store.c')
-rw-r--r-- | xs_store.c | 693 |
1 files changed, 693 insertions, 0 deletions
diff --git a/xs_store.c b/xs_store.c new file mode 100644 index 0000000..dbf40c4 --- /dev/null +++ b/xs_store.c @@ -0,0 +1,693 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <xs.h> +#include "xs_store.h" +#include "list.h" + +/* boring declarations of local functions */ + +static void xenstore_init (XenStore *pkg_tree); +static void xenstore_class_init (XenStoreClass *klass); +static void xenstore_tree_model_init (GtkTreeModelIface *iface); +static void xenstore_finalize (GObject *object); +static GtkTreeModelFlags xenstore_get_flags (GtkTreeModel *tree_model); +static gint xenstore_get_n_columns (GtkTreeModel *tree_model); +static GType xenstore_get_column_type (GtkTreeModel *tree_model, + gint index); +static gboolean xenstore_get_iter (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path); +static GtkTreePath *xenstore_get_path (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static void xenstore_get_value (GtkTreeModel *tree_model, + GtkTreeIter *iter, + gint column, + GValue *value); +static gboolean xenstore_iter_next (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gboolean xenstore_iter_children (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent); +static gboolean xenstore_iter_has_child (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gint xenstore_iter_n_children (GtkTreeModel *tree_model, + GtkTreeIter *iter); +static gboolean xenstore_iter_nth_child (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n); +static gboolean xenstore_iter_parent (GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *child); + +static GObjectClass *parent_class = NULL; + +/* ------------------------------------------------------------------------- */ + +static int trace = 0; + +struct xs_node { + char *xs_path; + char *xs_name; + struct xs_node *parent; + int nchildren; + struct list_head children; + struct list_head siblings; +}; + +struct _XenStore { + GObject parent; /* this MUST be the first member */ + struct xs_handle *xenstore; + GIOChannel *ch; + guint id; + struct xs_node *root; +}; + +/* ------------------------------------------------------------------------- */ + +GType +xenstore_get_type (void) +{ + static GType xenstore_type = 0; + static const GTypeInfo xenstore_info = { + sizeof (XenStoreClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) xenstore_class_init, + NULL, /* class finalize */ + NULL, /* class_data */ + sizeof (XenStore), + 0, /* n_preallocs */ + (GInstanceInitFunc) xenstore_init + }; + static const GInterfaceInfo tree_model_info = { + (GInterfaceInitFunc) xenstore_tree_model_init, + NULL, + NULL + }; + + if (xenstore_type) + return xenstore_type; + + xenstore_type = g_type_register_static (G_TYPE_OBJECT, "XenStore", + &xenstore_info, (GTypeFlags)0); + g_type_add_interface_static (xenstore_type, GTK_TYPE_TREE_MODEL, &tree_model_info); + return xenstore_type; +} + +static void +xenstore_class_init (XenStoreClass *klass) +{ + GObjectClass *object_class; + + parent_class = (GObjectClass*) g_type_class_peek_parent (klass); + object_class = (GObjectClass*) klass; + + object_class->finalize = xenstore_finalize; +} + +static void +xenstore_tree_model_init (GtkTreeModelIface *iface) +{ + iface->get_flags = xenstore_get_flags; + iface->get_n_columns = xenstore_get_n_columns; + iface->get_column_type = xenstore_get_column_type; + iface->get_iter = xenstore_get_iter; + iface->get_path = xenstore_get_path; + iface->get_value = xenstore_get_value; + iface->iter_next = xenstore_iter_next; + iface->iter_children = xenstore_iter_children; + iface->iter_has_child = xenstore_iter_has_child; + iface->iter_n_children = xenstore_iter_n_children; + iface->iter_nth_child = xenstore_iter_nth_child; + iface->iter_parent = xenstore_iter_parent; +} + +/* ------------------------------------------------------------------------- */ + +static struct xs_node* node_new(char *path) +{ + struct xs_node *node; + char *name; + + name = strrchr(path,'/') +1; + if (0 == name[0]) + name = "root"; + + if (trace) + fprintf(stderr,"%s: \"%s\"\n", __FUNCTION__, path); + node = malloc(sizeof(struct xs_node)); + memset(node,0,sizeof(struct xs_node)); + node->xs_path = strdup(path); + node->xs_name = strdup(name); + node->nchildren = -1; + INIT_LIST_HEAD(&node->children); + INIT_LIST_HEAD(&node->siblings); + return node; +} + +static void node_remove(struct xs_node *node) +{ + struct xs_node *child; + struct list_head *item, *safe; + + list_for_each_safe(item, safe, &node->children) { + child = list_entry(item, struct xs_node, siblings); + node_remove(child); + } + + if (trace) + fprintf(stderr,"%s: \"%s\"\n", __FUNCTION__, node->xs_path); + list_del(&node->siblings); + free(node->xs_name); + free(node->xs_path); + free(node); +} + +static struct xs_node* node_add_child(XenStore *st, struct xs_node *node, char *name) +{ + struct xs_node *child; + char *xs_path; + + if (trace > 1) + fprintf(stderr,"%s: parent \"%s\" name \"%s\"\n", + __FUNCTION__, node->xs_path, name); + xs_path = malloc(strlen(node->xs_path) + strlen(name) + 2); + if (0 == strcmp(node->xs_path, "/")) + sprintf(xs_path, "/%s", name); + else + sprintf(xs_path, "%s/%s", node->xs_path, name); + child = node_new(xs_path); + child->parent = node; + list_add_tail(&child->siblings, &node->children); + node->nchildren++; + return child; +} + +static void node_add_children(XenStore *st, struct xs_node *node) +{ + struct xs_transaction_handle *xst; + struct xs_node *child; + unsigned int i,num; + char **list; + + g_assert(-1 == node->nchildren); + node->nchildren = 0; + + if (NULL == st->xenstore) + return; + if (NULL == (xst = xs_transaction_start(st->xenstore))) { + fprintf(stderr,"Oops, can't start transaction\n"); + return; + } + list = xs_directory(st->xenstore, xst, node->xs_path, &num); + xs_transaction_end(st->xenstore, xst, 0); + + for (i = 0; i < num; i++) + child = node_add_child(st, node, list[i]); + free(list); +} + +static struct xs_node* node_find_path(char *path, struct xs_node *node) +{ + struct xs_node *child; + struct list_head *item; + int len; + + if (0 == strcmp(path, node->xs_path)) + return node; + list_for_each(item, &node->children) { + child = list_entry(item, struct xs_node, siblings); + len = strlen(child->xs_path); + if (0 != strncmp(path, child->xs_path, len)) + continue; + if (0 == path[len]) + return child; + if ('/' == path[len]) + return node_find_path(path, child); + } + return NULL; +} + +static struct xs_node* node_find_name(char *name, struct xs_node *node) +{ + struct xs_node *child; + struct list_head *item; + + list_for_each(item, &node->children) { + child = list_entry(item, struct xs_node, siblings); + if (0 == strcmp(name, child->xs_name)) + return child; + } + return NULL; +} + +/* ------------------------------------------------------------------------- */ + +static GtkTreePath* +do_get_path(XenStore *st, struct xs_node *find) +{ + GtkTreePath *path; + struct xs_node *node, *child; + struct list_head *item; + int level,i,len; + + if (trace > 1) + fprintf(stderr,"%s: \"%s\"\n", __FUNCTION__, find->xs_path); + + node = st->root; + path = gtk_tree_path_new(); + for (level = 0;; level++) { + i = 0; + list_for_each(item, &node->children) { + child = list_entry(item, struct xs_node, siblings); + len = strlen(child->xs_path); + if (0 != strncmp(find->xs_path, child->xs_path, len)) { + i++; + continue; + } + if (0 == find->xs_path[len]) { + if (trace > 2) + fprintf(stderr,"%s: %d %d %*s \"%s\" [final]\n", __FUNCTION__, + level, i, level*3, "", child->xs_name); + gtk_tree_path_append_index(path, i); + return path; + } + if ('/' == find->xs_path[len]) { + if (trace > 2) + fprintf(stderr,"%s: %d %d %*s \"%s\"\n", __FUNCTION__, + level, i, level*3, "", child->xs_name); + gtk_tree_path_append_index(path, i); + goto next_level; + } + i++; + } + return NULL; + next_level: + node = child; + } + return NULL; +} + +static gboolean watch_trigger(GIOChannel *source, GIOCondition condition, + gpointer data) +{ + XenStore *st = data; + GtkTreePath *path = NULL; + GtkTreeIter iter; + char **vec = NULL, *h, *name = NULL; + struct xs_transaction_handle *xst; + unsigned int count; + struct xs_node *node; + char *xs_value = NULL; + int i; + + vec = xs_read_watch(st->xenstore, &count); + + if ('/' != vec[XS_WATCH_PATH][0]) { + if (trace) + fprintf(stderr,"%s: ignore: no path %d \"%s\"\n", __FUNCTION__, + count, vec[XS_WATCH_PATH]); + goto out; + } + if (0 == strcmp(vec[XS_WATCH_PATH], "/")) { + if (trace > 1) + fprintf(stderr,"%s: ignore: invisible root\n", __FUNCTION__); + goto out; + } + + if (NULL == (xst = xs_transaction_start(st->xenstore))) + goto out; + xs_value = xs_read(st->xenstore, xst, vec[XS_WATCH_PATH], NULL); + xs_transaction_end(st->xenstore, xst, 0); + + if (trace) + fprintf(stderr,"%s: node: %d \"%s\" \"%s\"\n", __FUNCTION__, + count, vec[XS_WATCH_PATH], xs_value ? xs_value : "<deleted>"); + node = node_find_path(vec[XS_WATCH_PATH], st->root); + if (NULL != node) { + fprintf(stderr,"%s: node: %p \"%s\"\n", __FUNCTION__, + node, node ? node->xs_path : "<null>"); + path = do_get_path(st, node); + if (xs_value) { + memset(&iter, 0, sizeof(iter)); + iter.user_data = node; + gtk_tree_model_row_changed(GTK_TREE_MODEL(st), path, &iter); + } else { + node_remove(node); + gtk_tree_model_row_deleted(GTK_TREE_MODEL(st), path); + } + goto out; + } + if (!xs_value) + /* ignore unknown deletes */ + goto out; + + i = 0; + while (NULL == node) { + if (name) + free(name); + h = strrchr(vec[XS_WATCH_PATH], '/'); + name = strdup(h+1); + if (h == vec[XS_WATCH_PATH]) + h++; + *h = 0; + if (trace > 1) + fprintf(stderr,"%s: parent %d: \"%s\" -> \"%s\"\n", __FUNCTION__, + i++, vec[XS_WATCH_PATH], name); + node = node_find_path(vec[XS_WATCH_PATH], st->root); + } + if (trace > 1) + fprintf(stderr,"%s: parent ok: \"%s\" %p -> \"%s\"\n", __FUNCTION__, + node ? node->xs_path : "<null>", node, name); + if (-1 == node->nchildren) { + node_add_children(st, node); + node = node_find_name(name, node); + g_assert(NULL != node); + } else { + node = node_add_child(st, node, name); + } + + path = do_get_path(st, node); + memset(&iter, 0, sizeof(iter)); + iter.user_data = node; + gtk_tree_model_row_inserted(GTK_TREE_MODEL(st), path, &iter); + + out: + if (path) + gtk_tree_path_free(path); + if (xs_value) + free(xs_value); + if (name) + free(name); + if (vec) + free(vec); + return TRUE; +} + +static void +xenstore_init(XenStore *st) +{ + if (trace) + fprintf(stderr,"%s\n", __FUNCTION__); + st->root = node_new("/"); + +#if 1 + st->xenstore = xs_daemon_open_readonly(); + if (NULL == st->xenstore) { + fprintf(stderr,"%s: can't connect to %s\n", __FUNCTION__, + xs_daemon_socket_ro()); + return; + } +#else + st->xenstore = xs_domain_open(); + if (NULL == st->xenstore) { + fprintf(stderr,"%s: can't connect to %s\n", __FUNCTION__, + xs_domain_dev()); + return; + } +#endif + + xs_watch(st->xenstore, "/", "token"); + st->ch = g_io_channel_unix_new(xs_fileno(st->xenstore)); + st->id = g_io_add_watch(st->ch, G_IO_IN, watch_trigger, st); +} + +static void +xenstore_finalize(GObject *object) +{ + XenStore *st = XENSTORE(object); + + if (trace) + fprintf(stderr,"%s\n", __FUNCTION__); + if (st->id) + g_source_destroy(g_main_context_find_source_by_id + (g_main_context_default(), st->id)); + node_remove(st->root); + (*parent_class->finalize)(object); +} + +/* ------------------------------------------------------------------------- */ + +static GtkTreeModelFlags +xenstore_get_flags(GtkTreeModel *tree_model) +{ + XenStore *st = XENSTORE(tree_model); + + if (trace > 2) + fprintf(stderr,"%s: trace\n", __FUNCTION__); + g_return_val_if_fail(IS_XENSTORE(st), (GtkTreeModelFlags)0); + return GTK_TREE_MODEL_ITERS_PERSIST; +} + +static gint +xenstore_get_n_columns(GtkTreeModel *tree_model) +{ + XenStore *st = XENSTORE(tree_model); + + g_return_val_if_fail(IS_XENSTORE(st), (GtkTreeModelFlags)0); + return XENSTORE_N_COLUMNS; +} + +static GType +xenstore_get_column_type(GtkTreeModel *tree_model, + gint index) +{ + XenStore *st = XENSTORE(tree_model); + enum xenstore_cols column = index; + + if (trace > 2) + fprintf(stderr,"%s: <= %d\n", __FUNCTION__, index); + g_return_val_if_fail(IS_XENSTORE(st), (GtkTreeModelFlags)0); + switch(column) { + case XENSTORE_COL_NAME: + case XENSTORE_COL_VALUE: + case XENSTORE_COL_PATH: + return G_TYPE_STRING; + case XENSTORE_N_COLUMNS: + break; + } + return G_TYPE_INVALID; +} + +static gboolean +xenstore_get_iter(GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreePath *path) +{ + XenStore *st = XENSTORE(tree_model); + struct xs_node *parent, *child = NULL; + struct list_head *item; + gint *indices, i, j; + + if (trace > 2) + fprintf(stderr,"%s: trace\n", __FUNCTION__); + g_assert(IS_XENSTORE(st)); + g_assert(path!=NULL); + + parent = st->root; + indices = gtk_tree_path_get_indices(path); + for (i = 0; i < gtk_tree_path_get_depth(path); i++) { + if (-1 == parent->nchildren) + node_add_children(st, parent); + + j = 0; + list_for_each(item, &parent->children) { + child = list_entry(item, struct xs_node, siblings); + if (j == indices[i]) + break; + j++; + } + if (j != indices[i]) + return FALSE; + + if (trace > 1) + fprintf(stderr,"%s: %d:%d %*s\"%s\"\n", __FUNCTION__, + i, indices[i], 3*i, "", + child ? child->xs_name : "<null>"); + parent = child; + } + + if (NULL == child) + return FALSE; + memset(iter,0,sizeof(*iter)); + iter->user_data = child; + return TRUE; +} + +static GtkTreePath* +xenstore_get_path(GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + XenStore *st = XENSTORE(tree_model); + struct xs_node *find = iter->user_data; + + return do_get_path(st, find); +} + +static void +xenstore_get_value(GtkTreeModel *tree_model, + GtkTreeIter *iter, + gint index, + GValue *value) +{ + XenStore *st = XENSTORE(tree_model); + enum xenstore_cols column = index; + struct xs_transaction_handle *xst; + struct xs_node *node = iter->user_data; + char *xs_value; + + if (trace > 2) + fprintf(stderr,"%s: \"%s\" %d\n", __FUNCTION__, node->xs_path, index); + switch (column) { + case XENSTORE_COL_NAME: + g_value_init(value, G_TYPE_STRING); + g_value_set_string(value, node->xs_name); + break; + case XENSTORE_COL_PATH: + g_value_init(value, G_TYPE_STRING); + g_value_set_string(value, node->xs_path); + break; + case XENSTORE_COL_VALUE: + if (NULL == (xst = xs_transaction_start(st->xenstore))) + break; + xs_value = xs_read(st->xenstore, xst, node->xs_path, NULL); + g_value_init(value, G_TYPE_STRING); + g_value_set_string(value, xs_value); + free(xs_value); + xs_transaction_end(st->xenstore, xst, 0); + break; + case XENSTORE_N_COLUMNS: + break; + } +} + +static gboolean +xenstore_iter_next(GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + XenStore *st = XENSTORE(tree_model); + struct xs_node *node = iter->user_data; + struct xs_node *next; + + if (trace > 1) + fprintf(stderr,"%s: <= \"%s\"\n", __FUNCTION__, node->xs_path); + if (-1 == node->nchildren) + node_add_children(st, node); + + if (node->siblings.next == &node->parent->children) { + if (trace > 2) + fprintf(stderr,"%s: EOF\n", __FUNCTION__); + return FALSE; + } + + next = list_entry(node->siblings.next, struct xs_node, siblings); + if (trace > 2) + fprintf(stderr,"%s: => \"%s\"\n", __FUNCTION__, next->xs_path); + iter->user_data = next; + return TRUE; +} + + +static gboolean +xenstore_iter_has_child(GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + return xenstore_iter_n_children(tree_model, iter) ? TRUE : FALSE; +} + +static gboolean +xenstore_iter_parent(GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *child) +{ + struct xs_node *node = child->user_data; + + if (trace > 1) + fprintf(stderr,"%s: <= \"%s\"\n", __FUNCTION__, node->xs_path); + if (NULL == node->parent) + return FALSE; + + if (trace > 2) + fprintf(stderr,"%s: => \"%s\"\n", __FUNCTION__, + node->parent ? node->parent->xs_path : "<null>"); + memset(iter,0,sizeof(*iter)); + iter->user_data = node->parent; + return TRUE; +} + +static gint +xenstore_iter_n_children(GtkTreeModel *tree_model, + GtkTreeIter *iter) +{ + XenStore *st = XENSTORE(tree_model); + struct xs_node *node = iter->user_data; + + if (trace > 1) + fprintf(stderr,"%s: <= \"%s\"\n", __FUNCTION__, node->xs_path); + if (-1 == node->nchildren) + node_add_children(st, node); + if (trace > 2) + fprintf(stderr,"%s: => %d\n", __FUNCTION__, node->nchildren); + return node->nchildren; +} + +static gboolean +xenstore_iter_nth_child(GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent, + gint n) +{ + XenStore *st = XENSTORE(tree_model); + struct xs_node *node = parent ? parent->user_data : NULL; + struct xs_node *child = NULL; + struct list_head *item; + int i; + + if (trace > 1) + fprintf(stderr,"%s: <= \"%s\" %d\n", __FUNCTION__, + node ? node->xs_path : "<null>", n); + if (NULL == node) + node = st->root; + if (-1 == node->nchildren) + node_add_children(st, node); + if (0 == node->nchildren) + return FALSE; + + i = 0; + list_for_each(item, &node->children) { + child = list_entry(item, struct xs_node, siblings); + if (i == n) + break; + n++; + } + if (i != n) + return FALSE; + + g_assert(NULL != child); + memset(iter,0,sizeof(*iter)); + iter->user_data = child; + return TRUE; +} + +static gboolean +xenstore_iter_children(GtkTreeModel *tree_model, + GtkTreeIter *iter, + GtkTreeIter *parent) +{ + return xenstore_iter_nth_child(tree_model, iter, parent, 0); +} + +/* ------------------------------------------------------------------------- */ + +XenStore* +xenstore_new(void) +{ + if (trace) + fprintf(stderr,"%s\n", __FUNCTION__); + return g_object_new(XENSTORE_TYPE, NULL); +} + |