Hi

Here is an implementation of object tracking.

I have slightly extended the tracking API already defined to include
an object create & destroy notification.

Regards
Angus

---
 corosync/Makefile                |    2 +-
 corosync/exec/apidef.c           |    2 +
 corosync/exec/objdb.c            |  268 +++++++++++++++++++++++++++++++++++++-
 corosync/exec/objdb.h            |   44 ++++++-
 corosync/include/confdb.h        |   33 ++++-
 corosync/include/coroapi.h       |   49 +++++++-
 corosync/include/ipc_confdb.h    |   30 ++++-
 corosync/include/mar_gen.h       |    2 +-
 corosync/lib/confdb.c            |  148 ++++++++++++++++++---
 corosync/man/corosync-objctl.8   |   10 +-
 corosync/services/confdb.c       |  106 ++++++++++++++-
 corosync/test/testconfdb.c       |    4 +-
 corosync/tools/corosync-objctl.c |  147 ++++++++++++++++++++-
 13 files changed, 799 insertions(+), 46 deletions(-)

diff --git a/corosync/Makefile b/corosync/Makefile
index 17758c7..445fcac 100644
--- a/corosync/Makefile
+++ b/corosync/Makefile
@@ -173,7 +173,7 @@ install: all
        install -m 755 $(builddir)exec/*lcrso $(DESTDIR)$(LCRSODIR)
        install -m 755 $(builddir)services/*lcrso $(DESTDIR)$(LCRSODIR)
        install -m 755 $(builddir)exec/corosync $(DESTDIR)$(SBINDIR)
-       install -m 755 $(builddir)tools/objctl $(DESTDIR)$(SBINDIR)
+       install -m 755 $(builddir)tools/corosync-objctl $(DESTDIR)$(SBINDIR)
        install -m 700 $(builddir)tools/keygen $(DESTDIR)$(SBINDIR)/ais-keygen
 
        if [ ! -f $(DESTDIR)$(ETCDIR)/penais.conf ] ; then         \
diff --git a/corosync/exec/apidef.c b/corosync/exec/apidef.c
index 8105a51..c04c586 100644
--- a/corosync/exec/apidef.c
+++ b/corosync/exec/apidef.c
@@ -101,6 +101,8 @@ void apidef_init (struct objdb_iface_ver0 *objdb) {
        apidef_corosync_api_v1.object_find_from = objdb->object_find_from;
        apidef_corosync_api_v1.object_iter_from = objdb->object_iter_from;
        apidef_corosync_api_v1.object_key_iter_from = 
objdb->object_key_iter_from;
+       apidef_corosync_api_v1.object_track_start = objdb->object_track_start;
+       apidef_corosync_api_v1.object_track_stop = objdb->object_track_stop;
        apidef_corosync_api_v1.object_write_config = objdb->object_write_config;
 }
 
diff --git a/corosync/exec/objdb.c b/corosync/exec/objdb.c
index 785aff9..a2cc888 100644
--- a/corosync/exec/objdb.c
+++ b/corosync/exec/objdb.c
@@ -50,6 +50,17 @@ struct object_key {
        struct list_head list;
 };
 
+struct object_tracker {
+       unsigned int object_handle;
+       void * data_pt;
+       object_track_depth_t depth;
+       object_key_change_notify_fn_t key_change_notify_fn;
+       object_create_notify_fn_t object_create_notify_fn;
+       object_destroy_notify_fn_t object_destroy_notify_fn;
+       struct list_head tracker_list;
+       struct list_head object_list;
+};
+
 struct object_instance {
        void *object_name;
        int object_name_len;
@@ -66,6 +77,7 @@ struct object_instance {
        int object_valid_list_entries;
        struct object_key_valid *object_key_valid_list;
        int object_key_valid_list_entries;
+       struct list_head track_head;
 };
 
 struct object_find_instance {
@@ -76,6 +88,7 @@ struct object_find_instance {
 };
 
 struct objdb_iface_ver0 objdb_iface;
+struct list_head objdb_trackers_head;
 
 static struct hdb_handle_database object_instance_database = {
        .handle_count   = 0,
@@ -118,6 +131,8 @@ static int objdb_init (void)
        list_init (&instance->key_head);
        list_init (&instance->child_head);
        list_init (&instance->child_list);
+       list_init (&instance->track_head);
+       list_init (&objdb_trackers_head);
 
        hdb_handle_put (&object_instance_database, handle);
        return (0);
@@ -129,6 +144,153 @@ error_exit:
        return (-1);
 }
 
+static int _object_notify_deleted_children(struct object_instance *parent_pt)
+{
+       struct list_head *list;
+       struct list_head *notify_list;
+       int res;
+       struct object_instance *obj_pt = NULL;
+       struct object_tracker * tracker_pt;
+
+       for (list = parent_pt->child_head.next;
+                list != &parent_pt->child_head; list = list->next) {
+
+               obj_pt = list_entry(list, struct object_instance,
+                                                       child_list);
+               res = _object_notify_deleted_children(obj_pt);
+               if (res)
+                       return res;
+
+               for (notify_list = obj_pt->track_head.next;
+                        notify_list != &obj_pt->track_head;
+                        notify_list = notify_list->next) {
+
+                       tracker_pt = list_entry (notify_list, struct 
object_tracker, object_list);
+
+                       if ((tracker_pt != NULL) &&
+                               (tracker_pt->object_destroy_notify_fn != NULL))
+                               
tracker_pt->object_destroy_notify_fn(parent_pt->object_handle,
+                                                                               
                         obj_pt->object_name,
+                                                                               
                         obj_pt->object_name_len,
+                                                                               
                         tracker_pt->data_pt);
+               }
+       }
+
+       return 0;
+}
+
+static void object_created_notification(unsigned int object_handle,
+                                                                               
unsigned int parent_object_handle,
+                                                                               
void *name_pt, int name_len)
+{
+       struct list_head * list;
+       struct object_instance * obj_pt;
+       struct object_tracker * tracker_pt;
+       unsigned int obj_handle = object_handle;
+       unsigned int res;
+
+       do {
+               res = hdb_handle_get (&object_instance_database,
+                                                         obj_handle, (void 
*)&obj_pt);
+
+               for (list = obj_pt->track_head.next;
+                        list != &obj_pt->track_head; list = list->next) {
+
+                       tracker_pt = list_entry (list, struct object_tracker, 
object_list);
+
+                       if (((obj_handle == parent_object_handle) ||
+                                (tracker_pt->depth == 
OBJECT_TRACK_DEPTH_RECURSIVE)) &&
+                               (tracker_pt->object_create_notify_fn != NULL)) {
+                               
tracker_pt->object_create_notify_fn(object_handle, parent_object_handle,
+                                                                        
name_pt, name_len,
+                                                                        
tracker_pt->data_pt);
+                       }
+               }
+
+               hdb_handle_put (&object_instance_database, obj_handle);
+               obj_handle = obj_pt->parent_handle;
+
+       } while (obj_pt->object_handle != OBJECT_PARENT_HANDLE);
+
+}
+
+static void object_pre_deletion_notification(unsigned int object_handle,
+                                                                               
         unsigned int parent_object_handle,
+                                                                               
         void *name_pt, int name_len)
+{
+       struct list_head * list;
+       struct object_instance * obj_pt;
+       struct object_tracker * tracker_pt;
+       unsigned int obj_handle = object_handle;
+       unsigned int res;
+
+       do {
+               res = hdb_handle_get (&object_instance_database,
+                                                         obj_handle, (void 
*)&obj_pt);
+
+               for (list = obj_pt->track_head.next;
+                        list != &obj_pt->track_head; list = list->next) {
+
+                       tracker_pt = list_entry (list, struct object_tracker, 
object_list);
+
+                       if (((obj_handle == parent_object_handle) ||
+                                (tracker_pt->depth == 
OBJECT_TRACK_DEPTH_RECURSIVE)) &&
+                               (tracker_pt->object_destroy_notify_fn != NULL)) 
{
+                               
tracker_pt->object_destroy_notify_fn(parent_object_handle,
+                                                                        
name_pt, name_len,
+                                                                        
tracker_pt->data_pt);
+                       }
+               }
+               /* notify child object listeners */
+               if (obj_handle == object_handle)
+                       _object_notify_deleted_children(obj_pt);
+
+               hdb_handle_put (&object_instance_database, obj_handle);
+               obj_handle = obj_pt->parent_handle;
+
+       } while (obj_pt->object_handle != OBJECT_PARENT_HANDLE);
+
+}
+
+static void object_key_changed_notification(unsigned int object_handle,
+                                                                               
        void *name_pt,  int name_len,
+                                                                               
        void *value_pt, int value_len,
+                                                                               
        object_change_type_t type)
