/*
 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
 *
 * U.S. Government Rights - Commercial software. Government users are subject
 * to the Sun Microsystems, Inc. standard license agreement and applicable
 * provisions of the FAR and its supplements.
 *
 *
 * This distribution may include materials developed by third parties. Sun,
 * Sun Microsystems, the Sun logo and Solaris are trademarks or registered
 * trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
 *
 */
/*
 * Note: this file originally auto-generated by mib2c using
 *        : mib2c.iterate.conf,v 5.5 2002/12/16 22:50:18 hardaker Exp $
 */

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "stdhdr.h"
#include "entPhysicalContainsTable.h"
#include "entPhysicalTable.h"
#include "entLastChangeTime.h"

static int FreePhyContainsTableEntry(physIndexAndChildIndex_t *);
static int isRecursiveChild(int, int);

physIndexAndChildIndex_t *gPhyContainsTableHead;
int gPhyContainsTableSize;
/* Fix for 4910641 */
int_l *zChildIndexesTracker;
/* End of Fix for 4910641 */

/** Initialize the entPhysicalContainsTable table by defining its contents and how it's structured */
void
initialize_table_entPhysicalContainsTable(void)
{
    static oid entPhysicalContainsTable_oid[] = {1,3,6,1,2,1,47,1,3,3};
    netsnmp_table_registration_info *table_info;
    netsnmp_handler_registration *my_handler;
    netsnmp_iterator_info *iinfo;

    /* create the table structure itself */
    table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
    iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);

    /* if your table is read only, it's easiest to change the
       HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY */
    /* Fix for 4910624 - changing HANDLER_CAN_RWRITE to HANDLER_CAN_RONLY */
    my_handler = netsnmp_create_handler_registration("entPhysicalContainsTable",
                                                     entPhysicalContainsTable_handler,
                                                     entPhysicalContainsTable_oid,
                                                     OID_LENGTH(entPhysicalContainsTable_oid),
                                                     HANDLER_CAN_RONLY);
    /* End of Fix for 4910624 */
            
    if (!my_handler || !table_info || !iinfo)
        return; /* mallocs failed */

    /***************************************************
     * Setting up the table's definition
     */
    netsnmp_table_helper_add_indexes(table_info,
                                     ASN_INTEGER, /* index: entPhysicalIndex */
                                     ASN_INTEGER, /* index: entPhysicalChildIndex */
                                     0);

    table_info->min_column = 1;
    table_info->max_column = 1;

    /* iterator access routines */
    iinfo->get_first_data_point = entPhysicalContainsTable_get_first_data_point;
    iinfo->get_next_data_point = entPhysicalContainsTable_get_next_data_point;

    iinfo->table_reginfo = table_info;

    /***************************************************
     * registering the table with the master agent
     */
    DEBUGMSGTL(("initialize_table_entPhysicalContainsTable",
                "Registering table entPhysicalContainsTable as a table iterator\n"));		 
    netsnmp_register_table_iterator(my_handler, iinfo);
}

/** Initializes the entPhysicalContainsTable module */
void
init_entPhysicalContainsTable(void)
{

    /* here we initialize all the tables we're planning on supporting */
    initialize_table_entPhysicalContainsTable();
    gPhyContainsTableHead = NULL;
    gPhyContainsTableSize = 0;
}

