"Fossies" - the Fresh Open Source Software archive

Member "evms-2.5.5/plugins/csm/options.c" of archive evms-2.5.5.tar.gz:


/*
 *
 *   (C) Copyright IBM Corp. 2001, 2003
 *
 *   This program is free software;  you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program;  if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 *   Module: libcsm.so
 *
 *   File: segoptions.c
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <plugin.h>

#include "csm_plugin.h"


static int allocate_assign_option_descriptors( task_context_t * context )
{
        int                 i, rc = 0;
        const char         *my_nodeid_name=NULL;
        const node_list_t  *node_name_list=NULL;

        LOG_ENTRY();

        REQUIRE(context != NULL);

        context->option_descriptors->count = CSM_ASSIGN_OPTION_COUNT;

        // My Node Id
	rc = EngFncs->nodeid_to_string(&csm_nodeid, &my_nodeid_name);
        if (rc) {
                LOG_EXIT_INT(rc);
                return rc;
        }

        // List of Node Ids
        rc = EngFncs->get_node_list( 0, &node_name_list);
        if (rc) {
                rc = ENOMEM;
                LOG_EXIT_INT(rc);
                return rc;
        }
        else if (node_name_list->count == 0) {
                rc = ENOMEM;
                LOG_EXIT_INT(rc);
                return rc;
        }


        LOG_DEBUG("Node Name List ...\n");
        LOG_DEBUG("     count = %d\n", node_name_list->count);
        LOG_DEBUG("     ... Start\n");
        for ( i=0; i<node_name_list->count; i++ ) {
                LOG_DEBUG(" name = %s\n", node_name_list->node_info[i].node_name);
        }
        LOG_DEBUG("     ... Done\n");

        context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].flags = EVMS_OPTION_FLAGS_INACTIVE;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].constraint.list =
        EngFncs->engine_alloc( sizeof(value_list_t) + (sizeof(value_t) * node_name_list->count) );

        if (context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].constraint.list) {

                for ( i=0; i<node_name_list->count; i++ ) {
                        context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].constraint.list->value[i].s =
				EngFncs->engine_strdup( node_name_list->node_info[i].node_name );
                }

                context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].constraint.list->count = node_name_list->count;
        }
        else {
                rc = ENOMEM;
                LOG_EXIT_INT(rc);
                return rc;
        }

        context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].constraint_type = EVMS_Collection_List;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].help = NULL;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].name =
		EngFncs->engine_strdup( CSM_ASSIGN_OPTION_NODE_ID_STRING );
        context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].min_len = 1;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].max_len = NODEID_STRING_SIZE;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].tip =
		EngFncs->engine_strdup( _("Clustering requires that you specify a node that will owner this storage object.") );
        context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].title = EngFncs->engine_strdup( _("Node") );
        context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].type = EVMS_Type_String;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].unit = EVMS_Unit_None;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].value.s = EngFncs->engine_alloc(NODEID_STRING_SIZE+1);
        if (context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].value.s) {
                rc = 0;
        }
        else {
                rc = ENOMEM;
                LOG_EXIT_INT(rc);
                return rc;
        }


        // Storage Type Option
        context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].flags = EVMS_OPTION_FLAGS_INACTIVE;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].constraint.list =
        EngFncs->engine_alloc( sizeof(value_list_t) + (sizeof(value_t) * 3) );

        if (context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].constraint.list) {

                context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].constraint.list->value[0].s =
			EngFncs->engine_strdup( _("private") );
                context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].constraint.list->value[1].s =
			EngFncs->engine_strdup( _("shared") );
                context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].constraint.list->value[2].s =
			EngFncs->engine_strdup( _("deported") );
                context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].constraint.list->count = 3;
        }
        else {
                rc = ENOMEM;
                LOG_EXIT_INT(rc);
                return rc;
        }

        context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].constraint_type = EVMS_Collection_List;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].help = NULL;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].name =
		EngFncs->engine_strdup( CSM_ASSIGN_OPTION_TYPE_STRING );
        context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].min_len = 1;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].max_len = EVMS_NAME_SIZE+1;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].tip =
		EngFncs->engine_strdup( _("Clustering requires that you specify that the storage will be either shared by all or else private to a node.") );
        context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].title = EngFncs->engine_strdup( _("Type") );
        context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].type = EVMS_Type_String;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].unit = EVMS_Unit_None;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].value.s = EngFncs->engine_alloc(EVMS_NAME_SIZE+1);
        if (context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].value.s) {
                rc = 0;
        }
        else {
                rc = ENOMEM;
                LOG_EXIT_INT(rc);
                return rc;
        }

        // Container Name
        context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].flags = EVMS_OPTION_FLAGS_INACTIVE ;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].constraint.list = NULL;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].constraint_type = EVMS_Collection_None;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].help = NULL;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].name =
		EngFncs->engine_strdup( CSM_ASSIGN_OPTION_CONTAINER_NAME_STRING );
        context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].min_len = 1;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].max_len = EVMS_NAME_SIZE;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].tip =
		EngFncs->engine_strdup( _("Clustering requires that you choose a container in which to place cluster segments.") );
        context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].title = EngFncs->engine_strdup( _("Name") );
        context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].type = EVMS_Type_String;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].unit = EVMS_Unit_None;
        context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].value.s = EngFncs->engine_alloc(EVMS_NAME_SIZE+1);
        if (context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].value.s) {
                rc = 0;
        }
        else {
                rc = ENOMEM;
                LOG_EXIT_INT(rc);
                return rc;
        }


        LOG_EXIT_INT(rc);
        return rc;
}


static int initialize_assign_option_descriptors( task_context_t * context)
{
        int rc;
        const char *node_string;

        LOG_ENTRY();

        REQUIRE(context != NULL);
        REQUIRE(context->option_descriptors->count == CSM_ASSIGN_OPTION_COUNT);

        // Node ID
	rc = EngFncs->nodeid_to_string(&csm_nodeid, &node_string);
        if (rc) {
                LOG_EXIT_INT(rc);
                return rc;
        }
	context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].flags = 0;
	strncpy (context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].value.s,
		 node_string,
		 NODEID_STRING_SIZE );

        // Storage Type
        context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].flags = 0;
        strncpy (context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].value.s,
                 _("private"),
                 EVMS_NAME_SIZE );

        // Cluster Container Name
        context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].flags = EVMS_OPTION_FLAGS_NO_INITIAL_VALUE ;
        strncpy (context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].value.s,
                 "",
                 EVMS_NAME_SIZE );

        rc = 0;
        LOG_EXIT_INT(rc);
        return rc;
}


static int allocate_container_setinfo_option_descriptors( task_context_t *context )
{
        int rc = 0;

        LOG_ENTRY();

        REQUIRE(context != NULL);

        context->option_descriptors->count = CONTAINER_SETINFO_COUNT;

        // Node ID
        context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].flags = EVMS_OPTION_FLAGS_INACTIVE ;
        context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].constraint.list = NULL;
        context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].constraint_type = EVMS_Collection_None;
        context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].help = NULL;
        context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].name =
		EngFncs->engine_strdup( CONTAINER_SETINFO_NODE_ID_STRING );
        context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].min_len = 1;
        context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].max_len = NODEID_STRING_SIZE;
        context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].tip =
		EngFncs->engine_strdup( _("You can change the owner of a container (disk group) by changing the node id.") );
        context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].title = EngFncs->engine_strdup( _("Node") );
        context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].type = EVMS_Type_String;
        context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].unit = EVMS_Unit_None;
        context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].value.s = EngFncs->engine_alloc(NODEID_STRING_SIZE+1);
        if (context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].value.s) {
                rc = 0;
        }
        else {
                rc = ENOMEM;
                LOG_EXIT_INT(rc);
                return rc;
        }

        // Storage Type
        context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].flags = EVMS_OPTION_FLAGS_INACTIVE ;
        context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].constraint.list = NULL;
        context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].constraint_type = EVMS_Collection_List;
        context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].help = NULL;
        context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].name =
		EngFncs->engine_strdup( CONTAINER_SETINFO_TYPE_STRING );
        context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].min_len = 1;
        context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].max_len = EVMS_NAME_SIZE;
        context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].tip =
		EngFncs->engine_strdup( _("You can change the storage type of the container (disk group) to private, shared or deported.") );
        context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].title = EngFncs->engine_strdup( _("Type") );
        context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].type = EVMS_Type_String;
        context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].unit = EVMS_Unit_None;
        context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].value.s = EngFncs->engine_alloc(EVMS_NAME_SIZE+1);
        if (context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].value.s) {
                rc = 0;
        }
        else {
                rc = ENOMEM;
                LOG_EXIT_INT(rc);
                return rc;
        }



        // Container Name
        context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].flags = EVMS_OPTION_FLAGS_INACTIVE ;
        context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].constraint.list = NULL;
        context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].constraint_type = EVMS_Collection_None;
        context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].help = NULL;
        context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].name =
		EngFncs->engine_strdup( CONTAINER_SETINFO_NAME_STRING );
        context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].min_len = 1;
        context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].max_len = EVMS_NAME_SIZE;
        context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].tip =
		EngFncs->engine_strdup( _("You can change the name of the container (disk group) in which to place cluster segments.") );
        context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].title = EngFncs->engine_strdup( _("Name") );
        context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].type = EVMS_Type_String;
        context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].unit = EVMS_Unit_None;
        context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].value.s = EngFncs->engine_alloc(EVMS_NAME_SIZE+1);
        if (context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].value.s) {
                rc = 0;
        }
        else {
                rc = ENOMEM;
                LOG_EXIT_INT(rc);
                return rc;
        }


        LOG_EXIT_INT(rc);
        return rc;
}


static int initialize_container_setinfo_option_descriptors( task_context_t * context )
{
        int rc;
        const char *node_string;
        storage_container_t  *container=NULL;
        container_private_data_t *c_pdata;
	value_list_t * constraint_list;
	const node_list_t * node_list;

        LOG_ENTRY();

        REQUIRE(context != NULL);
        REQUIRE(context->container != NULL);
        REQUIRE(context->option_descriptors->count == CONTAINER_SETINFO_COUNT);
        REQUIRE(isa_cluster_container(context->container)==TRUE);

        container = (storage_container_t *) context->container;
        c_pdata = (container_private_data_t *) container->private_data;

        // Node ID
	rc = EngFncs->get_node_list(ACTIVE_NODES_ONLY, &node_list);
	if (!rc) {
		constraint_list = EngFncs->engine_alloc(sizeof(value_list_t) * node_list->count * sizeof(value_t));

		if (constraint_list != NULL) {
			int i;

			constraint_list->count = node_list->count;

			for (i = 0; i < node_list->count; i++) {
				constraint_list->value[i].s = EngFncs->engine_strdup(node_list->node_info[i].node_name);
			}

			context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].constraint.list = constraint_list;
			context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].constraint_type = EVMS_Collection_List;
		}

	}

	rc = EngFncs->nodeid_to_string(&c_pdata->nodeid, &node_string);
        if (rc) {
                LOG_EXIT_INT(rc);
                return rc;
        }
	context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].flags = EVMS_OPTION_FLAGS_NOT_REQUIRED;
	strncpy (context->option_descriptors->option[CONTAINER_SETINFO_NODE_ID_INDEX].value.s,
		 node_string,
		 sizeof(ece_nodeid_t) );

        // Type
	constraint_list = EngFncs->engine_alloc(sizeof(value_list_t) + 3 * sizeof(value_t));
	if (constraint_list != NULL) {

		constraint_list->count = 3;

		constraint_list->value[0].s = EngFncs->engine_strdup(_("private"));
		constraint_list->value[1].s = EngFncs->engine_strdup(_("shared"));
		constraint_list->value[2].s = EngFncs->engine_strdup(_("deported"));

		context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].constraint.list = constraint_list;
	}

        context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].flags = EVMS_OPTION_FLAGS_NOT_REQUIRED;
        if (container->flags & SCFLAG_CLUSTER_PRIVATE) {
                strncpy ( context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].value.s,
                          _("private"),
                          EVMS_NAME_SIZE );
        }
        else if (container->flags & SCFLAG_CLUSTER_SHARED) {
                strncpy ( context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].value.s,
                          _("shared"),
                          EVMS_NAME_SIZE );
        }
        else if (container->flags & SCFLAG_CLUSTER_DEPORTED) {
                strncpy ( context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].value.s,
                          _("deported"),
                          EVMS_NAME_SIZE );
        }
        else {
                strncpy ( context->option_descriptors->option[CONTAINER_SETINFO_TYPE_INDEX].value.s,
                          _("private"),
                          EVMS_NAME_SIZE );
        }

        // Cluster Container Name
        context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].flags = EVMS_OPTION_FLAGS_NOT_REQUIRED;
        strncpy (context->option_descriptors->option[CONTAINER_SETINFO_NAME_INDEX].value.s,
                 container->name,
                 EVMS_NAME_SIZE );

        rc = 0;
        LOG_EXIT_INT(rc);
        return rc;
}


static int set_assign_object( task_context_t * context,
                              list_anchor_t          declined_objects,
                              task_effect_t  * effect )
{
        int                 rc=EINVAL;
        storage_object_t   *obj;
        int                 found_good_object = FALSE;
        declined_object_t  *declined_object=NULL;
        list_element_t      iter, e;

        LOG_ENTRY();

        REQUIRE(context != NULL);
        REQUIRE(context->selected_objects != NULL);
        REQUIRE(EngFncs->list_count(context->selected_objects) != 0);


        LIST_FOR_EACH( context->selected_objects, iter, obj ) {

                if ( ( found_good_object == FALSE) &&
                     ( obj->object_type  == DISK || obj->object_type == SEGMENT ) &&
                     ( obj->volume       == NULL ) &&
                     ( EngFncs->list_count(obj->parent_objects) == 0 ) ) {

                        found_good_object = TRUE;

                        rc = initialize_assign_option_descriptors(context);

                        if (rc == 0) {
                                *effect |=  EVMS_Effect_Reload_Options;
                        }

                }
                else {

                        declined_object = EngFncs->engine_alloc( sizeof(declined_object_t));

                        if (declined_object) {

                                declined_object->object = obj;
                                declined_object->reason = rc; // REMINDER ... need to pickup reason codes the UI understands

                                e=EngFncs->insert_thing( declined_objects,
                                                         declined_object,
                                                         INSERT_AFTER,
                                                         NULL );
                                if (e!=NULL) {
                                        rc=0;
                                        *effect |=  EVMS_Effect_Reload_Objects;
                                }
                                else {
                                        rc = ENOMEM;
                                        EngFncs->engine_free(declined_object);
                                }

                        }
                        else {
                                LOG_ERROR("error, unable to malloc a declined object struct\n");
                                rc = ENOMEM;
                        }

                }

        }


        LOG_EXIT_INT(rc);
        return rc;
}


static int set_container_assign_object( task_context_t * context,
                                        list_anchor_t          declined_objects,
                                        task_effect_t  * effect )
{
        int                 rc=0;
        storage_object_t   *obj;
        declined_object_t  *declined_object=NULL;
        boolean             init_done=FALSE;
        list_element_t      iter, e;

        LOG_ENTRY();

        REQUIRE(context != NULL);
        REQUIRE(context->selected_objects != NULL);
        REQUIRE(EngFncs->list_count(context->selected_objects) != 0);

        LIST_FOR_EACH( context->selected_objects, iter, obj ) {

                if ( ( obj->object_type  == DISK || obj->object_type == SEGMENT ) &&
                     ( EngFncs->list_count(obj->parent_objects)==0) &&
                     ( obj->volume       == NULL ) ) {

                        if (init_done == FALSE) {

                                init_done = TRUE;

                                rc = initialize_assign_option_descriptors(context);

                                if (!rc) {
                                        *effect |=  EVMS_Effect_Reload_Options;
                                }

                        }

                }
                else {
                        declined_object = EngFncs->engine_alloc( sizeof(declined_object_t));

                        if (declined_object) {

                                declined_object->object = obj;
                                declined_object->reason = rc;

                                e = EngFncs->insert_thing( declined_objects,
                                                           declined_object,
                                                           INSERT_AFTER,
                                                           NULL );
                                if (e!=NULL) {
                                        rc=0;
                                        *effect |=  EVMS_Effect_Reload_Objects;
                                }
                                else {
                                        rc = ENOMEM;
                                        EngFncs->engine_free(declined_object);
                                }

                        }
                        else {
                                LOG_ERROR("error, unable to malloc a declined object struct\n");
                                rc = ENOMEM;
                        }
                }


        }


        LOG_EXIT_INT(rc);
        return rc;
}



void prune_acceptable_disks( list_anchor_t list )
{
        storage_object_t   *obj;
        seg_private_data_t *pdata=NULL;
        list_element_t  iter,iter2;
        boolean prune;

        LIST_FOR_EACH_SAFE( list, iter, iter2, obj ) {

                prune = TRUE;

                if ( obj->plugin != csm_plugin_record_ptr ) {

                        if (obj->object_type == DISK) {
                                prune = FALSE;
                        }
                        else if (obj->object_type == SEGMENT) {

                                pdata = (seg_private_data_t *)obj->private_data;

                                if ( !(pdata->cflags & SEG_CFLAG_TOP_SEGMENT) ) {
                                        // only accept segments from 390 dasd driver
                                        if ( strncmp(obj->name, "dasd", 4) == 0 ) {
                                                prune = FALSE;
                                        }
                                }

                        }

                }

                if (prune) EngFncs->delete_element(iter);
        }

}


static int get_acceptable_assign_objects( task_context_t * context )
{
        int rc;
	list_anchor_t temp_list = context->acceptable_objects;

        LOG_ENTRY();

        REQUIRE(context != NULL);
        REQUIRE(EngFncs->list_count(context->acceptable_objects) == 0);

        rc = EngFncs->get_object_list( DISK, //| SEGMENT,
                                       DATA_TYPE,
                                       NULL,
                                       NULL,
                                       TOPMOST,
                                       &context->acceptable_objects );

        if (rc == 0) {
		// Destroy the original acceptable objects list anchor.
		EngFncs->destroy_list(temp_list);

                if ( EngFncs->list_count(context->acceptable_objects) > 0) {
                         prune_acceptable_disks(context->acceptable_objects);
                }
                else {
                        LOG_DEBUG("no storage objects returned by get_object_list call\n");
                }

                rc = 0;

        }

        LOG_EXIT_INT(rc);
        return rc;
}


int csm_init_task(task_context_t * context)
{
        int rc = EINVAL;
	list_element_t iter;
	storage_object_t * ld;

        LOG_ENTRY();

        REQUIRE(context != NULL);
        REQUIRE(csm_has_quorum == TRUE || csm_admin_mode == TRUE);

        if (context) {

                switch (context->action) {

                case EVMS_Task_Assign_Plugin:

                        context->min_selected_objects = 1;
                        context->max_selected_objects = 1;

                        rc = allocate_assign_option_descriptors( context );
                        if (rc == 0) {
                                rc = get_acceptable_assign_objects( context );
                        }

                        break;

                case EVMS_Task_Create_Container:

                        context->min_selected_objects = 1;
                        context->max_selected_objects = 1024;

                        rc = allocate_assign_option_descriptors( context );
                        if (rc == 0) {
                                rc = get_acceptable_assign_objects( context );
                        }

                        break;

                case EVMS_Task_Set_Container_Info:

                        context->min_selected_objects = 0;
                        context->max_selected_objects = 0;

                        rc = allocate_container_setinfo_option_descriptors( context );
                        if (rc == 0) {
                                rc = initialize_container_setinfo_option_descriptors( context );
                        }

                        break;

		case EVMS_Task_Expand:
			if (!context->container) {
				rc = ENOSYS;
				break;
			}

			// anthing acceptable for assign is also acceptable for expand.
			rc = get_acceptable_assign_objects( context );

                        context->min_selected_objects = 1;
                        context->max_selected_objects = EngFncs->list_count(context->acceptable_objects);
			break;

		case EVMS_Task_Shrink:
			if (!context->container) {
				rc = ENOSYS;
				break;
			}

			LIST_FOR_EACH(context->container->objects_consumed, iter, ld) {
				if (csm_can_unassign(ld) == 0) {
					EngFncs->insert_thing(context->acceptable_objects,
							      ld,
							      INSERT_AFTER,
							      NULL);
				}
			}
                        context->min_selected_objects = 1;
                        context->max_selected_objects = EngFncs->list_count(context->acceptable_objects);

			rc = 0;
			break;

                default:
                        rc = ENOSYS;
                        LOG_ERROR("unsupported task ... context->action = %d\n", context->action);
                        break;
                }
        }

        LOG_EXIT_INT(rc);
        return rc;
}


int csm_set_objects( task_context_t * context,
                     list_anchor_t          declined_objects,
                     task_effect_t  * effect )
{
        int rc = EINVAL;

        LOG_ENTRY();

        if (context) {

                switch (context->action) {

                case  EVMS_Task_Assign_Plugin:

                        rc = set_assign_object( context, declined_objects, effect );
                        break;

                case EVMS_Task_Create_Container:

                        rc = set_container_assign_object(context,declined_objects,effect );
                        break;

		case EVMS_Task_Expand:

			if (context->container) {
				rc = 0;
			} else {
				rc = ENOSYS;
			}
			break;

		case EVMS_Task_Shrink:

			if (context->container) {
				rc = 0;
			} else {
				rc = ENOSYS;
			}
			break;

                default:

                        rc = ENOSYS;
                        LOG_ERROR("context->action is unknown or unsupported\n");
                        break;

                }
        }

        LOG_EXIT_INT(rc);
        return rc;
}


static int csm_set_assign_option( task_context_t * context,
                                  u_int32_t        index,
                                  value_t        * value,
                                  task_effect_t  * effect )
{
        int rc=EINVAL, i;
        storage_container_t *container=NULL;
        container_private_data_t *c_pdata;
        const char *node_string;

        LOG_ENTRY();

        REQUIRE(index >= 0 && index < CSM_ASSIGN_OPTION_COUNT);

        switch (index) {

        case CSM_ASSIGN_OPTION_NODE_ID_INDEX:
                if ( strlen(value->s) > 0 ) {

                        strncpy( context->option_descriptors->option[index].value.s,
                                 value->s,
                                 NODEID_STRING_SIZE );

                        context->option_descriptors->option[index].flags = 0;

                        rc = 0;

                }
                else {
                        rc = EINVAL;
                }
                break;

        case CSM_ASSIGN_OPTION_TYPE_INDEX:
                if ( strlen(value->s) > 0 ) {
                        strncpy( context->option_descriptors->option[index].value.s,
                                 value->s,
                                 EVMS_NAME_SIZE );

                        context->option_descriptors->option[index].flags = 0;

                        rc = 0;
                }
                else {
                        rc = EINVAL;
                }
                break;

        case CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX:
                if ( strlen(value->s) > 0 ) {

                        for (i=0,rc=0; rc==0 && i<strlen(value->s); i++) {
                                if ( value->s[i] == '/' ) {
                                        rc = EINVAL;
                                }
                        }

                        if (!rc) {
                                strncpy( context->option_descriptors->option[index].value.s,
                                         value->s,
                                         EVMS_NAME_SIZE );

                                context->option_descriptors->option[index].flags = 0;
                        }

                }
                else {
                        rc = EINVAL;
                }
                break;

        default:
                rc = EINVAL;
                break;
        }


        if (!rc) {
                if (strlen(context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].value.s)>0) {
                        rc = csm_find_container( context->option_descriptors->option[CSM_ASSIGN_OPTION_CONTAINER_NAME_INDEX].value.s,
                                                 &container );
                        if (!rc) {
                                c_pdata = (container_private_data_t *) container->private_data;
				rc = EngFncs->nodeid_to_string(&c_pdata->nodeid, &node_string);
                                if (!rc) {

                                        strncpy( context->option_descriptors->option[CSM_ASSIGN_OPTION_NODE_ID_INDEX].value.s,
                                                 node_string,
                                                 NODEID_STRING_SIZE );
                                }
                                if (container->flags & SCFLAG_CLUSTER_PRIVATE) {
                                        strcpy( context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].value.s,
                                                _("private") );
                                }
                                else if (container->flags & SCFLAG_CLUSTER_SHARED) {
                                        strcpy( context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].value.s,
                                                _("shared") );
                                }
                                else if (container->flags & SCFLAG_CLUSTER_DEPORTED) {
                                        strcpy( context->option_descriptors->option[CSM_ASSIGN_OPTION_TYPE_INDEX].value.s,
                                                _("deported") );
                                }
                        }
                        rc = 0;
                }
        }

        LOG_EXIT_INT(rc);
        return rc;
}


static int csm_set_container_option( task_context_t * context,
                                     u_int32_t        index,
                                     value_t        * value,
                                     task_effect_t  * effect )
{
        int rc=EINVAL, i;
        const node_list_t *node_name_list=NULL;
        int flag;
        char name[EVMS_NAME_SIZE+1];

        LOG_ENTRY();

        REQUIRE(index >= 0 && index < CONTAINER_SETINFO_COUNT);

        switch (index) {

        case CONTAINER_SETINFO_NODE_ID_INDEX:

                if ( strlen(value->s) > 0 ) {

                        // get list of node ids
                        rc = EngFncs->get_node_list( 0, &node_name_list);
                        if (rc) {
                                LOG_ERROR("unable to get cluster node list to validate options\n");
                                rc = ENOMEM;
                                LOG_EXIT_INT(rc);
                                return rc;
                        }

                        // must be configured nodeid
                        for ( i=0,flag=-1; flag!=0 && i<node_name_list->count; i++ ) {
                                flag = strncmp( node_name_list->node_info[i].node_name,
                                                value->s,
                                                NODEID_STRING_SIZE );
                        }

                        if (!flag) {

                                strncpy( context->option_descriptors->option[index].value.s,
                                         value->s,
                                         NODEID_STRING_SIZE );

                                context->option_descriptors->option[index].flags = 0;

                                rc = 0;

                        }
                        else {
                                rc = EINVAL;
                        }
                }
                else {
                        rc = EINVAL;
                }
                break;


        case CONTAINER_SETINFO_TYPE_INDEX:

                rc = EINVAL;
                if ( strlen(value->s) > 0 ) {

                        strncpy(name,value->s,EVMS_NAME_SIZE);
                        string_to_upper_case(name);

                        if (strcasecmp(name,_("private"))==0) {
                                strcpy(name, _("private"));
                                rc = 0;
                        }
                        else if (strcasecmp(name,_("shared"))==0) {
                                strcpy(name,_("shared"));
                                rc = 0;
                        }
                        else if (strcasecmp(name,_("deported"))==0) {
                                strcpy(name,_("deported"));
                                rc = 0;
                        }

                        if (!rc) {
                                strncpy( context->option_descriptors->option[index].value.s,
                                         name,
                                         EVMS_NAME_SIZE );

                                context->option_descriptors->option[index].flags = 0;
                        }
                }
                break;


        case CONTAINER_SETINFO_NAME_INDEX:

                if ( strlen(value->s) > 0 ) {

                        for (i=0,rc=0; rc==0 && i<strlen(value->s); i++) {
                                if ( value->s[i] == '/' ) {
                                        rc = EINVAL;
                                }
                        }

                        if (!rc) {
                                rc = EngFncs->validate_name(value->s);
                                if (!rc) {
                                        strncpy( context->option_descriptors->option[index].value.s,
                                                 value->s,
                                                 EVMS_NAME_SIZE );

                                        context->option_descriptors->option[index].flags = 0;
                                }
                                else {
                                        LOG_DEBUG("container name is already in use.\n");
                                        rc = EINVAL;
                                }
                        }

                }
                else {
                        rc = EINVAL;
                }
                break;

        default:
                rc = EINVAL;
                break;
        }

        LOG_EXIT_INT(rc);
        return rc;
}


int csm_get_option_count(task_context_t * task)
{
        int count=0;

        LOG_ENTRY();

        REQUIRE(task != NULL);

        switch (task->action) {

        case EVMS_Task_Assign_Plugin:
        case EVMS_Task_Create_Container:
                count = CSM_ASSIGN_OPTION_COUNT;
                break;

        case EVMS_Task_Expand:
                count = CSM_EXPAND_CONTAINER_OPTION_COUNT;
                break;

        case EVMS_Task_Shrink:
                count = CSM_SHRINK_CONTAINER_OPTION_COUNT;
                break;

        case EVMS_Task_Set_Container_Info:
                count = CONTAINER_SETINFO_COUNT;
                break;

        default:
                LOG_DEBUG("unsupported task ... task->action = %d\n", task->action);
                count = 0;
                break;
        }

        LOG_EXIT_INT(count);
        return count;
}


int csm_set_option( task_context_t * context,
                    u_int32_t        index,
                    value_t        * value,
                    task_effect_t  * effect )
{
        int rc;

        LOG_ENTRY();

        REQUIRE(context != NULL);
        REQUIRE(value != NULL);
        REQUIRE(effect != NULL);

        switch (context->action) {

        case EVMS_Task_Assign_Plugin:
        case EVMS_Task_Create_Container:

                rc = csm_set_assign_option(context,index,value,effect);
                break;

        case EVMS_Task_Set_Container_Info:
                rc = csm_set_container_option(context,index,value,effect);
                break;

	case EVMS_Task_Expand:
	case EVMS_Task_Shrink:
		if (context->container) {
			rc = 0;
		} else {
			rc = ENOSYS;
		}
		break;

        default:
                rc = ENOSYS;
                LOG_ERROR("error, unknown task ... context->action = %d\n", context->action);
                break;
        }

        LOG_EXIT_INT(rc);
        return rc;
}



/*
 * Returns segment specific information
 */