+{
+       struct list_head * list;
+       struct object_instance * obj_pt;
+       struct object_instance * owner_pt = NULL;
+       struct object_tracker * tracker_pt;
+       unsigned int obj_handle = object_handle;
+       unsigned int res;
+
+       do {
+               res = hdb_handle_get (&object_instance_database,
+                                                         obj_handle, (void 
*)&obj_pt);
+               if (owner_pt == NULL)
+                       owner_pt = obj_pt;
+
+               for (list = obj_pt->track_head.next;
+                        list != &obj_pt->track_head; list = list->next) {
+
+                       tracker_pt = list_entry (list, struct object_tracker, 
object_list);
+
+                       if (((obj_handle == object_handle) ||
+                                (tracker_pt->depth == 
OBJECT_TRACK_DEPTH_RECURSIVE)) &&
+                               (tracker_pt->key_change_notify_fn != NULL))
+                               tracker_pt->key_change_notify_fn(type, 
obj_pt->parent_handle, object_handle,
+                                                                               
                 owner_pt->object_name, owner_pt->object_name_len,
+                                                                               
                 name_pt, name_len,
+                                                                               
                 value_pt, value_len,
+                                                                               
                 tracker_pt->data_pt);
+               }
+
+               hdb_handle_put (&object_instance_database, obj_handle);
+               obj_handle = obj_pt->parent_handle;
+
+       } while (obj_pt->object_handle != OBJECT_PARENT_HANDLE);
+}
+
 /*
  * object db create/destroy/set
  */