/** returns the first data point within the entPhysicalContainsTable table data.

    Set the my_loop_context variable to the first data point structure
    of your choice (from which you can find the next one).  This could
    be anything from the first node in a linked list, to an integer
    pointer containing the beginning of an array variable.

    Set the my_data_context variable to something to be returned to
    you later that will provide you with the data to return in a given
    row.  This could be the same pointer as what my_loop_context is
    set to, or something different.

    The put_index_data variable contains a list of snmp variable
    bindings, one for each index in your table.  Set the values of
    each appropriately according to the data matching the first row
    and return the put_index_data variable at the end of the function.
*/
netsnmp_variable_list *
entPhysicalContainsTable_get_first_data_point(void **my_loop_context, void **my_data_context,
                                              netsnmp_variable_list *put_index_data,
                                              netsnmp_iterator_info *mydata)
{

    netsnmp_variable_list *vptr;
    physIndexAndChildIndex_t *zRunner, *zpValidEntry;
    int_l *zChildIndexes, zValidChildIdx=0, *zpValidChildIdx;

    zRunner = gPhyContainsTableHead;
    while (zRunner) {
        if (zRunner->entPhysicalIndex > 0) {
            zChildIndexes = zRunner->childIndexes;
            while ((zChildIndexes != NULL) && (*zChildIndexes != 0)){
                if (*zChildIndexes > 0) {
                    zValidChildIdx = *zChildIndexes;
                    break;
                }
                zChildIndexes++;
            }
            if (zValidChildIdx) {
                zpValidEntry = zRunner;
                zpValidChildIdx = zChildIndexes;
                break;
            }
        }
        zRunner = zRunner->pNextEntry;
    }
    if (zRunner == NULL) return NULL;

    /* Fix for 4910641: No idea why it worked in Sparc with the original */
    /*                  version.  *my_loop_context was pointing to */
    /*                  temporary address, and maybe Intel and Sparc handles */
    /*                  memory differently - that is probably why it worked */
    /*                  on Sparc but not on Intel.  This version is */
    /*                  valid, and easier to trace and understand. */
    *my_loop_context = (void *) zpValidEntry;
    *my_data_context = (void *) zpValidChildIdx;
    zChildIndexesTracker = zpValidChildIdx;
    /* End of Fix for 4910641 */

    vptr = put_index_data;
    
    snmp_set_var_value(vptr, (u_char *) &zpValidEntry->entPhysicalIndex, sizeof(zpValidEntry->entPhysicalIndex));
    vptr = vptr->next_variable;
    snmp_set_var_value(vptr, (u_char *) zpValidChildIdx, sizeof(int_l));
    vptr = vptr->next_variable;

    return put_index_data;
}

/** functionally the same as entPhysicalContainsTable_get_first_data_point, but
   my_loop_context has already been set to a previous value and should
   be updated to the next in the list.  For example, if it was a
   linked list, you might want to cast it and the return
   my_loop_context->next.  The my_data_context pointer should be set
   to something you need later and the indexes in put_index_data
   updated again. */

netsnmp_variable_list *
entPhysicalContainsTable_get_next_data_point(void **my_loop_context, void **my_data_context,
                                             netsnmp_variable_list *put_index_data,
                                             netsnmp_iterator_info *mydata)
{

    netsnmp_variable_list *vptr;
    physIndexAndChildIndex_t *zRunner, *zpValidEntry;
    int_l *zChildIndexes, zValidChildIdx=0, *zpValidChildIdx;

    /* Fix for 4910641: We need to dereference the pointers, and cast */
    /*                  them back to the appropriate data structure */
    zRunner = (physIndexAndChildIndex_t *)*my_loop_context;
    zChildIndexes = zChildIndexesTracker;
    /* End of Fix for 4910641 */

    if (zChildIndexes) 
	zChildIndexes++;
    while (zRunner) {
        if (zRunner->entPhysicalIndex > 0) {
            while ((zChildIndexes != NULL) && (*zChildIndexes != 0)){
                if (*zChildIndexes > 0) {
                    zValidChildIdx = *zChildIndexes;
                    break;
                }
                zChildIndexes++;
            }
            if (zValidChildIdx) {
                zpValidEntry = zRunner;
                zpValidChildIdx = zChildIndexes;
                break;
            }
        }
        zRunner = zRunner->pNextEntry;
        if (zRunner)
            zChildIndexes = zRunner->childIndexes;
    }
    if (zRunner == NULL) return NULL;

    /* Fix for 4910641: We are making sure that *my_loop_context and */
    /*                  *my_data_context are pointing to valid entries. */
    *my_loop_context = (void *) zpValidEntry;
    *my_data_context = (void *) zpValidChildIdx;
    zChildIndexesTracker = zpValidChildIdx;
    /* End Fix for 4910641 */
    
    vptr = put_index_data;
    
    snmp_set_var_value(vptr, (u_char *) &zpValidEntry->entPhysicalIndex, sizeof(zpValidEntry->entPhysicalIndex));
    vptr = vptr->next_variable;
    snmp_set_var_value(vptr, (u_char *) zpValidChildIdx, sizeof(int_l));
    vptr = vptr->next_variable;

    return put_index_data;
}