int csm_get_segment_info( storage_object_t  * object, extended_info_array_t * * info)
{
        int rc = EINVAL;
        extended_info_array_t   *Info;


        LOG_ENTRY();

        rc    = ENOMEM;  // init to failed calloc
        *info = NULL;     // init to no info returned

        Info = EngFncs->engine_alloc( sizeof(extended_info_array_t) + ( SEG_INFO_COUNT * sizeof(extended_info_t) ) );
        if (Info) {

                Info->count = SEG_INFO_COUNT;

                Info->info[SEG_INFO_NAME_INDEX].name = EngFncs->engine_strdup( "Name" );
                Info->info[SEG_INFO_NAME_INDEX].title = EngFncs->engine_strdup( _("Name") );
                Info->info[SEG_INFO_NAME_INDEX].desc = EngFncs->engine_strdup( _("This is the partition name. It must be unique on the system.") );
                Info->info[SEG_INFO_NAME_INDEX].type               = EVMS_Type_String;
                Info->info[SEG_INFO_NAME_INDEX].unit               = EVMS_Unit_None;
                Info->info[SEG_INFO_NAME_INDEX].value.s = EngFncs->engine_strdup( object->name );
                Info->info[SEG_INFO_NAME_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[SEG_INFO_NAME_INDEX].group, 0, sizeof(group_info_t));

                Info->info[SEG_INFO_SIZE_INDEX].name = EngFncs->engine_strdup( "Size" );
                Info->info[SEG_INFO_SIZE_INDEX].title = EngFncs->engine_strdup( _("Size") );
                Info->info[SEG_INFO_SIZE_INDEX].desc = EngFncs->engine_strdup( _("This is the size of the partition in sectors.") );
                Info->info[SEG_INFO_SIZE_INDEX].type               = EVMS_Type_Unsigned_Int64;
                Info->info[SEG_INFO_SIZE_INDEX].unit               = EVMS_Unit_Sectors;
                Info->info[SEG_INFO_SIZE_INDEX].value.ui64         = object->size;
                Info->info[SEG_INFO_SIZE_INDEX].format             = EVMS_Format_Normal;
                Info->info[SEG_INFO_SIZE_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[SEG_INFO_SIZE_INDEX].group, 0, sizeof(group_info_t));
                Info->info[SEG_INFO_SIZE_INDEX].flags |= EVMS_EINFO_FLAGS_NO_UNIT_CONVERSION;

                Info->info[SEG_INFO_START_INDEX].name = EngFncs->engine_strdup( "Start" );
                Info->info[SEG_INFO_START_INDEX].title = EngFncs->engine_strdup( _("Start Logical Blcok Address") );
                Info->info[SEG_INFO_START_INDEX].desc = EngFncs->engine_strdup( _("This is the sector offset of the partition on the disk, i.e., the logical block address of the first sector of the partition.") );
                Info->info[SEG_INFO_START_INDEX].type               = EVMS_Type_Unsigned_Int64;
                Info->info[SEG_INFO_START_INDEX].unit               = EVMS_Unit_None;
                Info->info[SEG_INFO_START_INDEX].value.ui64         = object->start;
                Info->info[SEG_INFO_START_INDEX].format             = EVMS_Format_Normal;
                Info->info[SEG_INFO_START_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[SEG_INFO_START_INDEX].group, 0, sizeof(group_info_t));


                Info->info[SEG_INFO_TYPE_INDEX].name = EngFncs->engine_strdup( "Type" );
                Info->info[SEG_INFO_TYPE_INDEX].title = EngFncs->engine_strdup( _("Type") );
                Info->info[SEG_INFO_TYPE_INDEX].desc = EngFncs->engine_strdup( _("Partition type - data, metadata, free.") );
                Info->info[SEG_INFO_TYPE_INDEX].type               = EVMS_Type_String;
                Info->info[SEG_INFO_TYPE_INDEX].unit               = EVMS_Unit_None;
                Info->info[SEG_INFO_TYPE_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[SEG_INFO_TYPE_INDEX].group, 0, sizeof(group_info_t));

                if ( object->data_type == DATA_TYPE ) {
                        Info->info[SEG_INFO_TYPE_INDEX].value.s = EngFncs->engine_strdup( _("data") );
                }
                else if ( object->data_type == META_DATA_TYPE ) {
                        Info->info[SEG_INFO_TYPE_INDEX].value.s = EngFncs->engine_strdup( _("metadata") );
                        Info->info[SEG_INFO_TYPE_INDEX].flags           = EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE;
                }
                else {
                        Info->info[SEG_INFO_TYPE_INDEX].value.s = EngFncs->engine_strdup( _("unknown") );
                }

                *info = Info;

                rc = 0;
        }
        else {
                LOG_ERROR("unable to malloc memory for extended info array\n");
        }


        LOG_EXIT_INT(rc);
        return rc;
}



