OpenSolaris_b135/lib/lvm/libmeta/common/meta_med.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Just in case we're not in a build environment, make sure that
 * TEXT_DOMAIN gets set to something.
 */
#if !defined(TEXT_DOMAIN)
#define	TEXT_DOMAIN "SYS_TEST"
#endif

/*
 * Mediator functions
 */

#include <meta.h>
#include <metamed.h>
#include <dlfcn.h>
#include <sdssc.h>

/*
 * There are too many external factors that affect the timing of the
 * operations, so we set the timeout to a very large value, in this
 * case 1 day, which should handle HW timeouts, large configurations,
 * and other potential delays.
 */
#define	CL_LONG_TMO	86400L			/* 1 day */
#define	CL_MEDIUM_TMO	3600L			/* 1 hour */
#define	CL_SHORT_TMO	600L			/* 10 minutes */
#define	CL_DEF_TMO	10L			/* 10 seconds */

static	md_timeval32_t def_rpcb_timeout =  { MD_CLNT_CREATE_TOUT, 0 };

/*
 * RPC handle
 */
typedef struct {
	char	*hostname;
	CLIENT	*clntp;
} med_handle_t;

/*
 * Data to be sent from med_clnt_create_timed to med_create_helper via
 * meta_client_create_retry.
 */
typedef struct {
	rpcprog_t	mcd_program;	/* RPC program designation */
	rpcvers_t	mcd_version;	/* RPC version */
	char		*mcd_nettype;	/* Type of network to use for RPC */
} med_create_data_t;

/*
 * Perform the work of actually doing the clnt_create for
 * meta_client_create_retry.
 */
static CLIENT *
med_create_helper(char *hostname, void *private, struct timeval *time_out)
{
	med_create_data_t	*cd = (med_create_data_t *)private;

	return (clnt_create_timed(hostname, cd->mcd_program, cd->mcd_version,
	    cd->mcd_nettype, time_out));
}

static
CLIENT *med_clnt_create_timed(
	char *hostname,
	const ulong_t prog,
	const ulong_t vers,
	char *nettype,
	const md_timeval32_t *tp
)
{
	med_create_data_t	cd;	/* Create data. */

	cd.mcd_program = prog;
	cd.mcd_version = vers;
	cd.mcd_nettype = nettype;
	return (meta_client_create_retry(hostname, med_create_helper,
	    (void *)&cd, (time_t)tp->tv_sec, NULL));
}

/*
 * Set the timeout value for this client handle.
 */
static int
cl_sto_medd(
	CLIENT		*clntp,
	char		*hostname,
	long		time_out,
	md_error_t	*ep
)
{
	md_timeval32_t	nto;

	(void) memset(&nto, '\0', sizeof (nto));

	nto.tv_sec = time_out;

	if (clnt_control(clntp, CLSET_TIMEOUT, (char *)&nto) != TRUE)
		return (mdrpcerror(ep, clntp, hostname,
		    dgettext(TEXT_DOMAIN, "metad client set timeout")));

	return (0);
}

/*
 * close RPC connection
 */
static void
close_medd(
	med_handle_t	*hp
)
{
	assert(hp != NULL);
	if (hp->hostname != NULL) {
		Free(hp->hostname);
	}
	if (hp->clntp != NULL) {
		auth_destroy(hp->clntp->cl_auth);
		clnt_destroy(hp->clntp);
	}
	Free(hp);
}

/*
 * open RPC connection to rpc.medd
 */
static med_handle_t *
open_medd(
	char		*hostname,
	long		time_out,
	md_error_t	*ep
)
{
	CLIENT		*clntp;
	med_handle_t	*hp;

	/* default to local host */
	if ((hostname == NULL) || (*hostname == '\0'))
		hostname = mynode();

	/* open RPC connection */
	assert(hostname != NULL);
	if ((clntp = med_clnt_create_timed(hostname, MED_PROG, MED_VERS,
	    "tcp", &def_rpcb_timeout)) == NULL) {
		if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
			clnt_pcreateerror(hostname);
		(void) mdrpccreateerror(ep, hostname,
		    "medd med_clnt_create_timed");
		return (NULL);
	} else {
		auth_destroy(clntp->cl_auth);
		clntp->cl_auth = authsys_create_default();
		assert(clntp->cl_auth != NULL);
	}

	if (cl_sto_medd(clntp, hostname, time_out, ep) != 0)
		return (NULL);

	/* return connection */
	hp = Zalloc(sizeof (*hp));
	hp->hostname = Strdup(hostname);
	hp->clntp = clntp;

	return (hp);
}