/** handles requests for the entPhysicalContainsTable table, if anything else needs to be done */
int
entPhysicalContainsTable_handler(
    netsnmp_mib_handler               *handler,
    netsnmp_handler_registration      *reginfo,
    netsnmp_agent_request_info        *reqinfo,
    netsnmp_request_info              *requests) {

    netsnmp_request_info *request;
    netsnmp_table_request_info *table_info;
    netsnmp_variable_list *var;
    int_l *idx;
    
    for(request = requests; request; request = request->next) {
        var = request->requestvb;
        if (request->processed != 0)
            continue;

        /* perform anything here that you need to do before each
           request is processed. */

        /* the following extracts the my_data_context pointer set in
           the loop functions above.  You can then use the results to
           help return data for the columns of the entPhysicalContainsTable table in question */
        idx = (int_l *) netsnmp_extract_iterator_context(request);
        if (idx == NULL) {
            if (reqinfo->mode == MODE_GET) {
                netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE);
                continue;
            }
            /* XXX: no row existed, if you support creation and this is a
               set, start dealing with it here, else continue */
        }

        /* extracts the information about the table from the request */
        table_info = netsnmp_extract_table_info(request);
        /* table_info->colnum contains the column number requested */
        /* table_info->indexes contains a linked list of snmp variable
           bindings for the indexes of the table.  Values in the list
           have been set corresponding to the indexes of the
           request */
        if (table_info==NULL) {
            continue;
        }

        switch(reqinfo->mode) {
            /* the table_iterator helper should change all GETNEXTs
               into GETs for you automatically, so you don't have to
               worry about the GETNEXT case.  Only GETs and SETs need
               to be dealt with here */
        case MODE_GET:
            switch(table_info->colnum) {
            case COLUMN_ENTPHYSICALCHILDINDEX:
                snmp_set_var_typed_value(var, ASN_INTEGER, (u_char *) idx, sizeof(idx));
                break;

            default:
                /* We shouldn't get here */
                snmp_log(LOG_ERR, "problem encountered in entPhysicalContainsTable_handler: unknown column\n");
            }
            break;

        case MODE_SET_RESERVE1:
            /* set handling... */

        default:
            snmp_log(LOG_ERR, "problem encountered in entPhysicalContainsTable_handler: unsupported mode\n");
        }
    }
    return SNMP_ERR_NOERROR;
}

/* Returns 0 for success
   1 if the entry already exists
   -1 for failure
   -2 for stale index */