/*
 * Returns Cluster Metadata specific information
 */
int csm_get_metadata_info(storage_object_t * object, extended_info_array_t **info)
{
        int rc = EINVAL;
        extended_info_array_t   *Info;
        csm_header_t            *hdr = ((seg_private_data_t *)object->private_data)->hdr;
        char                    *guid_string=NULL;
        const char              *node_string=NULL;


        LOG_ENTRY();

        rc    = ENOMEM;  // init to failed calloc
        *info = NULL;     // init to no info returned

        Info = EngFncs->engine_alloc( sizeof(extended_info_array_t) + ( HEADER_INFO_COUNT * sizeof(extended_info_t) ) );
        if (Info) {

                Info->count = HEADER_INFO_COUNT;

                Info->info[HEADER_INFO_HDRSIZE_INDEX].name = EngFncs->engine_strdup( "Size" );
                Info->info[HEADER_INFO_HDRSIZE_INDEX].title = EngFncs->engine_strdup( _("Header Size") );
                Info->info[HEADER_INFO_HDRSIZE_INDEX].desc = EngFncs->engine_strdup( _("This is the size of header in bytes.") );
                Info->info[HEADER_INFO_HDRSIZE_INDEX].type               = EVMS_Type_Unsigned_Int32;
                Info->info[HEADER_INFO_HDRSIZE_INDEX].unit               = EVMS_Unit_Bytes;
                Info->info[HEADER_INFO_HDRSIZE_INDEX].value.ui32         = hdr->size;
                Info->info[HEADER_INFO_HDRSIZE_INDEX].format             = EVMS_Format_Normal;
                Info->info[HEADER_INFO_HDRSIZE_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[HEADER_INFO_HDRSIZE_INDEX].group, 0, sizeof(group_info_t));

                Info->info[HEADER_INFO_ALTLBA_INDEX].name = EngFncs->engine_strdup( "Alternate LBA" );
                Info->info[HEADER_INFO_ALTLBA_INDEX].title = EngFncs->engine_strdup( _("Alternate Logical Block Address") );
                Info->info[HEADER_INFO_ALTLBA_INDEX].desc = EngFncs->engine_strdup( _("Logical Block Address of the alternate header.") );
                Info->info[HEADER_INFO_ALTLBA_INDEX].type               = EVMS_Type_Unsigned_Int64;
                Info->info[HEADER_INFO_ALTLBA_INDEX].unit               = EVMS_Unit_None;
                Info->info[HEADER_INFO_ALTLBA_INDEX].value.ui64         = hdr->alternate_lba;
                Info->info[HEADER_INFO_ALTLBA_INDEX].format             = EVMS_Format_Normal;
                Info->info[HEADER_INFO_ALTLBA_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[HEADER_INFO_ALTLBA_INDEX].group, 0, sizeof(group_info_t));

                Info->info[HEADER_INFO_START_INDEX].name = EngFncs->engine_strdup( "Useable Start" );
                Info->info[HEADER_INFO_START_INDEX].title = EngFncs->engine_strdup( _("Useable Start") );
                Info->info[HEADER_INFO_START_INDEX].desc = EngFncs->engine_strdup( _("Logical Block Address of the start of useable space on the disk.") );
                Info->info[HEADER_INFO_START_INDEX].type               = EVMS_Type_Unsigned_Int64;
                Info->info[HEADER_INFO_START_INDEX].unit               = EVMS_Unit_None;
                Info->info[HEADER_INFO_START_INDEX].value.ui64         = hdr->start_useable;
                Info->info[HEADER_INFO_START_INDEX].format             = EVMS_Format_Normal;
                Info->info[HEADER_INFO_START_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[HEADER_INFO_START_INDEX].group, 0, sizeof(group_info_t));

                Info->info[HEADER_INFO_END_INDEX].name = EngFncs->engine_strdup( "Useable End" );
                Info->info[HEADER_INFO_END_INDEX].title = EngFncs->engine_strdup( _("Useable End") );
                Info->info[HEADER_INFO_END_INDEX].desc = EngFncs->engine_strdup( _("Logical Block Address of the end of useable space on the disk.") );
                Info->info[HEADER_INFO_END_INDEX].type               = EVMS_Type_Unsigned_Int64;
                Info->info[HEADER_INFO_END_INDEX].unit               = EVMS_Unit_None;
                Info->info[HEADER_INFO_END_INDEX].value.ui64         = hdr->end_useable;
                Info->info[HEADER_INFO_END_INDEX].format             = EVMS_Format_Normal;
                Info->info[HEADER_INFO_END_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[HEADER_INFO_END_INDEX].group, 0, sizeof(group_info_t));


                guid_string = guid_to_string( &hdr->disk_id );

                if (guid_string) {

                        Info->info[HEADER_INFO_DISK_GUID_INDEX].name = EngFncs->engine_strdup( "Disk - GUID" );
                        Info->info[HEADER_INFO_DISK_GUID_INDEX].title = EngFncs->engine_strdup( _("Disk - GUID") );
                        Info->info[HEADER_INFO_DISK_GUID_INDEX].desc = EngFncs->engine_strdup( _("This is the disk globally unique identifier.") );
                        Info->info[HEADER_INFO_DISK_GUID_INDEX].type               = EVMS_Type_String;
                        Info->info[HEADER_INFO_DISK_GUID_INDEX].unit               = EVMS_Unit_None;
                        Info->info[HEADER_INFO_DISK_GUID_INDEX].value.s = EngFncs->engine_strdup( guid_string );
                        Info->info[HEADER_INFO_DISK_GUID_INDEX].collection_type    = EVMS_Collection_None;
                        memset( &Info->info[HEADER_INFO_DISK_GUID_INDEX].group, 0, sizeof(group_info_t));

                        free(guid_string);

                }
                else {
                        EngFncs->engine_free( Info );
                        rc = ENOMEM;
                        LOG_EXIT_INT(rc);
                        return rc;
                }

		EngFncs->nodeid_to_string(&hdr->nodeid, &node_string);
                if (node_string) {

                        Info->info[HEADER_INFO_NODE_CUID_INDEX].name = EngFncs->engine_strdup( "Node ID" );
                        Info->info[HEADER_INFO_NODE_CUID_INDEX].title = EngFncs->engine_strdup( _("Node ID") );
                        Info->info[HEADER_INFO_NODE_CUID_INDEX].desc = EngFncs->engine_strdup( _("This is the cluster node ID."));
                        Info->info[HEADER_INFO_NODE_CUID_INDEX].type               = EVMS_Type_String;
                        Info->info[HEADER_INFO_NODE_CUID_INDEX].unit               = EVMS_Unit_None;
                        Info->info[HEADER_INFO_NODE_CUID_INDEX].value.s = EngFncs->engine_strdup( node_string );
                        Info->info[HEADER_INFO_NODE_CUID_INDEX].collection_type    = EVMS_Collection_None;
                        memset( &Info->info[HEADER_INFO_NODE_CUID_INDEX].group, 0, sizeof(group_info_t));

                }
                else {
                        EngFncs->engine_free( Info );
                        rc = ENOMEM;
                        LOG_EXIT_INT(rc);
                        return rc;
                }

                *info = Info;

                rc = 0;

        }
        else {
                LOG_ERROR("unable to malloc memory for extended info array\n");
        }


        LOG_EXIT_INT(rc);
        return rc;
}


