root/usr/src/cmd/isns/isnsd/config.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (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 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdlib.h>
#include <string.h>
#include <libscf.h>
#include <pthread.h>

#include "isns_server.h"
#include "isns_log.h"
#include "isns_cfg.h"

/*
 * external variables
 */
extern uint64_t esi_threshold;
extern uint8_t mgmt_scn;
extern ctrl_node_t *control_nodes;
extern pthread_mutex_t ctrl_node_mtx;
extern char data_store[MAXPATHLEN];

#define DEFAULT_ESI_THRESHOLD   3
#define MAX_ESI_THRESHOLD       10

/*
 * load_config loads config data through SMF.
 * arg DATA_STORE_UPDATE indicates whether the data store location
 * can be updated or not.
 */
int
load_config(boolean_t DATA_STORE_UPDATE)
{

        int retval = -1;

        scf_handle_t    *handle = NULL;
        scf_scope_t     *sc = NULL;
        scf_service_t   *svc = NULL;
        scf_propertygroup_t     *pg = NULL;
        scf_property_t  *prop = NULL;
        scf_value_t     *value = NULL;
        scf_iter_t      *value_iter = NULL;

        ctrl_node_t *ctrl_node_p;
        char scf_name[MAXNAMELEN];
        char *name;

        /* connect to the current SMF global repository */
        handle = scf_handle_create(SCF_VERSION);

        /* allocate scf resources */
        sc = scf_scope_create(handle);
        svc = scf_service_create(handle);
        pg = scf_pg_create(handle);
        prop = scf_property_create(handle);
        value = scf_value_create(handle);
        value_iter = scf_iter_create(handle);

        /* if failed to allocate resources, exit */
        if (handle == NULL || sc == NULL || svc == NULL || pg == NULL ||
            prop == NULL || value == NULL || value_iter == NULL) {
                isnslog(LOG_DEBUG, "load_config",
                    "scf handles allocation failed.");
                goto out;
        }

        /* bind scf handle to the running svc.configd daemon */
        if (scf_handle_bind(handle) == -1) {
                isnslog(LOG_DEBUG, "load_config", "scf binding failed.");
                goto out;
        }

        /* get the scope of the localhost in the current repository */
        if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, sc) == -1) {
                isnslog(LOG_DEBUG, "load_config", "Getting scf scope failed.");
                goto out;
        }

        /* get the service "network/isns_server" within the scope */
        if (scf_scope_get_service(sc, ISNS_SERVER_SVC_NAME, svc) == -1) {
                isnslog(LOG_DEBUG, "load_config", "Getting %s service failed.",
                    ISNS_SERVER_SVC_NAME);
                goto out;
        }

        /* get the property group "config" within the given service */
        if (scf_service_get_pg(svc, ISNS_SERVER_CONFIG, pg) == -1) {
                isnslog(LOG_DEBUG, "load_config",
                    "Getting property group %s failed.",
                    ISNS_SERVER_CONFIG);
                goto out;
        }

        /*
         * Now get the properties.
         */
        if (scf_pg_get_property(pg, CONFIG_ESI_THRESHOLD, prop) == -1) {
                isnslog(LOG_DEBUG, "load_config", "Getting property %s failed",
                    CONFIG_ESI_THRESHOLD);
                goto out;
        }

        if (scf_property_get_value(prop, value) == -1) {
                isnslog(LOG_DEBUG, "load_config",
                    "Getting property value for %s failed.",
                    CONFIG_ESI_THRESHOLD);
                goto out;
        }

        if (scf_value_get_count(value, &esi_threshold) == -1) {
                isnslog(LOG_DEBUG, "load_config",
                    "Getting property integer value for %s failed.",
                    CONFIG_ESI_THRESHOLD);
                        goto out;
        }

        /* the range of ESI Threshold is [1, 10] */
        if (esi_threshold < 1) {
                esi_threshold = DEFAULT_ESI_THRESHOLD; /* 3 */
        } else if (esi_threshold > MAX_ESI_THRESHOLD) {
                esi_threshold = MAX_ESI_THRESHOLD; /* 10 */
        }

        isnslog(LOG_DEBUG, "load_config",
            "%s set to %d", CONFIG_ESI_THRESHOLD, esi_threshold);

        if (scf_pg_get_property(pg, CONFIG_MGMT_SCN, prop) == -1) {
                isnslog(LOG_DEBUG, "load_config",
                    "Getting scf property %s failed.", CONFIG_MGMT_SCN);
                        goto out;
        }

        if (scf_property_get_value(prop, value) == -1) {
                isnslog(LOG_DEBUG, "load_config",
                    "Getting property value for %s failed.",
                    CONFIG_MGMT_SCN);
                goto out;
        }

        if (scf_value_get_boolean(value, &mgmt_scn) == -1) {
                isnslog(LOG_DEBUG, "load_config",
                    "Getting boolean value for property %s failed",
                    CONFIG_MGMT_SCN);
                goto out;
        }
        isnslog(LOG_DEBUG, "load_config",
            "%s set to %s", CONFIG_MGMT_SCN,
            mgmt_scn ? "true" : "false");

        if (DATA_STORE_UPDATE) {
            if (scf_pg_get_property(pg, CONFIG_DATA_STORE, prop) == -1) {
                isnslog(LOG_DEBUG, "load_config", "Getting property %s failed",
                    CONFIG_DATA_STORE);
                goto out;
            }

            if (scf_property_get_value(prop, value) == -1) {
                isnslog(LOG_DEBUG, "load_config",
                    "Getting property value for %s failed",
                    CONFIG_DATA_STORE);
                goto out;
            }

            data_store[0] = 0;
            if (scf_value_get_astring(value, data_store, MAXPATHLEN) == -1) {
                isnslog(LOG_DEBUG, "load_config",
                    "Getting property string value for %s failed",
                    CONFIG_DATA_STORE);
                goto out;
            }
            isnslog(LOG_DEBUG, "load_config",
                "%s set to %s", CONFIG_DATA_STORE, data_store);
        }

        if (scf_pg_get_property(pg, CONFIG_CONTROL_NODES, prop) == -1) {
                isnslog(LOG_DEBUG, "load_config", "Getting property %s failed",
                    CONFIG_CONTROL_NODES);
                goto out;
        }

        if (scf_iter_property_values(value_iter, prop) == -1) {
                isnslog(LOG_DEBUG, "load_config",
                    "Getting iteration property %s failed",
                    CONFIG_CONTROL_NODES);
                goto out;
        }

        /* remove any old control node first. */
        (void) pthread_mutex_lock(&ctrl_node_mtx);
        while (control_nodes != NULL) {
            ctrl_node_p = control_nodes->next;
            free(control_nodes->name);
            free(control_nodes);
            control_nodes = ctrl_node_p;
        }

        while (scf_iter_next_value(value_iter, value) != 0) {
                if (scf_value_get_ustring(value, scf_name, MAXNAMELEN) == -1) {
                        isnslog(LOG_DEBUG, "load_config",
                            "Getting property string value for %s failed",
                            CONFIG_CONTROL_NODES);
                        (void) pthread_mutex_unlock(&ctrl_node_mtx);
                        goto out;
                }
                ctrl_node_p = (ctrl_node_t *)malloc(sizeof (ctrl_node_t));
                if (ctrl_node_p == NULL) {
                    isnslog(LOG_DEBUG, "load_config", "malloc() failed.");
                    (void) pthread_mutex_unlock(&ctrl_node_mtx);
                    goto out;
                }
                if (strlen(scf_name) != 0) {
                    name = (char *)malloc(strlen(scf_name) + 1);
                    if (name == NULL) {
                        free(ctrl_node_p);
                        isnslog(LOG_DEBUG, "load_config", "malloc() failed.");
                        (void) pthread_mutex_unlock(&ctrl_node_mtx);
                        goto out;
                    } else {
                        (void) strcpy(name, scf_name);
                        ctrl_node_p->name = (uchar_t *)name;
                        ctrl_node_p->next = control_nodes;
                        control_nodes = ctrl_node_p;
                    }
                    isnslog(LOG_DEBUG, "load_config",
                        "%s set to %s", CONFIG_CONTROL_NODES, scf_name);
                } else {
                    free(ctrl_node_p);
                }
        }
        (void) pthread_mutex_unlock(&ctrl_node_mtx);

        isnslog(LOG_DEBUG, "load_config", "loading server settings ok.");

        retval = 0; /* ok */

out:
        /* destroy scf pointers */
        if (value != NULL) {
                scf_value_destroy(value);
        }
        if (value_iter != NULL) {
                scf_iter_destroy(value_iter);
        }
        if (prop != NULL) {
                scf_property_destroy(prop);
        }
        if (pg != NULL) {
                scf_pg_destroy(pg);
        }
        if (svc != NULL) {
                scf_service_destroy(svc);
        }
        if (sc != NULL) {
                scf_scope_destroy(sc);
        }
        if (handle != NULL) {
                scf_handle_destroy(handle);
        }

        return (retval);
}

/*
 * is_control_node checks the given name to see if it is a control node.
 */
int
is_control_node(
        uchar_t *name
)
{
        ctrl_node_t *p;

        (void) pthread_mutex_lock(&ctrl_node_mtx);
        p = control_nodes;
        while (p != NULL) {
                if (strcmp((char *)p->name, (char *)name) == 0) {
                    (void) pthread_mutex_unlock(&ctrl_node_mtx);
                    return (1);
                }
                p = p->next;
        }
        (void) pthread_mutex_unlock(&ctrl_node_mtx);

        return (0);
}