/* Fix for 4915033 */
int addPhysicalContainsTableEntry(int xentPhysicalIndex, int xentChildIndex)
/* End of Fix for 4915033 */
{
    entPhysicalEntry_t *physentry, *childentry;
    physIndexAndChildIndex_t *zContainsTableEntry, *zRunner, *zlastEntry;
    int_l *zChildIndexes;
 
    /* Fix for 4890316: Check that adding itself as a child is not allowed */
    if (xentPhysicalIndex == xentChildIndex) {
        return (-1);
    }
    /* End of Fix for 4890316 */

    /* Fix for 48888088: -1 for invalid index, -2 for stale entries */
    if (xentPhysicalIndex <= 0 || xentPhysicalIndex > MAX_ENTITY_INDEX || xentChildIndex <= 0 || xentChildIndex > MAX_ENTITY_INDEX)
        return -1;
    physentry = getPhysicalTableStaleEntry(xentPhysicalIndex);
    if (physentry != NULL)
        return -2;
    childentry = getPhysicalTableStaleEntry(xentChildIndex);
    if (childentry != NULL)
        return -2;
    /* End of Fix for 4888088 */

    physentry = getPhysicalTableEntry(xentPhysicalIndex);
    childentry = getPhysicalTableEntry(xentChildIndex);

    if (physentry == NULL || childentry == NULL) {
/*
  Handle error here. Send it to log files
*/
        return (-1);
    }

    /* Fix for 4915080 */
    if (isRecursiveChild(xentChildIndex, xentPhysicalIndex))
        return (-1);
    /* End of Fix for 4915080 */

    zlastEntry = NULL;
    zRunner = gPhyContainsTableHead;
    while (zRunner != NULL) {
        if (zRunner->entPhysicalIndex == xentPhysicalIndex) {
            break;
        }
        zlastEntry = zRunner;
        zRunner = zRunner->pNextEntry;
    }
    if (zRunner != NULL ) {/* Found a entry with log index */
        int_l *p;
        p = zRunner->childIndexes;
        if (p == NULL) {
            zChildIndexes = (int_l *) malloc(2 * sizeof (int_l));
            if (!zChildIndexes) return -1;
            zChildIndexes[0] = xentChildIndex;
            zChildIndexes[1] = 0;
            zRunner->childIndexes = zChildIndexes;
        } else {/* Add phy index to last entry in the array */
            int i=0;
            int_l *empty = NULL;
            while (p != NULL && *p != 0) {
                if (*p == xentChildIndex) {
                    /* Already in the array, return a 1 */
		    return (1);
	        }
                if (*p == -1) /* Empty Slot */
                    empty = p;
                p++;
                i++;
            }
	    if (empty) { /* Reuse a empty spot */
		*empty = xentChildIndex;
	    } else {
                zRunner->childIndexes =
                    (int_l *)realloc(zRunner->childIndexes, (i + 2)*sizeof(int_l));
		if (!zRunner->childIndexes) return -1;
                zRunner->childIndexes[i] = xentChildIndex;
                zRunner->childIndexes[i+1] = 0;
	    }
        }
        /* Fix for 4891869: We replace entPhysicalContainedIn with this */
        /*                  entry only when this index is lower */
        if (childentry->entPhysicalContainedIn == 0 || childentry->entPhysicalContainedIn > xentPhysicalIndex)
            childentry->entPhysicalContainedIn = xentPhysicalIndex;
        /* End of Fix for 4891869 */
        configChanged();
        return (0);
    }

    /* New entry*/
    zContainsTableEntry = (physIndexAndChildIndex_t *)malloc(sizeof(physIndexAndChildIndex_t));
    if (!zContainsTableEntry) return -1;
    zContainsTableEntry->entPhysicalIndex = xentPhysicalIndex;
    zChildIndexes = (int_l *) malloc(2 * sizeof (int_l));
    if (!zChildIndexes) return -1;
    zChildIndexes[0] = xentChildIndex;
    zChildIndexes[1] = 0;
    zContainsTableEntry->childIndexes = zChildIndexes;
    zContainsTableEntry->pNextEntry = NULL;
    if (zlastEntry){
        zlastEntry->pNextEntry = zContainsTableEntry;
    } else {
        gPhyContainsTableHead = zContainsTableEntry;
    }
    /* Fix for 4891869: We replace entPhysicalContainedIn with this entry */
    /*                  only when this index is lower */
    if (childentry->entPhysicalContainedIn == 0 || childentry->entPhysicalContainedIn > xentPhysicalIndex)
        childentry->entPhysicalContainedIn = xentPhysicalIndex;
    /* End of Fix for 4891869 */
    gPhyContainsTableSize++;
    configChanged();
    return (0);
}

