aboutsummaryrefslogtreecommitdiffstats
path: root/xs_store.c
diff options
context:
space:
mode:
authorkraxel <kraxel>2005-12-08 11:17:50 +0000
committerkraxel <kraxel>2005-12-08 11:17:50 +0000
commite22cc1e84130dfe1086088c0452efc6596e5b855 (patch)
tree95045ace03f576aa357b079a780853f66044c0ad /xs_store.c
downloadxenwatch-e22cc1e84130dfe1086088c0452efc6596e5b855.tar.gz
Initial revision
Diffstat (limited to 'xs_store.c')
-rw-r--r--xs_store.c693
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);
+}
+