/*
 * steal and convert med_err_t
 */
int
meddstealerror(
	md_error_t	*ep,
	med_err_t	*medep
)
{
	char		buf[BUFSIZ];
	char		*p = buf;
	size_t		psize = BUFSIZ;
	char		*emsg;
	int		rval = -1;

	/* no error */
	if (medep->med_errno == 0) {
		/* assert(medep->name == NULL); */
		rval = 0;
		goto out;
	}

	/* steal error */
	if ((medep->med_node != NULL) && (medep->med_node[0] != '\0')) {
		(void) snprintf(p, psize, "%s: ", medep->med_node);
		p = &buf[strlen(buf)];
		psize = buf + BUFSIZ - p;
	}

	if ((medep->med_misc != NULL) && (medep->med_misc[0] != '\0')) {
		(void) snprintf(p, psize, "%s: ", medep->med_misc);
		p = &buf[strlen(buf)];
		psize = buf + BUFSIZ - p;
	}

	if (medep->med_errno < 0) {
		if ((emsg = med_errnum_to_str(medep->med_errno)) != NULL)
			(void) snprintf(p, psize, "%s", emsg);
		else
			(void) snprintf(p, psize, dgettext(TEXT_DOMAIN,
			    "unknown mediator errno %d\n"), medep->med_errno);
	} else {
		if ((emsg = strerror(medep->med_errno)) != NULL)
			(void) snprintf(p, psize, "%s", emsg);
		else
			(void) snprintf(p, psize, dgettext(TEXT_DOMAIN,
			    "errno %d out of range"), medep->med_errno);
	}
	(void) mderror(ep, MDE_MED_ERROR, buf);

	/* cleanup, return success */
out:
	if (medep->med_node != NULL)
		Free(medep->med_node);
	if (medep->med_misc != NULL)
		Free(medep->med_misc);
	(void) memset(medep, 0, sizeof (*medep));
	return (rval);
}

static med_handle_t *
open_medd_wrap(
	md_h_t		*mdhp,
	long		time_out,
	md_error_t	*ep
)
{
	med_handle_t		*hp = NULL;
	int			i;
	char    		*hnm;

	assert(mdhp && mdhp->a_cnt > 0);

	/* Loop through the hosts listed */
	i = min(mdhp->a_cnt, MAX_HOST_ADDRS) - 1;
	for (; i >= 0; i--) {
		hnm = mdhp->a_nm[i];

		if ((hp = open_medd(hnm, time_out, ep)) == NULL) {
			if (mdanyrpcerror(ep) && i != 0) {
				mdclrerror(ep);
				continue;
			}
		}
		return (hp);
	}

	rpc_createerr.cf_stat = RPC_CANTSEND;
	rpc_createerr.cf_error.re_status = 0;
	(void) mdrpccreateerror(ep, mdhp->a_nm[0],
	    dgettext(TEXT_DOMAIN, "medd open wrap"));

	return (NULL);
}

static int
setup_med_transtab(md_error_t *ep)
{
	mddb_med_t_parm_t	*tp = NULL;
	struct	stat		statb;
	int			i;
	size_t			alloc_size = 0;
	int			err = 0;


	if ((tp = Zalloc(sizeof (mddb_med_t_parm_t))) == NULL)
		return (mdsyserror(ep, ENOMEM, "setup_med_transtab"));

	if (metaioctl(MD_MED_GET_TLEN, tp, &tp->med_tp_mde, NULL) != 0) {
		err = mdstealerror(ep, &tp->med_tp_mde);
		goto out;
	}

	if (tp->med_tp_setup == 1)
		goto out;

	alloc_size = (sizeof (mddb_med_t_parm_t) - sizeof (mddb_med_t_ent_t)) +
	    (sizeof (mddb_med_t_ent_t) * tp->med_tp_nents);

	if ((tp = Realloc(tp, alloc_size)) == NULL) {
		err = mdsyserror(ep, ENOMEM, "setup_med_transtab");
		goto out;
	}

	if (metaioctl(MD_MED_GET_T, tp, &tp->med_tp_mde, NULL) != 0) {
		err = mdstealerror(ep, &tp->med_tp_mde);
		goto out;
	}

	for (i = 0; i < tp->med_tp_nents; i++) {
		if (meta_stat(tp->med_tp_ents[i].med_te_nm, &statb) == -1) {
			md_perror("setup_med_transtab(): stat():");
			tp->med_tp_ents[i].med_te_dev = NODEV64;
		} else {
			tp->med_tp_ents[i].med_te_dev =
			    meta_expldev(statb.st_rdev);
		}
	}

	if (metaioctl(MD_MED_SET_T, tp, &tp->med_tp_mde, NULL) != 0)
		err = mdstealerror(ep, &tp->med_tp_mde);

out:
	Free(tp);
	return (err);
}