/*
 * Returns NULL if children, else returns int array with null termination
 * The array is not a copy and SHOULD NOT be written to unless the
 * intent is to update the master information
 */
/* Fix for 4915033 */
int *getPhysicalContainsChildren(int parentIndex)
/* End of Fix for 4915033 */
{
    entPhysicalEntry_t *physentry;
    int_l *childIndexes=NULL;
    /* Fix for 4914153 */
    int *resultIndexes=NULL, i = 0;
    /* End of Fix for 4914153 */
    physIndexAndChildIndex_t *zRunner;

    /*
     * Find parent
     */
    physentry = getPhysicalTableEntry(parentIndex);
    if (physentry == NULL) {
        return (NULL);  /* assume no children */
    }

    zRunner = gPhyContainsTableHead;
    while (zRunner != NULL) {
        if ((zRunner->entPhysicalIndex == parentIndex)) {
            childIndexes = zRunner->childIndexes;
            /* Fix for 4914153: From this childIndexes array, we only */
            /* returns the true children array, excluding those "-1" entries */
            if (childIndexes != NULL) {
                while (*childIndexes != 0) {
                    /* We only need to count this entry if it is a valid */
                    /* (> -1) entry.  Else we move on until the end of the */
                    /* list */
                    if (*childIndexes > 0) {
                        resultIndexes = realloc(resultIndexes, (i + 1)*sizeof(int));
                        if (resultIndexes == NULL)
                            return NULL; /* Not enough memory, just return NULL */
                        resultIndexes[i] = *childIndexes;
                        i++;

                    }
                    childIndexes++;
                }
            }
            /* We can break here because this condition: */
            /* zRunner->entPhysicalIndex == parentIndex condition */
            /* can only happen once in the entPhysicalContains linked list */
            break;
            /* End of Fix for 4914153 */
        }
        zRunner = zRunner->pNextEntry;
    }
    /* Fix for 4914153: returns a NULL terminated list */
    if (i > 0) /* at least one child is found */
        resultIndexes = realloc(resultIndexes, (i + 1)*sizeof(int));
    if (resultIndexes == NULL) /* Not enough memory or no child found -> NULL */
        return NULL;
    resultIndexes[i] = 0;
    return (resultIndexes);
    /* End of Fix for 4914153 */
}

