OpenSolaris_b135/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);
}