root/usr/src/lib/udapl/libdat/common/dat_sr.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
 */

/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 *
 * MODULE: dat_sr.c
 *
 * PURPOSE: static registry implementation
 *
 * $Id: dat_sr.c,v 1.12 2003/08/20 14:28:40 hobie16 Exp $
 */


#include "dat_sr.h"

#include "dat_dictionary.h"
#include "udat_sr_parser.h"


/*
 *
 * Global Variables
 *
 */

static DAT_OS_LOCK              g_sr_lock;
static DAT_DICTIONARY           *g_sr_dictionary = NULL;


/*
 *
 * External Functions
 *
 */


/*
 * Function: dat_sr_init
 */

DAT_RETURN
dat_sr_init(void)
{
        DAT_RETURN                      status;

        status = dat_os_lock_init(&g_sr_lock);
        if (DAT_SUCCESS != status) {
                return (status);
        }

        status = dat_dictionary_create(&g_sr_dictionary);
        if (DAT_SUCCESS != status) {
                return (status);
        }

        /*
         * Since DAT allows providers to be loaded by either the static
         * registry or explicitly through OS dependent methods, do not
         * return an error if no providers are loaded via the static registry.
         */

        (void) dat_sr_load();

        return (DAT_SUCCESS);
}


/*
 * Function: dat_sr_fini
 */

extern DAT_RETURN
dat_sr_fini(void)
{
        DAT_RETURN                      status;

        status = dat_os_lock_destroy(&g_sr_lock);
        if (DAT_SUCCESS != status) {
                return (status);
        }

        status = dat_dictionary_destroy(g_sr_dictionary);
        if (DAT_SUCCESS != status) {
                return (status);
        }

        return (DAT_SUCCESS);
}


/*
 * Function: dat_sr_insert
 */

extern DAT_RETURN
dat_sr_insert(
    IN  const DAT_PROVIDER_INFO *info,
    IN  DAT_SR_ENTRY            *entry)
{
        DAT_RETURN              status;
        DAT_SR_ENTRY            *data;
        DAT_OS_SIZE             lib_path_size;
        DAT_OS_SIZE             lib_path_len;
        DAT_OS_SIZE             ia_params_size;
        DAT_OS_SIZE             ia_params_len;
        DAT_DICTIONARY_ENTRY    dict_entry;

        if (NULL == (data = dat_os_alloc(sizeof (DAT_SR_ENTRY)))) {
                status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
                    DAT_RESOURCE_MEMORY);
                goto bail;
        }

        lib_path_len = strlen(entry->lib_path);
        lib_path_size = (lib_path_len + 1) * sizeof (char);

        if (NULL == (data->lib_path = dat_os_alloc(lib_path_size))) {
                status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
                    DAT_RESOURCE_MEMORY);
                goto bail;
        }

        (void) dat_os_strncpy(data->lib_path, entry->lib_path, lib_path_len);
        data->lib_path[lib_path_len] = '\0';

        ia_params_len = strlen(entry->ia_params);
        ia_params_size = (ia_params_len + 1) * sizeof (char);

        if (NULL == (data->ia_params = dat_os_alloc(ia_params_size))) {
                status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
                    DAT_RESOURCE_MEMORY);
                goto bail;
        }

        (void) dat_os_strncpy(data->ia_params, entry->ia_params, ia_params_len);
        data->ia_params[ia_params_len] = '\0';

        data->info = entry->info;
        data->lib_handle = entry->lib_handle;
        data->ref_count = entry->ref_count;

        dict_entry = NULL;
        status = dat_dictionary_entry_create(&dict_entry);
        if (DAT_SUCCESS != status) {
                goto bail;
        }

        dat_os_lock(&g_sr_lock);

        status = dat_dictionary_insert(g_sr_dictionary,
                                dict_entry,
                                info,
                                (DAT_DICTIONARY_DATA *)data);
        dat_os_unlock(&g_sr_lock);

bail:
        if (DAT_SUCCESS != status) {
                if (NULL != data) {
                        if (NULL != data->lib_path) {
                                dat_os_free(data->lib_path, lib_path_size);
                        }

                        if (NULL != data->ia_params) {
                                dat_os_free(data->ia_params, ia_params_size);
                        }

                        dat_os_free(data, sizeof (DAT_SR_ENTRY));
                }

                if (NULL != dict_entry) {
                        (void) dat_dictionary_entry_destroy(dict_entry);
                }
        }

        return (status);
}


/*
 * Function: dat_sr_size
 */

extern DAT_RETURN
dat_sr_size(
    OUT DAT_COUNT               *size)
{
        return (dat_dictionary_size(g_sr_dictionary, size));
}