/* Fix for 4915033 */
/* This function will delete all the entries which has the parent index = */
/* xParentIndex. */
/* Returns number of entries deleted for success, */
/* -1 if entry not found */
/* -2 if stale */
int deletePhysicalContainsParentIndex(int xParentIndex)
{
    /* We go through the ContainsTable, and remove the parent */
    physIndexAndChildIndex_t *zRunner, *prevEntry, *temp=NULL;
    int num=0;
    /* Fix for 4926042*/
    int *childIndexes, *zchildIndexes;
    /* End of Fix for 4926042 */
    int_l *childIndexes2;
    int lowest_index = 0;
    entPhysicalEntry_t *physentry;
    int num_child=0;

    /* Fix for 4888088 */
    if (xParentIndex <= 0 || xParentIndex > MAX_ENTITY_INDEX)
        return -1;
    physentry = getPhysicalTableStaleEntry(xParentIndex);
    if (physentry != NULL)
        return -2;
    /* End of Fix for 4888088 */

    zRunner = gPhyContainsTableHead;
    prevEntry = NULL;

    while (zRunner != NULL) {
        if (zRunner->entPhysicalIndex == xParentIndex) {
            temp =  zRunner->pNextEntry;
            zRunner->pNextEntry = NULL;

            /* Fix for 4891869: we need to figure out the list of children */
            /*                  belonging to this parent, before actually */
            /*                  deleting the parent */
            childIndexes = getPhysicalContainsChildren(xParentIndex);
            /* Fix for 4926042 */
            zchildIndexes = childIndexes;
            /* End of Fix for 4926042 */
            /* End of Fix for 4891869 */

            if (prevEntry)
                prevEntry->pNextEntry = temp;
            else
                gPhyContainsTableHead = temp;
            FreePhyContainsTableEntry(zRunner);
            num++;
            gPhyContainsTableSize--;
            break;
        }
        prevEntry = zRunner;
        zRunner = zRunner->pNextEntry;
    }
    if (num) {
        /* Fix for 4891869: We need to sync the entPhysicalContainedIn */
        /* 1. Find all the children that has this as a parent */
        /* 2. If the parent is the last one for this child, reset the */
        /*    entPhysicalContainedIn to 0 */
        /* 3. If more than one parent, and if this is the lowest index, */
        /*    then reset this to the next lowest */
        /* 4. Otherwise do nothing */
        num_child = 0;
        while (childIndexes != NULL && *childIndexes != 0) {
            physentry = getPhysicalTableEntry(*childIndexes);
            if (physentry != NULL) {
                /* Need to reset entPhysicalContainedIn only if the */
                /* xParentIndex is already the lowest index.  In this case, */
                /* we will go through the ContainsTable and search for */
                /* all the parents for this particular child, and set it */
                /* to the second lowest index */
                if (physentry->entPhysicalContainedIn == xParentIndex) {
                    zRunner = gPhyContainsTableHead;
                    lowest_index = 0; /* First reset to zero */

                    while (zRunner != NULL) {
                        childIndexes2 = zRunner->childIndexes;
                        while (childIndexes2 != NULL && *childIndexes2 != 0) {
                            if (*childIndexes2 == *childIndexes) {
                                if (lowest_index == 0)
                                    lowest_index = zRunner->entPhysicalIndex;
                                else if (lowest_index > zRunner->entPhysicalIndex)
                                    lowest_index = zRunner->entPhysicalIndex;
                                break;
                            }
                            childIndexes2++;
                        }
                        zRunner = zRunner->pNextEntry;
                    }
                    physentry->entPhysicalContainedIn = lowest_index;
                }
            }
            /* Fix for 4888088: count the number of children */
            if (*childIndexes > 0)
                num_child++;
            /* End of Fix for 4888088 */
            childIndexes++;
        }
        /* End of Fix for 4891869 */
        configChanged();
        /* Fix for 4926042 */
        free (zchildIndexes);
        /* End of Fix for 4926042 */
        return (num_child);
    } else {
        return (-1);
    }
}

/* This function will delete all the entries which has the child index = */
/* xChildIndex */
/* Returns number of entries deleted for success, */
/* -1 if entry not found */
/* -2 if entry is stale */
int deletePhysicalContainsChildIndex(int xChildIndex)
{
    physIndexAndChildIndex_t *zRunner;
    int_l *childIndexes=NULL;
    int num=0;

    /* Fix for 4888088 */
    entPhysicalEntry_t *physentry;
    if (xChildIndex <= 0 || xChildIndex > MAX_ENTITY_INDEX)
        return -1;
    physentry = getPhysicalTableStaleEntry(xChildIndex);
    if (physentry != NULL)
        return -2;
    /* End of Fix for 4888088 */

    zRunner = gPhyContainsTableHead;
    while (zRunner != NULL) {
        childIndexes = zRunner->childIndexes;
        while (childIndexes != NULL && *childIndexes != 0) {
            if (*childIndexes == xChildIndex) {
                deletePhysicalContainsTableEntry((int)zRunner->entPhysicalIndex, xChildIndex);
                num++;
            }
            childIndexes++;
        }
        zRunner = zRunner->pNextEntry;
    }
    if (num) {
        configChanged();
        return (num);
    } else {
        return (-1);
    }
}