/*
 * Externals
 */

/*
 * NULLPROC - just returns a response
 */
int
clnt_med_null(
	char			*hostname,
	md_error_t		*ep
)
{
	med_handle_t		*hp;
	med_err_t		res;

	/* initialize */
	mdclrerror(ep);

	/* do it */
	if ((hp = open_medd(hostname, CL_DEF_TMO, ep)) == NULL)
		return (-1);

	if (med_null_1(NULL, &res, hp->clntp) != RPC_SUCCESS)
		(void) mdrpcerror(ep, hp->clntp, hostname,
		    dgettext(TEXT_DOMAIN, "medd nullproc"));

	close_medd(hp);

	xdr_free(xdr_med_err_t, (char *)&res);

	if (! mdisok(ep))
		return (-1);

	return (0);
}

/*
 * Update the mediator information on the mediator.
 * This function does the same functionality as
 * clnt_med_upd_data() except that it takes different
 * argument so that host which is just a mediator, can
 * still update its mediator record.
 */
int
clnt_user_med_upd_data(
	md_h_t	*mdhp,
	bool_t	obandiskset,
	char	*setname,
	uint_t	setnum,
	med_data_t	*meddp,
	md_error_t	*ep
)
{
	med_handle_t    	*hp;
	med_upd_data_args_t	args;
	med_err_t		res;

	/* Initialize */
	mdclrerror(ep);
	(void) memset(&args, 0, sizeof (args));
	(void) memset(&res, 0, sizeof (res));

	/* Build args */
	if (obandiskset)
		args.med.med_caller = Strdup(MED_MN_CALLER);
	else
		args.med.med_caller = Strdup(mynode());

	args.med.med_setname = Strdup(setname);
	args.med.med_setno = setnum;
	args.med_data = *meddp;

	if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
		return (-1);

	if (med_upd_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
		(void) mdrpcerror(ep, hp->clntp, hp->hostname,
		    dgettext(TEXT_DOMAIN, "medd get record"));
	else
		(void) meddstealerror(ep, &res);

	close_medd(hp);

	xdr_free(xdr_med_upd_data_args_t, (char *)&args);
	xdr_free(xdr_med_err_t, (char *)&res);

	if (! mdisok(ep))
		return (-1);

	return (0);
}

/*
 * Get the mediator information from the client.
 * The code does same functinality as clnt_med_get_data()
 * except that it takes different arguments so that
 * host which doesn't have set information, can still
 * get access to mediator information
 */
int
clnt_user_med_get_data(
	md_h_t	*mdhp,
	bool_t	obandiskset,
	char	*setname,
	uint_t	setnum,
	med_data_t	*meddp,
	md_error_t	*ep
)
{
	int			rval = -1;
	med_handle_t		*hp;
	med_args_t		args;
	med_get_data_res_t	res;

	/* Initialize */
	mdclrerror(ep);
	(void) memset(&args, 0, sizeof (args));
	(void) memset(&res, 0, sizeof (res));

	/* Build args */
	if (obandiskset)
		args.med.med_caller = Strdup(MED_MN_CALLER);
	else
		args.med.med_caller = Strdup(mynode());

	args.med.med_setname = Strdup(setname);
	args.med.med_setno = setnum;

	if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
		return (-1);

	if (med_get_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
		(void) mdrpcerror(ep, hp->clntp, hp->hostname,
		    dgettext(TEXT_DOMAIN, "medd get record"));
	else
		(void) meddstealerror(ep, &res.med_status);

	close_medd(hp);

	if (mdisok(ep)) {
		/* copy the mediator data in meddp */
		(void) memmove(meddp, &res.med_data, sizeof (med_data_t));
		rval = 0;
	}

	xdr_free(xdr_med_args_t, (char *)&args);
	xdr_free(xdr_med_get_data_res_t, (char *)&res);

	return (rval);
}


/*
 * Update the mediator information on the mediator.
 * *** This is not normally called from user code, the kernel does this! ***
 */
int
clnt_med_upd_data(
	md_h_t			*mdhp,
	mdsetname_t		*sp,
	med_data_t		*meddp,
	md_error_t		*ep
)
{
	med_handle_t		*hp;
	med_upd_data_args_t	args;
	med_err_t		res;
	md_set_desc		*sd;

	/* initialize */
	mdclrerror(ep);
	(void) memset(&args, 0, sizeof (args));
	(void) memset(&res, 0, sizeof (res));

	/* build args */
	if ((sd = metaget_setdesc(sp, ep)) == NULL)
		return (-1);

	if (MD_MNSET_DESC(sd))
		/*
		 * In the MN diskset, use a generic nodename, multiowner, as
		 * the node initiating the RPC request.  This allows
		 * any node to access mediator information.
		 *
		 * MN diskset reconfig cycle forces consistent
		 * view of set/node/drive/mediator information across all nodes
		 * in the MN diskset.  This allows the relaxation of
		 * node name checking in rpc.metamedd for MN disksets.
		 *
		 * In the traditional diskset, only a calling node that is
		 * in the mediator record's diskset nodelist can access
		 * mediator data.
		 */
		args.med.med_caller = Strdup(MED_MN_CALLER);
	else
		args.med.med_caller = Strdup(mynode());
	args.med.med_setname = Strdup(sp->setname);
	args.med.med_setno = sp->setno;
	args.med_data = *meddp;

	/* do it */
	if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
		return (-1);

	if (med_upd_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
		(void) mdrpcerror(ep, hp->clntp, hp->hostname,
		    dgettext(TEXT_DOMAIN, "medd update data"));
	else
		(void) meddstealerror(ep, &res);

	close_medd(hp);

	xdr_free(xdr_med_upd_data_args_t, (char *)&args);
	xdr_free(xdr_med_err_t, (char *)&res);

	if (! mdisok(ep))
		return (-1);

	return (0);
}

/*
 * Get the mediator data for this client from the mediator
 */
int
clnt_med_get_data(
	md_h_t			*mdhp,
	mdsetname_t		*sp,
	med_data_t		*meddp,
	md_error_t		*ep
)
{
	med_handle_t		*hp;
	med_args_t		args;
	med_get_data_res_t	res;
	int			rval = -1;
	md_set_desc		*sd;

	/* initialize */
	mdclrerror(ep);
	(void) memset(&args, 0, sizeof (args));
	(void) memset(&res, 0, sizeof (res));

	/* build args */
	if ((sd = metaget_setdesc(sp, ep)) == NULL)
		return (-1);

	if (MD_MNSET_DESC(sd))
		/*
		 * In the MN diskset, use a generic nodename, multiowner, as
		 * the node initiating the RPC request.  This allows
		 * any node to access mediator information.
		 *
		 * MN diskset reconfig cycle forces consistent
		 * view of set/node/drive/mediator information across all nodes
		 * in the MN diskset.  This allows the relaxation of
		 * node name checking in rpc.metamedd for MN disksets.
		 *
		 * In the traditional diskset, only a calling node that is
		 * in the mediator record's diskset nodelist can access
		 * mediator data.
		 */
		args.med.med_caller = Strdup(MED_MN_CALLER);
	else
		args.med.med_caller = Strdup(mynode());
	args.med.med_setname = Strdup(sp->setname);
	args.med.med_setno = sp->setno;

	/* do it */
	if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
		return (-1);

	if (med_get_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
		(void) mdrpcerror(ep, hp->clntp, hp->hostname,
		    dgettext(TEXT_DOMAIN, "medd get data"));
	else
		(void) meddstealerror(ep, &res.med_status);

	close_medd(hp);

	if (mdisok(ep)) {
		/* do something with the results */
		(void) memmove(meddp, &res.med_data, sizeof (med_data_t));
		rval = 0;
	}

	xdr_free(xdr_med_args_t, (char *)&args);
	xdr_free(xdr_med_get_data_res_t, (char *)&res);

	return (rval);
}

/*
 * Update the mediator record on the mediator.
 */
int
clnt_med_upd_rec(
	md_h_t			*mdhp,
	mdsetname_t		*sp,
	med_rec_t		*medrp,
	md_error_t		*ep
)
{
	med_handle_t		*hp;
	med_upd_rec_args_t	args;
	med_err_t		res;
	md_set_desc		*sd;

	/* initialize */
	mdclrerror(ep);
	(void) memset(&args, 0, sizeof (args));
	(void) memset(&res, 0, sizeof (res));

	/* build args */
	if ((sd = metaget_setdesc(sp, ep)) == NULL)
		return (-1);

	if (MD_MNSET_DESC(sd))
		/*
		 * In the MN diskset, use a generic nodename, multiowner, as
		 * the node initiating the RPC request.  This allows
		 * any node to access mediator information.
		 *
		 * MN diskset reconfig cycle forces consistent
		 * view of set/node/drive/mediator information across all nodes
		 * in the MN diskset.  This allows the relaxation of
		 * node name checking in rpc.metamedd for MN disksets.
		 *
		 * In the traditional diskset, only a calling node that is
		 * in the mediator record's diskset nodelist can access
		 * mediator data.
		 */
		args.med.med_caller = Strdup(MED_MN_CALLER);
	else
		args.med.med_caller = Strdup(mynode());
	args.med.med_setname = Strdup(sp->setname);
	args.med.med_setno = sp->setno;
	args.med_flags = 0;
	args.med_rec = *medrp;			/* structure assignment */

	/* do it */
	if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
		return (-1);

	if (med_upd_rec_1(&args, &res, hp->clntp) != RPC_SUCCESS)
		(void) mdrpcerror(ep, hp->clntp, hp->hostname,
		    dgettext(TEXT_DOMAIN, "medd update record"));
	else
		(void) meddstealerror(ep, &res);

	close_medd(hp);

	xdr_free(xdr_med_upd_rec_args_t, (char *)&args);
	xdr_free(xdr_med_err_t, (char *)&res);

	if (! mdisok(ep))
		return (-1);

	return (0);
}

/*
 * Get the mediator record for this client from the mediator
 */
int
clnt_med_get_rec(
	md_h_t			*mdhp,
	mdsetname_t		*sp,
	med_rec_t		*medrp,
	md_error_t		*ep
)
{
	med_handle_t		*hp;
	med_args_t		args;
	med_get_rec_res_t	res;
	int			rval = -1;
	md_set_desc		*sd;

	/* initialize */
	mdclrerror(ep);
	(void) memset(&args, 0, sizeof (args));
	(void) memset(&res, 0, sizeof (res));

	/* build args */
	if ((sd = metaget_setdesc(sp, ep)) == NULL)
		return (-1);

	if (MD_MNSET_DESC(sd))
		/*
		 * In the MN diskset, use a generic nodename, multiowner, as
		 * the node initiating the RPC request.  This allows
		 * any node to access mediator information.
		 *
		 * MN diskset reconfig cycle forces consistent
		 * view of set/node/drive/mediator information across all nodes
		 * in the MN diskset.  This allows the relaxation of
		 * node name checking in rpc.metamedd for MN disksets.
		 *
		 * In the traditional diskset, only a calling node that is
		 * in the mediator record's diskset nodelist can access
		 * mediator data.
		 */
		args.med.med_caller = Strdup(MED_MN_CALLER);
	else
		args.med.med_caller = Strdup(mynode());
	args.med.med_setname = Strdup(sp->setname);
	args.med.med_setno = sp->setno;

	/* do it */
	if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
		return (-1);

	if (med_get_rec_1(&args, &res, hp->clntp) != RPC_SUCCESS)
		(void) mdrpcerror(ep, hp->clntp, hp->hostname,
		    dgettext(TEXT_DOMAIN, "medd get record"));
	else
		(void) meddstealerror(ep, &res.med_status);

	close_medd(hp);

	if (mdisok(ep)) {
		/* do something with the results */
		(void) memmove(medrp, &res.med_rec, sizeof (med_rec_t));
		rval = 0;
	}

	xdr_free(xdr_med_args_t, (char *)&args);
	xdr_free(xdr_med_get_rec_res_t, (char *)&res);

	return (rval);
}

/*
 * Get the name of the host from the mediator daemon.
 */
int
clnt_med_hostname(
	char			*hostname,
	char			**ret_hostname,
	md_error_t		*ep
)
{
	med_handle_t		*hp;
	med_hnm_res_t		res;
	int			rval = -1;

	/* initialize */
	mdclrerror(ep);
	(void) memset(&res, 0, sizeof (res));

	/* No args */

	/* do it */
	if ((hp = open_medd(hostname, CL_DEF_TMO, ep)) == NULL)
		return (-1);

	if (med_hostname_1(NULL, &res, hp->clntp) != RPC_SUCCESS)
		(void) mdrpcerror(ep, hp->clntp, hostname,
		    dgettext(TEXT_DOMAIN, "medd hostname"));
	else
		(void) meddstealerror(ep, &res.med_status);

	close_medd(hp);

	if (mdisok(ep)) {
		/* do something with the results */
		rval = 0;

		if (ret_hostname != NULL)
			*ret_hostname = Strdup(res.med_hnm);
	}

	xdr_free(xdr_med_hnm_res_t, (char *)&res);

	return (rval);
}

int
meta_med_hnm2ip(md_hi_arr_t *mp, md_error_t *ep)
{
	int		i, j;
	int		max_meds;

	if ((max_meds = get_max_meds(ep)) == 0)
		return (-1);

	for (i = 0; i < max_meds; i++) {
		mp->n_lst[i].a_flg = 0;
		/* See if this is the local host */
		if (mp->n_lst[i].a_cnt > 0 &&
		    strcmp(mp->n_lst[i].a_nm[0], mynode()) == NULL)
			mp->n_lst[i].a_flg |= NMIP_F_LOCAL;

		for (j = 0; j < mp->n_lst[i].a_cnt; j++) {
			struct hostent	*hp;
			char		*hnm = mp->n_lst[i].a_nm[j];

			/*
			 * Cluster nodename support
			 *
			 * See if the clustering code can give us an IP addr
			 * for the stored name. If not, find it the old way
			 * which will use the public interface.
			 */
			if (sdssc_get_priv_ipaddr(mp->n_lst[i].a_nm[j],
			    (struct in_addr *)&mp->n_lst[i].a_ip[j]) !=
			    SDSSC_OKAY) {
				if ((hp = gethostbyname(hnm)) == NULL)
					return (mdsyserror(ep, EADDRNOTAVAIL,
					    hnm));

				/* We only do INET addresses */
				if (hp->h_addrtype != AF_INET)
					return (mdsyserror(ep, EPFNOSUPPORT,
					    hnm));

				/* We take the first address only */
				if (*hp->h_addr_list) {
					(void) memmove(&mp->n_lst[i].a_ip[j],
					    *hp->h_addr_list,
					    sizeof (struct in_addr));
				} else
					return (mdsyserror(ep, EADDRNOTAVAIL,
					    hnm));
			}

		}
	}
	return (0);
}

int
meta_h2hi(md_h_arr_t *mdhp, md_hi_arr_t *mdhip, md_error_t *ep)
{
	int			i, j;
	int			max_meds;

	if ((max_meds = get_max_meds(ep)) == 0)
		return (-1);

	mdhip->n_cnt = mdhp->n_cnt;

	for (i = 0; i < max_meds; i++) {
		mdhip->n_lst[i].a_flg = 0;
		mdhip->n_lst[i].a_cnt = mdhp->n_lst[i].a_cnt;
		if (mdhp->n_lst[i].a_cnt == 0)
			continue;
		for (j = 0; j < mdhp->n_lst[i].a_cnt; j++)
			(void) strcpy(mdhip->n_lst[i].a_nm[j],
			    mdhp->n_lst[i].a_nm[j]);
	}
	return (0);
}

int
meta_hi2h(md_hi_arr_t *mdhip, md_h_arr_t *mdhp, md_error_t *ep)
{
	int			i, j;
	int			max_meds;

	if ((max_meds = get_max_meds(ep)) == 0)
		return (-1);

	mdhp->n_cnt = mdhip->n_cnt;
	for (i = 0; i < max_meds; i++) {
		mdhp->n_lst[i].a_cnt = mdhip->n_lst[i].a_cnt;
		if (mdhip->n_lst[i].a_cnt == 0)
			continue;
		for (j = 0; j < mdhip->n_lst[i].a_cnt; j++)
			(void) strcpy(mdhp->n_lst[i].a_nm[j],
			    mdhip->n_lst[i].a_nm[j]);
	}
	return (0);
}

int
setup_med_cfg(
	mdsetname_t		*sp,
	mddb_config_t		*cp,
	int			force,
	md_error_t		*ep
)
{
	md_set_desc		*sd;
	int			i;
	int			max_meds;

	if (metaislocalset(sp))
		return (0);

	if ((sd = metaget_setdesc(sp, ep)) == NULL)
		return (-1);

	if (setup_med_transtab(ep))
		return (-1);

	if (meta_h2hi(&sd->sd_med, &cp->c_med, ep))
		return (-1);

	/* Make sure the ip addresses are current */
	if (meta_med_hnm2ip(&cp->c_med, ep))
		return (-1);

	if (force)
		return (0);

	if ((max_meds = get_max_meds(ep)) == 0)
		return (-1);

	/* Make sure metamedd still running on host - only chk nodename */
	for (i = 0; i < max_meds; i++) {
		char		*hostname;
		char		*hnm;

		if (sd->sd_med.n_lst[i].a_cnt == 0)
			continue;

		hnm = sd->sd_med.n_lst[i].a_nm[0];

		if (clnt_med_hostname(hnm, &hostname, ep))
			return (mddserror(ep, MDE_DS_NOMEDONHOST, sp->setno,
			    hnm, NULL, sp->setname));
		Free(hostname);
	}
	return (0);
}

/*
 * This is a general routine to get mediator information from
 * file /etc/lvm/meddb. Commands medstat and metainit use this
 * routine to get mediator information from all mediator hosts or update
 * its mediator record respectively.
 */
int
meta_mediator_info_from_file(char *sname, int verbose, md_error_t *ep)
{
	uint_t		c;
	int		i;
	int		j;
	int		fd;
	int		rec_size;
	char		*setname;
	uint_t		setnum;
	med_rec_t	*rec_buf = NULL;
	med_db_hdr_t	*dbhbr;
	med_rec_t	*medrecp;
	med_data_t	medd;
	med_data_t	save_medd;
	md_h_t		mdh;
	uint_t		latest_med_dat_cc = 0;
	int		retval = 0;
	int		medok = 0;
	int		golden = 0;
	bool_t		obandiskset;
	int		isSetFound = 0;

	/* Open the meddb file */
	if ((fd = open(MED_DB_FILE, O_RDONLY, 0)) == -1) {

		/*
		 * During the start up of the SVM services, this function
		 * will be called with an empty sname. In that case it is
		 * entirely possible for the MED_DB_FILE not to exist.
		 * If so, then no need to report an error.
		 */
		if (sname != NULL) {
			(void) mdsyserror(ep, errno, MED_DB_FILE);
			mde_perror(ep, dgettext(TEXT_DOMAIN,
			    "Error in opening meddb file"));
			return (1);
		}
		return (0);
	}

	/* Initialize rec_size */
	rec_size = roundup(sizeof (med_rec_t), DEV_BSIZE);

	/* Allocate a record buffer */
	if ((rec_buf = malloc(rec_size)) == NULL) {
		(void) mdsyserror(ep, errno, MED_DB_FILE);
		mde_perror(ep, dgettext(TEXT_DOMAIN,
		    "Error in allocating memory"));
		goto out;
	}

	/* read the file header */
	if ((read(fd, rec_buf, rec_size)) != rec_size) {
		(void) mdsyserror(ep, EINVAL, MED_DB_FILE);
		mde_perror(ep, dgettext(TEXT_DOMAIN,
		    "Error in reading mediator record"));
		goto out;
	}

	dbhbr = (med_db_hdr_t *)rec_buf;

	/* Number of records in the mediator file */
	c = dbhbr->med_dbh_nm;

	for (i = 0; i < c; i++) {
		(void) memset(rec_buf, 0, rec_size);

		if (read(fd, rec_buf, rec_size) == -1) {
			(void) mdsyserror(ep, errno, MED_DB_FILE);
			mde_perror(ep, dgettext(TEXT_DOMAIN,
			    "Error in reading mediator record"));
			goto out;
		}

		medrecp = (med_rec_t *)rec_buf;

		/*
		 * For oban diskset first entry in the rec_nodes field is
		 * "multiowner" and all other entries are empty.
		 * Check if this is really multiowner diskset.
		 */

		if ((strcmp(medrecp->med_rec_nodes[0], MED_MN_CALLER) == 0) &&
		    (medrecp->med_rec_nodes[1][0] == '\0'))
			obandiskset = TRUE;
		else
			obandiskset = FALSE;

		if (sname != NULL) {
			/*
			 * Continue if the set name is not in our interest.
			 * This is required when this routine is called
			 * from medstat
			 */

			if (strcmp(sname, medrecp->med_rec_snm) != 0) {
				continue;
			}

			if (verbose)
				(void) printf("%8.8s\t\t%6.6s\t%6.6s\n",
				    gettext("Mediator"), gettext("Status"),
				    gettext("Golden"));

			isSetFound = 1;
			setname = sname;
		} else {
			setname = medrecp->med_rec_snm;
		}
		setnum = medrecp->med_rec_sn;
		(void) memset(&medd, '\0', sizeof (medd));
		(void) memset(&mdh, '\0', sizeof (mdh));
		(void) memset(&save_medd, '\0', sizeof (save_medd));
		latest_med_dat_cc = 0;

		for (j = 0; j < MED_MAX_HOSTS; j++) {
			/*
			 * It is possible for the n_lst[j] slot to be empty
			 * if the mediator node has already been removed so
			 * go to the next slot.
			 */
			if (medrecp->med_rec_meds.n_lst[j].a_cnt == 0)
				continue;
			mdh = medrecp->med_rec_meds.n_lst[j];

			if ((sname != NULL) && (verbose))
				(void) printf("%-17.17s\t",
				    medrecp->med_rec_meds.n_lst[j].a_nm[0]);

			if (clnt_user_med_get_data(&mdh, obandiskset,
			    setname, setnum, &medd, ep) == -1) {
				if (sname == NULL) {
					continue;
				} else {
					if (mdanyrpcerror(ep)) {
						if (verbose)
							(void) printf("%s\n",
							    gettext("Unreach"
							    "able"));
						continue;
					} else if (mdiserror(ep,
					    MDE_MED_ERROR)) {
						if (verbose)
							(void) printf("%s\n",
							    gettext("Bad"));
					} else {
						if (verbose)
							(void) printf("%s\n",
							    gettext("Fatal"));
					}
					mde_perror(ep, "");
					if (mdiserror(ep, MDE_MED_ERROR))
						continue;
					goto out;
				}
			} else {
				/*
				 * Make sure this node has the correct value
				 * for the mediator record. If not we want the
				 * highest value from the other nodes. Save it
				 * for updating once the loop through all the
				 * mediator nodes has completed.
				 */
				if (sname == NULL) {
					if (latest_med_dat_cc <
					    medd.med_dat_cc) {
						latest_med_dat_cc =
						    medd.med_dat_cc;
						(void) memcpy(&save_medd, &medd,
						    sizeof (medd));
					}
				} else {
					if (verbose)
						(void) printf("%s",
						    gettext("Ok"));
					if (medd.med_dat_fl & MED_DFL_GOLDEN) {
						if (verbose)
							(void) printf("\t%s",
							    gettext("Yes"));
						golden++;
					} else {
						if (verbose)
							(void) printf("\t%s",
							    gettext("No"));
					}
					if (verbose)
						(void) printf("\n");
						medok++;
				}
			}
		}
		if (sname == NULL) {

			/*
			 * Mediators only become active when there are
			 * replica updates to the sets and this can only
			 * occur when there is a disk in the set.
			 * If there are no disks found then the save_medd
			 * structure will be empty. If save_medd is empty,
			 * do not update the set.
			 */
			if (save_medd.med_dat_sn == 0)
				continue;
			/*
			 * Update the latest mediator information
			 * on this node
			 */
			(void) strlcpy(mdh.a_nm[0], mynode(),
			    sizeof (mdh.a_nm[0]));
			mdh.a_cnt = 1;
			if (clnt_user_med_upd_data(&mdh, obandiskset,
			    setname, setnum, &save_medd, ep) == -1) {
				/*
				 * We had some errors while updaing the
				 * record. This means this metaset is
				 * not updated with latest mediator
				 * information.
				 */
				mde_perror(ep, "");
			}

		} else {
			if (golden) {
				retval = 0;
				goto out;
			}
			if (medok < ((medrecp->med_rec_meds.n_cnt / 2) + 1))
				retval = 1;
		}
	}

out:
	if ((sname != NULL) && (isSetFound == 0)) {
		(void) mderror(ep, MDE_NO_SET, sname);
		mde_perror(ep, "");
		retval = 1;
	}
	if (rec_buf != NULL)
		Free(rec_buf);
	if (close(fd) < 0) {
		(void) mdsyserror(ep, errno, MED_DB_FILE);
		mde_perror(ep, dgettext(TEXT_DOMAIN,
		    "Error in closing meddb file"));
		return (1);
	}
	return (retval);
}