@@ -189,6 +351,7 @@ static int object_create (
        list_init (&object_instance->key_head);
        list_init (&object_instance->child_head);
        list_init (&object_instance->child_list);
+       list_init (&object_instance->track_head);
        object_instance->object_name = malloc (object_name_len);
        if (object_instance->object_name == 0) {
                goto error_put_destroy;
@@ -211,6 +374,10 @@ static int object_create (
        hdb_handle_put (&object_instance_database, *object_handle);
 
        hdb_handle_put (&object_instance_database, parent_object_handle);
+       object_created_notification(object_instance->object_handle,
+                                                               
object_instance->parent_handle,
+                                                               
object_instance->object_name,
+                                                               
object_instance->object_name_len);
 
        return (0);
 
@@ -322,6 +489,8 @@ static int object_key_create (
 
        list_init (&object_key->list);
        list_add (&object_key->list, &instance->key_head);
+       object_key_changed_notification(object_handle, key_name, key_len,
+                                                               value, 
value_len, OBJECT_KEY_CREATED);
 
        return (0);
 
@@ -338,7 +507,6 @@ error_exit:
        return (-1);
 }
 
-
 static int _clear_object(struct object_instance *instance)
 {
        struct list_head *list;
@@ -390,6 +558,11 @@ static int object_destroy (
                return (res);
        }
 
+       object_pre_deletion_notification(object_handle,
+                                                                        
instance->parent_handle,
+                                                                        
instance->object_name,
+                                                                        
instance->object_name_len);
+
        /* Recursively clear sub-objects & keys */
        res = _clear_object(instance);
 
@@ -641,6 +814,9 @@ static int object_key_delete (
        }
 
        hdb_handle_put (&object_instance_database, object_handle);
+       if (ret == 0)
+               object_key_changed_notification(object_handle, key_name, 
key_len,
+                                                                               
value, value_len, OBJECT_KEY_DELETED);
        return (ret);
 
 error_exit:
@@ -735,6 +911,9 @@ static int object_key_replace (
        }
 
        hdb_handle_put (&object_instance_database, object_handle);
+       if (ret == 0)
+               object_key_changed_notification(object_handle, key_name, 
key_len,
+                                                                               
new_value, new_value_len, OBJECT_KEY_REPLACED);
        return (ret);
 
 error_put:
@@ -1093,8 +1272,6 @@ error_exit:
 }
 

-
-
 static int object_parent_get(unsigned int object_handle,
                             unsigned int *parent_handle)
 {
@@ -1118,6 +1295,89 @@ static int object_parent_get(unsigned int object_handle,
 }
 

+static int object_track_start(unsigned int object_handle,
+                                                         object_track_depth_t 
depth,
+                                                         
object_key_change_notify_fn_t key_change_notify_fn,
+                                                         
object_create_notify_fn_t object_create_notify_fn,
+                                                         
object_destroy_notify_fn_t object_destroy_notify_fn,
+                                                         void * priv_data_pt)
+{
+       struct object_instance *instance;
+       unsigned int res;
+       struct object_tracker * tracker_pt;
+
+       res = hdb_handle_get (&object_instance_database,
+                             object_handle, (void *)&instance);
+       if (res != 0) {
+               return (res);
+       }
+       tracker_pt = malloc(sizeof(struct object_tracker));
+
+       tracker_pt->depth = depth;
+       tracker_pt->object_handle = object_handle;
+       tracker_pt->key_change_notify_fn = key_change_notify_fn;
+       tracker_pt->object_create_notify_fn = object_create_notify_fn;
+       tracker_pt->object_destroy_notify_fn = object_destroy_notify_fn;
+       tracker_pt->data_pt = priv_data_pt;
+
+       list_init(&tracker_pt->object_list);
+       list_init(&tracker_pt->tracker_list);
+
+       list_add(&tracker_pt->object_list, &instance->track_head);
+       list_add(&tracker_pt->tracker_list, &objdb_trackers_head);
+
+       hdb_handle_put (&object_instance_database, object_handle);
+
+       return (res);
+}
+
+static void object_track_stop(object_key_change_notify_fn_t 
key_change_notify_fn,
+                                                         
object_create_notify_fn_t object_create_notify_fn,
+                                                         
object_destroy_notify_fn_t object_destroy_notify_fn,
+                                                         void * priv_data_pt)
+{
+       struct object_instance *instance;
+       struct object_tracker * tracker_pt = NULL;
+       struct object_tracker * obj_tracker_pt = NULL;
+       struct list_head *list, *tmp_list;
+       struct list_head *obj_list, *tmp_obj_list;
+       unsigned int res;
+
+       /* go through the global list and find all the trackers to stop */
+       for (list = objdb_trackers_head.next, tmp_list = list->next;
+                list != &objdb_trackers_head; list = tmp_list, tmp_list = 
tmp_list->next) {
+
+               tracker_pt = list_entry (list, struct object_tracker, 
tracker_list);
+
+               if (tracker_pt && (tracker_pt->data_pt == priv_data_pt) &&
+                       (tracker_pt->object_create_notify_fn == 
object_create_notify_fn) &&
+                       (tracker_pt->object_destroy_notify_fn == 
object_destroy_notify_fn) &&
+                       (tracker_pt->key_change_notify_fn == 
key_change_notify_fn)) {
+
+                       /* get the object & take this tracker off of it's list. 
*/
+
+                       res = hdb_handle_get (&object_instance_database,
+                                                                 
tracker_pt->object_handle, (void *)&instance);
+                       if (res != 0) continue;
+
+                       for (obj_list = instance->track_head.next, tmp_obj_list 
= obj_list->next;
+                                obj_list != &instance->track_head; obj_list = 
tmp_obj_list, tmp_obj_list = tmp_obj_list->next) {
+
+                               obj_tracker_pt = list_entry (obj_list, struct 
object_tracker, object_list);
+                               if (obj_tracker_pt == tracker_pt) {
+                                       /* this is the tracker we are after. */
+                                       list_del(obj_list);
+                               }
+                       }
+                       hdb_handle_put (&object_instance_database, 
tracker_pt->object_handle);
+
+                       /* remove the tracker off of the global list */
+                       list_del(list);
+                       free(tracker_pt);
+               }
+       }
+}
+
 static int object_dump(unsigned int object_handle,
                       FILE *file)
 {
@@ -1178,6 +1438,8 @@ struct objdb_iface_ver0 objdb_iface = {
        .object_iter_from       = object_iter_from,
        .object_priv_get        = object_priv_get,
        .object_parent_get      = object_parent_get,
+       .object_track_start     = object_track_start,
+       .object_track_stop      = object_track_stop,
        .object_dump            = object_dump,
        .object_write_config    = object_write_config,
 };
diff --git a/corosync/exec/objdb.h b/corosync/exec/objdb.h
index 9656eaa..608bd42 100644
--- a/corosync/exec/objdb.h
+++ b/corosync/exec/objdb.h
@@ -40,11 +40,39 @@
 
 #include <stdio.h>
 
+typedef enum {
+       OBJECT_TRACK_DEPTH_ONE,
+       OBJECT_TRACK_DEPTH_RECURSIVE
+} object_track_depth_t;
+
+typedef enum {
+       OBJECT_KEY_CREATED,
+       OBJECT_KEY_REPLACED,
+       OBJECT_KEY_DELETED
+} object_change_type_t;
+
+typedef void (*object_key_change_notify_fn_t)(object_change_type_t change_type,
+                                                                               
          unsigned int parent_object_handle,
+                                                                               
          unsigned int object_handle,
+                                                                               
          void *object_name_pt, int object_name_len,
+                                                                               
          void *key_name_pt, int key_len,
+                                                                               
          void *key_value_pt, int key_value_len,
+                                                                               
          void *priv_data_pt);
+
+typedef void (*object_create_notify_fn_t) (unsigned int parent_object_handle,
+                                                                               
   unsigned int object_handle,
+                                                                               
   void *name_pt, int name_len,
+                                                                               
   void *priv_data_pt);
+
+typedef void (*object_destroy_notify_fn_t) (unsigned int parent_object_handle,
+                                                                               
        void *name_pt, int name_len,
+                                                                               
        void *priv_data_pt);
+
 struct object_valid {
        char *object_name;
        int object_len;
 };
-       
+
 struct object_key_valid {
        char *key_name;
        int key_len;
@@ -174,6 +202,20 @@ struct objdb_iface_ver0 {
                void **value,
                int *value_len);
 
+       int (*object_track_start) (
+               unsigned int object_handle,
+               object_track_depth_t depth,
+               object_key_change_notify_fn_t key_change_notify_fn,
+               object_create_notify_fn_t object_create_notify_fn,
+               object_destroy_notify_fn_t object_destroy_notify_fn,
+               void * priv_data_pt);
+
+       void (*object_track_stop) (
+               object_key_change_notify_fn_t key_change_notify_fn,
+               object_create_notify_fn_t object_create_notify_fn,
+               object_destroy_notify_fn_t object_destroy_notify_fn,
+               void * priv_data_pt);
+
        int (*object_write_config) (char **error_string);
 };
 
diff --git a/corosync/include/confdb.h b/corosync/include/confdb.h
index 831d982..7e1b9ee 100644
--- a/corosync/include/confdb.h
+++ b/corosync/include/confdb.h
@@ -50,6 +50,11 @@ typedef enum {
 } confdb_dispatch_t;
 
 typedef enum {
+       CONFDB_TRACK_DEPTH_ONE,
+       CONFDB_TRACK_DEPTH_RECURSIVE
+} confdb_track_depth_t;
+
+typedef enum {
        CONFDB_OK = 1,
        CONFDB_ERR_LIBRARY = 2,
        CONFDB_ERR_TIMEOUT = 5,
@@ -65,9 +70,15 @@ typedef enum {
        CONFDB_ERR_SECURITY = 29,
 } confdb_error_t;
 
+typedef enum {
+       OBJECT_KEY_CREATED,
+       OBJECT_KEY_REPLACED,
+       OBJECT_KEY_DELETED
+} confdb_change_type_t;
 
-typedef void (*confdb_change_notify_fn_t) (
+typedef void (*confdb_key_change_notify_fn_t) (
        confdb_handle_t handle,
+       confdb_change_type_t change_type,
        unsigned int parent_object_handle,
        unsigned int object_handle,
        void *object_name,
@@ -77,8 +88,23 @@ typedef void (*confdb_change_notify_fn_t) (
        void *key_value,
        int key_value_len);
 
+typedef void (*confdb_object_create_notify_fn_t) (
+       confdb_handle_t handle,
+       unsigned int parent_object_handle,
+       unsigned int object_handle,
+       uint8_t *name_pt,
+       int  name_len);
+
+typedef void (*confdb_object_delete_notify_fn_t) (
+       confdb_handle_t handle,
+       unsigned int parent_object_handle,
+       uint8_t *name_pt,
+       int  name_len);
+
 typedef struct {
-       confdb_change_notify_fn_t confdb_change_notify_fn;
+       confdb_object_create_notify_fn_t confdb_object_create_change_notify_fn;
+       confdb_object_delete_notify_fn_t confdb_object_delete_change_notify_fn;
+       confdb_key_change_notify_fn_t confdb_key_change_notify_fn;
 } confdb_callbacks_t;
 
 /** @} */
@@ -119,7 +145,6 @@ confdb_error_t confdb_dispatch (
        confdb_handle_t handle,
        confdb_dispatch_t dispatch_types);
 
-
 /*
  * Change notification
  */
@@ -194,7 +219,7 @@ confdb_error_t confdb_key_replace (
  * Object queries
  * "find" loops through all objects of a given name and is also
  * a quick way of finding a specific object,
- * "iter" returns ech object in sequence.
+ * "iter" returns each object in sequence.
  */
 confdb_error_t confdb_object_find_start (
        confdb_handle_t handle,
diff --git a/corosync/include/coroapi.h b/corosync/include/coroapi.h
index 0cd2335..aa9baa8 100644
--- a/corosync/include/coroapi.h
+++ b/corosync/include/coroapi.h
@@ -90,13 +90,46 @@ struct object_valid {
        char *object_name;
        int object_len;
 };
-       
+
 struct object_key_valid {
        char *key_name;
        int key_len;
        int (*validate_callback) (void *key, int key_len, void *value, int 
value_len);
 };
 
+typedef enum {
+       OBJECT_TRACK_DEPTH_ONE,
+       OBJECT_TRACK_DEPTH_RECURSIVE
+} object_track_depth_t;
+
+typedef enum {
+       OBJECT_KEY_CREATED,
+       OBJECT_KEY_REPLACED,
+       OBJECT_KEY_DELETED
+} object_change_type_t;
+
+typedef void (*object_key_change_notify_fn_t)(object_change_type_t change_type,
+                                                                               
          unsigned int parent_object_handle,
+                                                                               
          unsigned int object_handle,
+                                                                               
          void *object_name_pt, int object_name_len,
+                                                                               
          void *key_name_pt, int key_len,
+                                                                               
          void *key_value_pt, int key_value_len,
+                                                                               
          void *priv_data_pt);
+
+typedef void (*object_create_notify_fn_t) (unsigned int parent_object_handle,
+                                                                               
   unsigned int object_handle,
+                                                                               
   uint8_t *name_pt, int name_len,
+                                                                               
   void *priv_data_pt);
+
+typedef void (*object_destroy_notify_fn_t) (unsigned int parent_object_handle,
+                                                                               
        uint8_t *name_pt, int name_len,
+                                                                               
        void *priv_data_pt);
+typedef void (*object_notify_callback_fn_t)(unsigned int object_handle,
+                                                                               
        void *key_name, int key_len,
+                                                                               
        void *value, int value_len,
+                                                                               
        object_change_type_t type,
+                                                                               
        void * priv_data_pt);
+
 #endif /* OBJECT_PARENT_HANDLE_DEFINED */
 
 struct corosync_api_v1 {
@@ -222,6 +255,20 @@ struct corosync_api_v1 {
                void **value,
                int *value_len);
 
+       int (*object_track_start) (
+               unsigned int object_handle,
+               object_track_depth_t depth,
+               object_key_change_notify_fn_t key_change_notify_fn,
+               object_create_notify_fn_t object_create_notify_fn,
+               object_destroy_notify_fn_t object_destroy_notify_fn,
+               void * priv_data_pt);
+
+       void (*object_track_stop) (
+               object_key_change_notify_fn_t key_change_notify_fn,
+               object_create_notify_fn_t object_create_notify_fn,
+               object_destroy_notify_fn_t object_destroy_notify_fn,
+               void * priv_data_pt);
+
        int (*object_write_config) (char **error_string);
 
        /*
diff --git a/corosync/include/ipc_confdb.h b/corosync/include/ipc_confdb.h
index acc0871..ab01a6f 100644
--- a/corosync/include/ipc_confdb.h
+++ b/corosync/include/ipc_confdb.h
@@ -51,7 +51,8 @@ enum req_confdb_types {
        MESSAGE_REQ_CONFDB_KEY_ITER = 9,
        MESSAGE_REQ_CONFDB_TRACK_START = 10,
        MESSAGE_REQ_CONFDB_TRACK_STOP = 11,
-       MESSAGE_REQ_CONFDB_WRITE = 12
+       MESSAGE_REQ_CONFDB_XPATH_EVAL_EXPRESSION = 12,
+       MESSAGE_REQ_CONFDB_WRITE = 13
 };
 
 enum res_confdb_types {
@@ -67,8 +68,10 @@ enum res_confdb_types {
        MESSAGE_RES_CONFDB_KEY_ITER = 9,
        MESSAGE_RES_CONFDB_TRACK_START = 10,
        MESSAGE_RES_CONFDB_TRACK_STOP = 11,
-       MESSAGE_RES_CONFDB_CHANGE_CALLBACK = 12,
-       MESSAGE_RES_CONFDB_WRITE = 13
+       MESSAGE_RES_CONFDB_KEY_CHANGE_CALLBACK = 12,
+       MESSAGE_RES_CONFDB_OBJECT_CREATE_CALLBACK = 13,
+       MESSAGE_RES_CONFDB_OBJECT_DESTROY_CALLBACK = 14,
+       MESSAGE_RES_CONFDB_WRITE = 15
 };
 

@@ -174,8 +177,9 @@ struct res_lib_confdb_write {
        mar_name_t error __attribute__((aligned(8)));
 };
 
-struct res_lib_confdb_change_callback {
+struct res_lib_confdb_key_change_callback {
        mar_res_header_t header __attribute__((aligned(8)));
+       mar_uint32_t change_type __attribute__((aligned(8)));
        mar_uint32_t parent_object_handle __attribute__((aligned(8)));
        mar_uint32_t object_handle __attribute__((aligned(8)));
        mar_name_t object_name __attribute__((aligned(8)));
@@ -183,5 +187,23 @@ struct res_lib_confdb_change_callback {
        mar_name_t key_value __attribute__((aligned(8)));
 };
 
+struct res_lib_confdb_object_create_callback {
+       mar_res_header_t header __attribute__((aligned(8)));
+       mar_uint32_t parent_object_handle __attribute__((aligned(8)));
+       mar_uint32_t object_handle __attribute__((aligned(8)));
+       mar_name_t name __attribute__((aligned(8)));
+};
+
+struct res_lib_confdb_object_destroy_callback {
+       mar_res_header_t header __attribute__((aligned(8)));
+       mar_uint32_t parent_object_handle __attribute__((aligned(8)));
+       mar_name_t name __attribute__((aligned(8)));
+};
+
+struct req_lib_confdb_object_track_start {
+       mar_req_header_t header __attribute__((aligned(8)));
+       mar_uint32_t object_handle __attribute__((aligned(8)));
+       mar_uint32_t flags __attribute__((aligned(8)));
+};
 
 #endif /* IPC_CONFDB_H_DEFINED */
diff --git a/corosync/include/mar_gen.h b/corosync/include/mar_gen.h
index 09a839d..af343e5 100644
--- a/corosync/include/mar_gen.h
+++ b/corosync/include/mar_gen.h
@@ -109,7 +109,7 @@ static inline char *get_mar_name_t (mar_name_t *name) {
         return ((char *)name->value);
 }
 
-static int mar_name_match(mar_name_t *name1, mar_name_t *name2)
+static inline int mar_name_match(mar_name_t *name1, mar_name_t *name2)
 {
         if (name1->length == name2->length) {
                 return ((strncmp ((char *)name1->value, (char *)name2->value,
diff --git a/corosync/lib/confdb.c b/corosync/lib/confdb.c
index 7e22c03..8ff8cb2 100644
--- a/corosync/lib/confdb.c
+++ b/corosync/lib/confdb.c
@@ -304,8 +304,10 @@ confdb_error_t confdb_dispatch (
        int cont = 1; /* always continue do loop except when set to 0 */
        int dispatch_avail;
        struct confdb_inst *confdb_inst;
-       struct res_lib_confdb_change_callback *res_confdb_change_callback;
        confdb_callbacks_t callbacks;
+       struct res_lib_confdb_key_change_callback *res_key_changed_pt;
+       struct res_lib_confdb_object_create_callback *res_object_created_pt;
+       struct res_lib_confdb_object_destroy_callback *res_object_destroyed_pt;
        struct res_overlay dispatch_data;
        int ignore_dispatch = 0;
 
@@ -400,24 +402,44 @@ confdb_error_t confdb_dispatch (
                 * Dispatch incoming message
                 */
                switch (dispatch_data.header.id) {
-               case MESSAGE_RES_CONFDB_CHANGE_CALLBACK:
-                       res_confdb_change_callback = (struct 
res_lib_confdb_change_callback *)&dispatch_data;
-
-                       callbacks.confdb_change_notify_fn (handle,
-                                                          
res_confdb_change_callback->parent_object_handle,
-                                                          
res_confdb_change_callback->object_handle,
-                                                          
res_confdb_change_callback->object_name.value,
-                                                          
res_confdb_change_callback->object_name.length,
-                                                          
res_confdb_change_callback->key_name.value,
-                                                          
res_confdb_change_callback->key_name.length,
-                                                          
res_confdb_change_callback->key_value.value,
-                                                          
res_confdb_change_callback->key_value.length);
-                       break;
-
-               default:
-                       error = SA_AIS_ERR_LIBRARY;
-                       goto error_nounlock;
-                       break;
+                       case MESSAGE_RES_CONFDB_KEY_CHANGE_CALLBACK:
+                               res_key_changed_pt = (struct 
res_lib_confdb_key_change_callback *)&dispatch_data;
+
+                               callbacks.confdb_key_change_notify_fn(handle,
+                                       res_key_changed_pt->change_type,
+                                       res_key_changed_pt->object_handle,
+                                       
res_key_changed_pt->parent_object_handle,
+                                       res_key_changed_pt->object_name.value,
+                                       res_key_changed_pt->object_name.length,
+                                       res_key_changed_pt->key_name.value,
+                                       res_key_changed_pt->key_name.length,
+                                       res_key_changed_pt->key_value.value,
+                                       res_key_changed_pt->key_value.length);
+                               break;
+
+                       case MESSAGE_RES_CONFDB_OBJECT_CREATE_CALLBACK:
+                               res_object_created_pt = (struct 
res_lib_confdb_object_create_callback *)&dispatch_data;
+
+                               
callbacks.confdb_object_create_change_notify_fn(handle,
+                                       res_object_created_pt->object_handle,
+                                       
res_object_created_pt->parent_object_handle,
+                                       res_object_created_pt->name.value,
+                                       res_object_created_pt->name.length);
+                               break;
+
+                       case MESSAGE_RES_CONFDB_OBJECT_DESTROY_CALLBACK:
+                               res_object_destroyed_pt = (struct 
res_lib_confdb_object_destroy_callback *)&dispatch_data;
+
+                               
callbacks.confdb_object_delete_change_notify_fn(handle,
+                                       
res_object_destroyed_pt->parent_object_handle,
+                                       res_object_destroyed_pt->name.value,
+                                       res_object_destroyed_pt->name.length);
+                               break;
+
+                       default:
+                               error = SA_AIS_ERR_LIBRARY;
+                               goto error_nounlock;
+                               break;
                }
 
                /*
@@ -1197,4 +1219,92 @@ error_exit:
        return (error);
 }
 
+confdb_error_t confdb_track_changes (
+       confdb_handle_t handle,
+       unsigned int object_handle,
+       unsigned int flags)
+{
+       confdb_error_t error;
+       struct confdb_inst *confdb_inst;
+       struct iovec iov[2];
+       struct req_lib_confdb_object_track_start req;
+       mar_res_header_t res;
+
+       error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void 
*)&confdb_inst);
+       if (error != SA_AIS_OK) {
+               return (error);
+       }
+
+       if (confdb_inst->standalone) {
+               error = CONFDB_ERR_NOT_SUPPORTED;
+               goto error_exit;
+       }
+
+       req.header.size = sizeof (struct req_lib_confdb_object_track_start);
+       req.header.id = MESSAGE_REQ_CONFDB_TRACK_START;
+       req.object_handle = object_handle;
+       req.flags = flags;
+
+       iov[0].iov_base = (char *)&req;
+       iov[0].iov_len = sizeof (struct req_lib_confdb_object_track_start);
+
+       pthread_mutex_lock (&confdb_inst->response_mutex);
+
+       error = saSendMsgReceiveReply (confdb_inst->response_fd, iov, 1,
+               &res, sizeof ( mar_res_header_t));
+
+       pthread_mutex_unlock (&confdb_inst->response_mutex);
+       if (error != SA_AIS_OK) {
+               goto error_exit;
+       }
+
+       error = res.error;
+
+error_exit:
+       saHandleInstancePut (&confdb_handle_t_db, handle);
+
+       return (error);
+}
+
+confdb_error_t confdb_stop_track_changes (confdb_handle_t handle)
+{
+       confdb_error_t error;
+       struct confdb_inst *confdb_inst;
+       struct iovec iov[2];
+       mar_req_header_t req;
+       mar_res_header_t res;
+
+       error = saHandleInstanceGet (&confdb_handle_t_db, handle, (void 
*)&confdb_inst);
+       if (error != SA_AIS_OK) {
+               return (error);
+       }
+
+       if (confdb_inst->standalone) {
+               error = CONFDB_ERR_NOT_SUPPORTED;
+               goto error_exit;
+       }
+
+       req.size = sizeof (mar_req_header_t);
+       req.id = MESSAGE_REQ_CONFDB_TRACK_STOP;
+
+       iov[0].iov_base = (char *)&req;
+       iov[0].iov_len = sizeof (mar_req_header_t);
+
+       pthread_mutex_lock (&confdb_inst->response_mutex);
+
+       error = saSendMsgReceiveReply (confdb_inst->response_fd, iov, 1,
+               &res, sizeof ( mar_res_header_t));
+
+       pthread_mutex_unlock (&confdb_inst->response_mutex);
+       if (error != SA_AIS_OK) {
+               goto error_exit;
+       }
+
+       error = res.error;
+
+error_exit:
+       saHandleInstancePut (&confdb_handle_t_db, handle);
+
+       return (error);
+}
 
diff --git a/corosync/man/corosync-objctl.8 b/corosync/man/corosync-objctl.8
index f230008..250a99c 100644
--- a/corosync/man/corosync-objctl.8
+++ b/corosync/man/corosync-objctl.8
@@ -35,7 +35,7 @@
 .SH NAME
 corosync-objctl \- Configure objects in the Object Database
 .SH SYNOPSIS
-.B "corosync-objctl [\-c|\-w|\-d|\-a|\-h] <OBJECT-SPEC>..."
+.B "corosync-objctl [\-c|\-w|\-d|\-a|\-t\-h] <OBJECT-SPEC>..."
 .SH DESCRIPTION
 .B corosync-objctl
 is used to configure objects within the object database at runtime.
@@ -62,12 +62,16 @@ Create a new object.
 .B -d
 Delete an existing object.
 .TP
-.B "-w"
+.B -w
 Use this option when you want to write a new value to a key.
 .TP
-.B "-a"
+.B -a
 Display all values currently available.
 .TP
+.B -t
+Track changes to an object and it's children. As changes are made to the object
+they are printed out. this is kind of like a "tail -f" for the object database.
+.TP
 .B -h
 Print basic usage.
 .SH EXAMPLES
diff --git a/corosync/services/confdb.c b/corosync/services/confdb.c
index 2b56b00..440e44b 100644
--- a/corosync/services/confdb.c
+++ b/corosync/services/confdb.c
@@ -46,7 +46,7 @@
 #include "../exec/logsys.h"
 #include "../include/coroapi.h"
 
-LOGSYS_DECLARE_SUBSYS ("CONFDB", LOG_INFO);
+LOGSYS_DECLARE_SUBSYS ("CONFDB", LOG_DEBUG);
 
 static struct corosync_api_v1 *api;
 
@@ -74,7 +74,21 @@ static void message_handler_req_lib_confdb_write (void 
*conn, void *message);
 static void message_handler_req_lib_confdb_track_start (void *conn, void 
*message);
 static void message_handler_req_lib_confdb_track_stop (void *conn, void 
*message);
 
-
+static void confdb_notify_lib_of_key_change(object_change_type_t change_type,
+                                                                               
        unsigned int parent_object_handle,
+                                                                               
        unsigned int object_handle,
+                                                                               
        void *object_name_pt, int object_name_len,
+                                                                               
        void *key_name_pt, int key_name_len,
+                                                                               
        void *key_value_pt, int key_value_len,
+                                                                               
        void *priv_data_pt);
+
+static void confdb_notify_lib_of_new_object(unsigned int parent_object_handle,
+                                                                               
        unsigned int object_handle,
+                                                                               
        uint8_t *name_pt, int name_len,
+                                                                               
        void *priv_data_pt);
+static void confdb_notify_lib_of_destroyed_object(unsigned int 
parent_object_handle,
+                                                                               
                  uint8_t *name_pt, int name_len,
+                                                                               
                  void *priv_data_pt);
 /*
  * Library Handler Definition
  */
@@ -149,7 +163,7 @@ static struct corosync_lib_handler confdb_lib_engine[] =
        { /* 11 */
                .lib_handler_fn                         = 
message_handler_req_lib_confdb_track_stop,
                .response_size                          = sizeof 
(mar_res_header_t),
-               .response_id                            = 
MESSAGE_RES_CONFDB_TRACK_START,
+               .response_id                            = 
MESSAGE_RES_CONFDB_TRACK_STOP,
                .flow_control                           = 
COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED
        },
        { /* 12 */
@@ -230,6 +244,11 @@ static int confdb_lib_exit_fn (void *conn)
 {
 
        log_printf(LOG_LEVEL_DEBUG, "exit_fn for conn=%p\n", conn);
+       /* cleanup the object trackers for this client. */
+       api->object_track_stop(confdb_notify_lib_of_key_change,
+                                                  
confdb_notify_lib_of_new_object,
+                                                  
confdb_notify_lib_of_destroyed_object,
+                                                  api->ipc_conn_partner_get 
(conn));
        return (0);
 }
 
@@ -469,14 +488,84 @@ static void message_handler_req_lib_confdb_write (void 
*conn, void *message)
        api->ipc_conn_send_response(conn, &res_lib_confdb_write, 
sizeof(res_lib_confdb_write));
 }
 
-/* TODO: when we have notification in the objdb. */
+static void confdb_notify_lib_of_key_change(object_change_type_t change_type,
+                                                                               
          unsigned int parent_object_handle,
+                                                                               
          unsigned int object_handle,
+                                                                               
          void *object_name_pt, int object_name_len,
+                                                                               
          void *key_name_pt, int key_name_len,
+                                                                               
          void *key_value_pt, int key_value_len,
+                                                                               
          void *priv_data_pt)
+{
+       struct res_lib_confdb_key_change_callback res;
+
+       res.header.size = sizeof(res);
+       res.header.id = MESSAGE_RES_CONFDB_KEY_CHANGE_CALLBACK;
+       res.header.error = SA_AIS_OK;
+// handle & type
+       res.change_type = change_type;
+       res.parent_object_handle = parent_object_handle;
+       res.object_handle = object_handle;
+//object
+       memcpy(res.object_name.value, object_name_pt, object_name_len);
+       res.object_name.length = object_name_len;
+//key name
+       memcpy(res.key_name.value, key_name_pt, key_name_len);
+       res.key_name.length = key_name_len;
+//key value
+       memcpy(res.key_value.value, key_value_pt, key_value_len);
+       res.key_value.length = key_value_len;
+
+       api->ipc_conn_send_response(priv_data_pt, &res, sizeof(res));
+}
+
+static void confdb_notify_lib_of_new_object(unsigned int parent_object_handle,
+                                                                               
   unsigned int object_handle,
+                                                                               
   uint8_t *name_pt, int name_len,
+                                                                               
   void *priv_data_pt)
+{
+       struct res_lib_confdb_object_create_callback res;
+
+       res.header.size = sizeof(res);
+       res.header.id = MESSAGE_RES_CONFDB_OBJECT_CREATE_CALLBACK;
+       res.header.error = SA_AIS_OK;
+       res.parent_object_handle = parent_object_handle;
+       res.object_handle = object_handle;
+       memcpy(res.name.value, name_pt, name_len);
+       res.name.length = name_len;
+
+       api->ipc_conn_send_response(priv_data_pt, &res, sizeof(res));
+}
+
+static void confdb_notify_lib_of_destroyed_object(unsigned int 
parent_object_handle,
+                                                                               
        uint8_t *name_pt, int name_len,
+                                                                               
        void *priv_data_pt)
+{
+       struct res_lib_confdb_object_destroy_callback res;
+
+       res.header.size = sizeof(res);
+       res.header.id = MESSAGE_RES_CONFDB_OBJECT_DESTROY_CALLBACK;
+       res.header.error = SA_AIS_OK;
+       res.parent_object_handle = parent_object_handle;
+       memcpy(res.name.value, name_pt, name_len);
+       res.name.length = name_len;
+
+       api->ipc_conn_send_response(priv_data_pt, &res, sizeof(res));
+}
+
+
 static void message_handler_req_lib_confdb_track_start (void *conn, void 
*message)
 {
+       struct req_lib_confdb_object_track_start *req = (struct 
req_lib_confdb_object_track_start *)message;
        mar_res_header_t res;
 
+       api->object_track_start(req->object_handle,     req->flags,
+                                                       
confdb_notify_lib_of_key_change,
+                                                       
confdb_notify_lib_of_new_object,
+                                                       
confdb_notify_lib_of_destroyed_object,
+                                                       
api->ipc_conn_partner_get (conn));
        res.size = sizeof(res);
        res.id = MESSAGE_RES_CONFDB_TRACK_START;
-       res.error = SA_AIS_ERR_NOT_SUPPORTED;
+       res.error = SA_AIS_OK;
        api->ipc_conn_send_response(conn, &res, sizeof(res));
 }
 
@@ -484,9 +573,14 @@ static void message_handler_req_lib_confdb_track_stop 
(void *conn, void *message
 {
        mar_res_header_t res;
 
+       api->object_track_stop(confdb_notify_lib_of_key_change,
+                                                  
confdb_notify_lib_of_new_object,
+                                                  
confdb_notify_lib_of_destroyed_object,
+                                                  api->ipc_conn_partner_get 
(conn));
+
        res.size = sizeof(res);
        res.id = MESSAGE_RES_CONFDB_TRACK_STOP;
-       res.error = SA_AIS_ERR_NOT_SUPPORTED;
+       res.error = SA_AIS_OK;
        api->ipc_conn_send_response(conn, &res, sizeof(res));
 }
 
diff --git a/corosync/test/testconfdb.c b/corosync/test/testconfdb.c
index 8ecbf46..90ab3c5 100644
--- a/corosync/test/testconfdb.c
+++ b/corosync/test/testconfdb.c
@@ -47,7 +47,9 @@
 
 /* Callbacks are not supported yet */
 confdb_callbacks_t callbacks = {
-       .confdb_change_notify_fn = NULL,
+       .confdb_key_change_notify_fn = NULL,
+       .confdb_object_create_change_notify_fn = NULL,
+       .confdb_object_delete_change_notify_fn = NULL
 };
 
 /* Recursively dump the object tree */
diff --git a/corosync/tools/corosync-objctl.c b/corosync/tools/corosync-objctl.c
index 84f356c..d59c2f6 100644
--- a/corosync/tools/corosync-objctl.c
+++ b/corosync/tools/corosync-objctl.c
@@ -54,6 +54,7 @@ typedef enum {
        ACTION_DELETE,
        ACTION_PRINT_ALL,
        ACTION_PRINT_DEFAULT,
+       ACTION_TRACK,
 } action_types_t;
 
 typedef enum {
@@ -62,8 +63,32 @@ typedef enum {
        FIND_KEY_ONLY
 } find_object_of_type_t;
 
+static void tail_key_changed(confdb_handle_t handle,
+                                                          confdb_change_type_t 
change_type,
+                                                          unsigned int 
parent_object_handle,
+                                                          unsigned int 
object_handle,
+                                                          void *object_name,
+                                                          int  object_name_len,
+                                                          void *key_name,
+                                                          int key_name_len,
+                                                          void *key_value,
+                                                          int key_value_len);
+
+static void tail_object_created(confdb_handle_t handle,
+                                                               unsigned int 
parent_object_handle,
+                                                               unsigned int 
object_handle,
+                                                               uint8_t 
*name_pt,
+                                                               int  name_len);
+
+static void tail_object_deleted(confdb_handle_t handle,
+                                                               unsigned int 
parent_object_handle,
+                                                               uint8_t 
*name_pt,
+                                                               int  name_len);
+
 confdb_callbacks_t callbacks = {
-       .confdb_change_notify_fn = NULL,
+       .confdb_key_change_notify_fn = tail_key_changed,
+       .confdb_object_create_change_notify_fn = tail_object_created,
+       .confdb_object_delete_change_notify_fn = tail_object_deleted,
 };
 
 static int action;
@@ -377,6 +402,113 @@ static void create_object(confdb_handle_t handle, char * 
name_pt)
        }
 }
 
+static void tail_key_changed(confdb_handle_t handle,
+                                                          confdb_change_type_t 
change_type,
+                                                          unsigned int 
parent_object_handle,
+                                                          unsigned int 
object_handle,
+                                                          void *object_name_pt,
+                                                          int  object_name_len,
+                                                          void *key_name_pt,
+                                                          int key_name_len,
+                                                          void *key_value_pt,
+                                                          int key_value_len)
+{
+       char * on = (char*)object_name_pt;
+       char * kn = (char*)key_name_pt;
+       char * kv = (char*)key_value_pt;
+
+       on[object_name_len] = '\0';
+       kv[key_value_len] = '\0';
+       kn[key_name_len] = '\0';
+       printf("key_changed> %s.%s=%s\n", on, kn, kv);
+}
+
+static void tail_object_created(confdb_handle_t handle,
+                                                               unsigned int 
parent_object_handle,
+                                                               unsigned int 
object_handle,
+                                                               uint8_t 
*name_pt,
+                                                               int  name_len)
+{
+       name_pt[name_len] = '\0';
+       printf("object_created> %s\n", name_pt);
+}
+
+static void tail_object_deleted(confdb_handle_t handle,
+                                                               unsigned int 
parent_object_handle,
+                                                               uint8_t 
*name_pt,
+                                                               int  name_len)
+{
+       name_pt[name_len] = '\0';
+
+       printf("object_deleted> %s\n", name_pt);
+}
+
+static void listen_for_object_changes(confdb_handle_t handle)
+{
+       int result;
+       fd_set read_fds;
+       int select_fd;
+       SaBoolT quit = SA_FALSE;
+
+       FD_ZERO (&read_fds);
+       confdb_fd_get(handle, &select_fd);
+       printf ("Type \"q\" to finish\n");
+       do {
+               FD_SET (select_fd, &read_fds);
+               FD_SET (STDIN_FILENO, &read_fds);
+               result = select (select_fd + 1, &read_fds, 0, 0, 0);
+               if (result == -1) {
+                       perror ("select\n");
+               }
+               if (FD_ISSET (STDIN_FILENO, &read_fds)) {
+                       char inbuf[3];
+
+                       fgets(inbuf, sizeof(inbuf), stdin);
+                       if (strncmp(inbuf, "q", 1) == 0)
+                               quit = SA_TRUE;
+               }
+               if (FD_ISSET (select_fd, &read_fds)) {
+                       if (confdb_dispatch (handle, CONFDB_DISPATCH_ALL) != 
CONFDB_OK)
+                               exit(1);
+               }
+       } while (result && quit == SA_FALSE);
+
+       confdb_stop_track_changes(handle);
+
+}
+
+static void track_object(confdb_handle_t handle, char * name_pt)
+{
+       confdb_error_t res;
+       uint32_t obj_handle;
+
+       res = find_object (handle, name_pt, FIND_OBJECT_ONLY, &obj_handle);
+
+       if (res != CONFDB_OK) {
+               fprintf (stderr, "Could not find object \"%s\". Error %d\n",
+                                name_pt, res);
+               return;
+       }
+
+       res = confdb_track_changes (handle, obj_handle, 
CONFDB_TRACK_DEPTH_RECURSIVE);
+       if (res != CONFDB_OK) {
+               fprintf (stderr, "Could not enable tracking on object \"%s\". 
Error %d\n",
+                                name_pt, res);
+               return;
+       }
+}
+
+static void stop_tracking(confdb_handle_t handle)
+{
+       confdb_error_t res;
+
+       res = confdb_stop_track_changes (handle);
+       if (res != CONFDB_OK) {
+               fprintf (stderr, "Could not stop tracking. Error %d\n", res);
+               return;
+       }
+}
+
 static void delete_object(confdb_handle_t handle, char * name_pt)
 {
        confdb_error_t res;
@@ -425,7 +557,7 @@ int main (int argc, char *argv[]) {
        action = ACTION_READ;
 
        for (;;){
-               c = getopt (argc,argv,"hawcdp:");
+               c = getopt (argc,argv,"hawcdtp:");
                if (c==-1) {
                        break;
                }
@@ -450,6 +582,9 @@ int main (int argc, char *argv[]) {
                        case 'w':
                                action = ACTION_WRITE;
                                break;
+                       case 't':
+                               action = ACTION_TRACK;
+                               break;
                        default :
                                action = ACTION_READ;
                                break;
@@ -485,9 +620,17 @@ int main (int argc, char *argv[]) {
                        case ACTION_DELETE:
                                delete_object(handle, argv[optind++]);
                                break;
+                       case ACTION_TRACK:
+                               track_object(handle, argv[optind++]);
+                               break;
                }
        }
 
+       if (action == ACTION_TRACK) {
+               listen_for_object_changes(handle);
+               stop_tracking(handle);
+       }
+
        result = confdb_finalize (handle);
        if (result != CONFDB_OK) {
                fprintf (stderr, "Error finalizing objdb API. Error %d\n", 
result);
-- 
1.5.6

_______________________________________________
Openais mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/openais

Reply via email to