/* Delete the entry specified by the xParentIndex and xChildIndex */
/* returns 0 if successful */
/* -1 if entry not found */
/* -2 if entry is stale */
int deletePhysicalContainsTableEntry(int xParentIndex, int xChildIndex)
{
    physIndexAndChildIndex_t *zRunner;
    entPhysicalEntry_t *physentry;
    int zparentIdx;
    int num=0;
    int_l *childIndexes=NULL;
    int lowest_index = 0;

    /* Fix for 4888088 */
    if (xParentIndex <= 0 || xParentIndex > MAX_ENTITY_INDEX || xChildIndex <= 0 || xChildIndex > MAX_ENTITY_INDEX)
        return -1;
    physentry = getPhysicalTableStaleEntry(xParentIndex);
    if (physentry != NULL)
        return -2;
    physentry = getPhysicalTableStaleEntry(xChildIndex);
    if (physentry != NULL)
        return -2;
    /* End of Fix for 4888088 */
    
    zRunner = gPhyContainsTableHead;

    while (zRunner != NULL) {
        zparentIdx = zRunner->entPhysicalIndex;
        if (zparentIdx == xParentIndex) {
            childIndexes = zRunner->childIndexes;
            while (childIndexes != NULL && *childIndexes != 0) {
                if (*childIndexes == xChildIndex) {
                    *childIndexes = -1;
                    num++;
                }
                childIndexes++;
            }
            break;
        }
        zRunner = zRunner->pNextEntry;
    }
    if (num) {
        /* Fix for 4891869: we need to make sure that we reset the */
        /* entPhysicalContainedIn when necessary */
        physentry = getPhysicalTableEntry(xChildIndex);
        if (physentry != NULL) {
            if (physentry->entPhysicalContainedIn == xParentIndex) {
                /* we want to set entPhysicalContainedIn to the lowest value */
                /* or to zero if necessary */
                zRunner = gPhyContainsTableHead;
                while (zRunner != NULL) {
                    childIndexes = zRunner->childIndexes;
                    while (childIndexes != NULL && *childIndexes != 0) {
                        if (*childIndexes == xChildIndex) {
                            if (lowest_index == 0)
                                lowest_index = zRunner->entPhysicalIndex;
                            else if (lowest_index > zRunner->entPhysicalIndex)
                                lowest_index = zRunner->entPhysicalIndex;
                            break;
                        }
                        childIndexes++;
                    }
                    zRunner = zRunner->pNextEntry;
                }
                physentry->entPhysicalContainedIn = lowest_index;
            }
        }
        /* End of Fix for 4891869 */
        configChanged();
        return (0);
    } else {
        return (-1);
    }
}
/* End of Fix for 4915033 */

static int 
FreePhyContainsTableEntry(physIndexAndChildIndex_t *xEntry)
{
    if (xEntry == NULL) return (-1);
    free(xEntry->childIndexes);
    free(xEntry);
    xEntry = NULL;
    return 0;
}

/* Fix for 4915080 */
/* Check to see if childIndex is really related to the parentIndex, in */
/* a directed graph way.  Return 1 if it is related, 0 if not. */
static int isRecursiveChild(int parentIndex, int childIndex)
{
    int i, ret;
    int *childlist;
    int *childlist2;

    i = 0;
    ret = 0;

    if (parentIndex == childIndex)
        return 1;

    /* Check for the entPhysicalContainedIn */
    childlist = getAllChildrenFromPhysicalContainedIn(parentIndex);
    if (childlist != NULL) {
        while (childlist[i] != NULL) {
            ret = isRecursiveChild(childlist[i], childIndex);
            if (ret == 1) {
                free(childlist);
                return 1;
            }
            i++;
        }
        free(childlist);
    }

    /* Now we deal with the entPhysicalContainsTable */
    childlist2 = getPhysicalContainsChildren(parentIndex);
    i = 0;
    if (childlist2 != NULL) {
        while (childlist2[i] != NULL) {
            ret = isRecursiveChild(childlist2[i], childIndex);
            if (ret == 1) {
                free(childlist2);
                return 1;
            }
            i++;
        }
        free(childlist2);
    }

    return 0;
}
/* End of Fix for 4915080 */