/*
 * Function: dat_sr_list
 */

extern DAT_RETURN
dat_sr_list(
    IN  DAT_COUNT               max_to_return,
    OUT DAT_COUNT               *entries_returned,
    OUT DAT_PROVIDER_INFO       * (dat_provider_list[]))
{
        DAT_SR_ENTRY            **array;
        DAT_COUNT               array_size;
        DAT_COUNT               i;
        DAT_RETURN              status;

        array = NULL;
        status = DAT_SUCCESS;

        /*
         * The dictionary size may increase between the call to
         * dat_dictionary_size() and dat_dictionary_enumerate().
         * Therefore we loop until a successful enumeration is made.
         */
        *entries_returned = 0;
        for (;;) {
                status = dat_dictionary_size(g_sr_dictionary, &array_size);
                if (DAT_SUCCESS != status) {
                        goto bail;
                }

                if (array_size == 0) {
                        status = DAT_SUCCESS;
                        goto bail;
                }

                array = dat_os_alloc(array_size * sizeof (DAT_SR_ENTRY *));
                if (array == NULL) {
                        status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
                            DAT_RESOURCE_MEMORY);
                        goto bail;
                }

                dat_os_lock(&g_sr_lock);

                status = dat_dictionary_enumerate(g_sr_dictionary,
                                (DAT_DICTIONARY_DATA *) array,
                                array_size);

                dat_os_unlock(&g_sr_lock);

                if (DAT_SUCCESS == status) {
                        break;
                } else {
                        dat_os_free(array,
                            array_size * sizeof (DAT_SR_ENTRY *));
                        array = NULL;
                        continue;
                }
        }

        for (i = 0; (i < max_to_return) && (i < array_size); i++) {
                if (NULL == dat_provider_list[i]) {
                        status = DAT_ERROR(DAT_INVALID_PARAMETER,
                            DAT_INVALID_ARG3);
                        goto bail;
                }

                *dat_provider_list[i] = array[i]->info;
        }

        *entries_returned = i;

bail:
        if (NULL != array) {
                dat_os_free(array, array_size * sizeof (DAT_SR_ENTRY *));
        }

        return (status);
}



/*
 * Function: dat_sr_provider_open
 */

extern DAT_RETURN
dat_sr_provider_open(
    IN  const DAT_PROVIDER_INFO *info)
{
        DAT_RETURN              status;
        DAT_SR_ENTRY            *data;

        dat_os_lock(&g_sr_lock);

        status = dat_dictionary_search(g_sr_dictionary,
                        info,
                        (DAT_DICTIONARY_DATA *) &data);

        if (DAT_SUCCESS == status) {
                if (0 == data->ref_count) {
                        status = dat_os_library_load(data->lib_path,
                            &data->lib_handle);
                        if (status == DAT_SUCCESS) {
                                data->ref_count++;
                        } else {
                                dat_os_dbg_print(DAT_OS_DBG_TYPE_SR,
                                    "DAT Registry: static registry unable to "
                                    "load library %s\n", data->lib_path);
                                goto bail;
                        }
                        data->init_func = (DAT_PROVIDER_INIT_FUNC)
                            dat_os_library_sym(data->lib_handle,
                                DAT_PROVIDER_INIT_FUNC_STR);
                        data->fini_func = (DAT_PROVIDER_FINI_FUNC)
                            dat_os_library_sym(data->lib_handle,
                                DAT_PROVIDER_FINI_FUNC_STR);

                        if (NULL != data->init_func) {
                                (*data->init_func)(&data->info,
                                    data->ia_params);
                        }
                } else {
                        data->ref_count++;
                }
        }

bail:
        dat_os_unlock(&g_sr_lock);

        return (status);
}


/*
 * Function: dat_sr_provider_close
 */

extern DAT_RETURN
dat_sr_provider_close(
    IN  const DAT_PROVIDER_INFO *info)
{
        DAT_RETURN              status;
        DAT_SR_ENTRY            *data;

        dat_os_lock(&g_sr_lock);

        status = dat_dictionary_search(g_sr_dictionary,
                        info,
                        (DAT_DICTIONARY_DATA *)&data);

        if (DAT_SUCCESS == status) {
                if (1 == data->ref_count) {
                        if (NULL != data->fini_func) {
                                (*data->fini_func)(&data->info);
                        }

                        status = dat_os_library_unload(data->lib_handle);
                        if (status == DAT_SUCCESS) {
                                data->ref_count--;
                        }
                } else {
                        data->ref_count--;
                }
        }

        dat_os_unlock(&g_sr_lock);

        return (status);
}