/*
 * Returns plugin specific information
 */
int csm_get_plugin_info( char * descriptor_name, extended_info_array_t * * info )
{
        int rc = EINVAL;
        extended_info_array_t   *Info;
        char                     version_string[64];
        char                     required_engine_api_version_string[64];
        char                     required_plugin_api_version_string[64];


        LOG_ENTRY();

        // a measure of protection ...
        if (info == NULL) {
                LOG_EXIT_INT(rc);
                return rc;
        }

        rc    = ENOMEM;  // init to failed calloc
        *info = NULL;     // init to no info returned

        Info = EngFncs->engine_alloc( sizeof(extended_info_array_t) + (PLUGIN_INFO_COUNT*sizeof(extended_info_t))  );
        if (Info) {

                Info->count = PLUGIN_INFO_COUNT;

                sprintf(version_string, "%d.%d.%d",
                        MAJOR_VERSION,
                        MINOR_VERSION,
                        PATCH_LEVEL );

                sprintf(required_engine_api_version_string, "%d.%d.%d",
                        csm_plugin_record_ptr->required_engine_api_version.major,
                        csm_plugin_record_ptr->required_engine_api_version.minor,
                        csm_plugin_record_ptr->required_engine_api_version.patchlevel );

                sprintf(required_plugin_api_version_string, "%d.%d.%d",
                        csm_plugin_record_ptr->required_plugin_api_version.plugin.major,
                        csm_plugin_record_ptr->required_plugin_api_version.plugin.minor,
                        csm_plugin_record_ptr->required_plugin_api_version.plugin.patchlevel );

                Info->info[PLUGIN_INFO_SNAME_INDEX].name = EngFncs->engine_strdup( "ShortName" );
                Info->info[PLUGIN_INFO_SNAME_INDEX].title = EngFncs->engine_strdup( _("Short Name") );
                Info->info[PLUGIN_INFO_SNAME_INDEX].desc = EngFncs->engine_strdup( _("A short name given to this plug-in") );
                Info->info[PLUGIN_INFO_SNAME_INDEX].type               = EVMS_Type_String;
                Info->info[PLUGIN_INFO_SNAME_INDEX].unit               = EVMS_Unit_None;
                Info->info[PLUGIN_INFO_SNAME_INDEX].value.s = EngFncs->engine_strdup( csm_plugin_record_ptr->short_name );
                Info->info[PLUGIN_INFO_SNAME_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[PLUGIN_INFO_SNAME_INDEX].group, 0, sizeof(group_info_t));

                Info->info[PLUGIN_INFO_LNAME_INDEX].name = EngFncs->engine_strdup( "LongName" );
                Info->info[PLUGIN_INFO_LNAME_INDEX].title = EngFncs->engine_strdup( _("Long Name") );
                Info->info[PLUGIN_INFO_LNAME_INDEX].desc = EngFncs->engine_strdup( _("A longer, more descriptive name for this plug-in") );
                Info->info[PLUGIN_INFO_LNAME_INDEX].type               = EVMS_Type_String;
                Info->info[PLUGIN_INFO_LNAME_INDEX].unit               = EVMS_Unit_None;
                Info->info[PLUGIN_INFO_LNAME_INDEX].value.s = EngFncs->engine_strdup( csm_plugin_record_ptr->long_name );
                Info->info[PLUGIN_INFO_LNAME_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[PLUGIN_INFO_LNAME_INDEX].group, 0, sizeof(group_info_t));

                Info->info[PLUGIN_INFO_TYPE_INDEX].name = EngFncs->engine_strdup( "Type" );
                Info->info[PLUGIN_INFO_TYPE_INDEX].title = EngFncs->engine_strdup( _("Plug-in Type") );
                Info->info[PLUGIN_INFO_TYPE_INDEX].desc = EngFncs->engine_strdup( _("There are various types of plug-ins, each responsible for some kind of storage object or logical volume.") );
                Info->info[PLUGIN_INFO_TYPE_INDEX].type               = EVMS_Type_String;
                Info->info[PLUGIN_INFO_TYPE_INDEX].unit               = EVMS_Unit_None;
                Info->info[PLUGIN_INFO_TYPE_INDEX].value.s = EngFncs->engine_strdup( _("Segment Manager") );
                Info->info[PLUGIN_INFO_TYPE_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[PLUGIN_INFO_TYPE_INDEX].group, 0, sizeof(group_info_t));

                Info->info[PLUGIN_INFO_VERSION_INDEX].name = EngFncs->engine_strdup( "Version" );
                Info->info[PLUGIN_INFO_VERSION_INDEX].title = EngFncs->engine_strdup( _("Plug-in Version") );
                Info->info[PLUGIN_INFO_VERSION_INDEX].desc = EngFncs->engine_strdup( _("This is the version number of the plugin.") );
                Info->info[PLUGIN_INFO_VERSION_INDEX].type               = EVMS_Type_String;
                Info->info[PLUGIN_INFO_VERSION_INDEX].unit               = EVMS_Unit_None;
                Info->info[PLUGIN_INFO_VERSION_INDEX].value.s = EngFncs->engine_strdup( version_string );
                Info->info[PLUGIN_INFO_VERSION_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[PLUGIN_INFO_VERSION_INDEX].group, 0, sizeof(group_info_t));

                Info->info[PLUGIN_INFO_REQENGSVCVERSION_INDEX].name = EngFncs->engine_strdup( "Required Engine Services Version" );
                Info->info[PLUGIN_INFO_REQENGSVCVERSION_INDEX].title = EngFncs->engine_strdup( _("Required Engine Services Version") );
                Info->info[PLUGIN_INFO_REQENGSVCVERSION_INDEX].desc = EngFncs->engine_strdup( _("This is the version of the Engine services that this plugin requires.  "
												"It will not run on older versions of the Engine services.") );
                Info->info[PLUGIN_INFO_REQENGSVCVERSION_INDEX].type               = EVMS_Type_String;
                Info->info[PLUGIN_INFO_REQENGSVCVERSION_INDEX].unit               = EVMS_Unit_None;
                Info->info[PLUGIN_INFO_REQENGSVCVERSION_INDEX].value.s = EngFncs->engine_strdup( required_engine_api_version_string );
                Info->info[PLUGIN_INFO_REQENGSVCVERSION_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[PLUGIN_INFO_REQENGSVCVERSION_INDEX].group, 0, sizeof(group_info_t));

                Info->info[PLUGIN_INFO_REQPLUGAPIVERSION_INDEX].name = EngFncs->engine_strdup( "Required Engine Plug-in API Version" );
                Info->info[PLUGIN_INFO_REQPLUGAPIVERSION_INDEX].title = EngFncs->engine_strdup( _("Required Engine Plug-in API Version") );
                Info->info[PLUGIN_INFO_REQPLUGAPIVERSION_INDEX].desc = EngFncs->engine_strdup( _("This is the version of the Engine plug-in API that this plugin requires.  "
												 "It will not run on older versions of the Engine plug-in API.") );
                Info->info[PLUGIN_INFO_REQPLUGAPIVERSION_INDEX].type               = EVMS_Type_String;
                Info->info[PLUGIN_INFO_REQPLUGAPIVERSION_INDEX].unit               = EVMS_Unit_None;
                Info->info[PLUGIN_INFO_REQPLUGAPIVERSION_INDEX].value.s = EngFncs->engine_strdup( required_plugin_api_version_string );
                Info->info[PLUGIN_INFO_REQPLUGAPIVERSION_INDEX].collection_type    = EVMS_Collection_None;
                memset( &Info->info[PLUGIN_INFO_REQPLUGAPIVERSION_INDEX].group, 0, sizeof(group_info_t));

                *info = Info;

                rc = 0;
        }


        LOG_EXIT_INT(rc);
        return rc;
}