1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Just in case we're not in a build environment, make sure that
29 * TEXT_DOMAIN gets set to something.
30 */
31#if !defined(TEXT_DOMAIN)
32#define	TEXT_DOMAIN "SYS_TEST"
33#endif
34
35/*
36 * Mediator functions
37 */
38
39#include <meta.h>
40#include <metamed.h>
41#include <dlfcn.h>
42#include <sdssc.h>
43
44/*
45 * There are too many external factors that affect the timing of the
46 * operations, so we set the timeout to a very large value, in this
47 * case 1 day, which should handle HW timeouts, large configurations,
48 * and other potential delays.
49 */
50#define	CL_LONG_TMO	86400L			/* 1 day */
51#define	CL_MEDIUM_TMO	3600L			/* 1 hour */
52#define	CL_SHORT_TMO	600L			/* 10 minutes */
53#define	CL_DEF_TMO	10L			/* 10 seconds */
54
55static	md_timeval32_t def_rpcb_timeout =  { MD_CLNT_CREATE_TOUT, 0 };
56
57/*
58 * RPC handle
59 */
60typedef struct {
61	char	*hostname;
62	CLIENT	*clntp;
63} med_handle_t;
64
65/*
66 * Data to be sent from med_clnt_create_timed to med_create_helper via
67 * meta_client_create_retry.
68 */
69typedef struct {
70	rpcprog_t	mcd_program;	/* RPC program designation */
71	rpcvers_t	mcd_version;	/* RPC version */
72	char		*mcd_nettype;	/* Type of network to use for RPC */
73} med_create_data_t;
74
75/*
76 * Perform the work of actually doing the clnt_create for
77 * meta_client_create_retry.
78 */
79static CLIENT *
80med_create_helper(char *hostname, void *private, struct timeval *time_out)
81{
82	med_create_data_t	*cd = (med_create_data_t *)private;
83
84	return (clnt_create_timed(hostname, cd->mcd_program, cd->mcd_version,
85	    cd->mcd_nettype, time_out));
86}
87
88static
89CLIENT *med_clnt_create_timed(
90	char *hostname,
91	const ulong_t prog,
92	const ulong_t vers,
93	char *nettype,
94	const md_timeval32_t *tp
95)
96{
97	med_create_data_t	cd;	/* Create data. */
98
99	cd.mcd_program = prog;
100	cd.mcd_version = vers;
101	cd.mcd_nettype = nettype;
102	return (meta_client_create_retry(hostname, med_create_helper,
103	    (void *)&cd, (time_t)tp->tv_sec, NULL));
104}
105
106/*
107 * Set the timeout value for this client handle.
108 */
109static int
110cl_sto_medd(
111	CLIENT		*clntp,
112	char		*hostname,
113	long		time_out,
114	md_error_t	*ep
115)
116{
117	md_timeval32_t	nto;
118
119	(void) memset(&nto, '\0', sizeof (nto));
120
121	nto.tv_sec = time_out;
122
123	if (clnt_control(clntp, CLSET_TIMEOUT, (char *)&nto) != TRUE)
124		return (mdrpcerror(ep, clntp, hostname,
125		    dgettext(TEXT_DOMAIN, "metad client set timeout")));
126
127	return (0);
128}
129
130/*
131 * close RPC connection
132 */
133static void
134close_medd(
135	med_handle_t	*hp
136)
137{
138	assert(hp != NULL);
139	if (hp->hostname != NULL) {
140		Free(hp->hostname);
141	}
142	if (hp->clntp != NULL) {
143		auth_destroy(hp->clntp->cl_auth);
144		clnt_destroy(hp->clntp);
145	}
146	Free(hp);
147}
148
149/*
150 * open RPC connection to rpc.medd
151 */
152static med_handle_t *
153open_medd(
154	char		*hostname,
155	long		time_out,
156	md_error_t	*ep
157)
158{
159	CLIENT		*clntp;
160	med_handle_t	*hp;
161
162	/* default to local host */
163	if ((hostname == NULL) || (*hostname == '\0'))
164		hostname = mynode();
165
166	/* open RPC connection */
167	assert(hostname != NULL);
168	if ((clntp = med_clnt_create_timed(hostname, MED_PROG, MED_VERS,
169	    "tcp", &def_rpcb_timeout)) == NULL) {
170		if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
171			clnt_pcreateerror(hostname);
172		(void) mdrpccreateerror(ep, hostname,
173		    "medd med_clnt_create_timed");
174		return (NULL);
175	} else {
176		auth_destroy(clntp->cl_auth);
177		clntp->cl_auth = authsys_create_default();
178		assert(clntp->cl_auth != NULL);
179	}
180
181	if (cl_sto_medd(clntp, hostname, time_out, ep) != 0)
182		return (NULL);
183
184	/* return connection */
185	hp = Zalloc(sizeof (*hp));
186	hp->hostname = Strdup(hostname);
187	hp->clntp = clntp;
188
189	return (hp);
190}
191
192/*
193 * steal and convert med_err_t
194 */
195int
196meddstealerror(
197	md_error_t	*ep,
198	med_err_t	*medep
199)
200{
201	char		buf[BUFSIZ];
202	char		*p = buf;
203	size_t		psize = BUFSIZ;
204	char		*emsg;
205	int		rval = -1;
206
207	/* no error */
208	if (medep->med_errno == 0) {
209		/* assert(medep->name == NULL); */
210		rval = 0;
211		goto out;
212	}
213
214	/* steal error */
215	if ((medep->med_node != NULL) && (medep->med_node[0] != '\0')) {
216		(void) snprintf(p, psize, "%s: ", medep->med_node);
217		p = &buf[strlen(buf)];
218		psize = buf + BUFSIZ - p;
219	}
220
221	if ((medep->med_misc != NULL) && (medep->med_misc[0] != '\0')) {
222		(void) snprintf(p, psize, "%s: ", medep->med_misc);
223		p = &buf[strlen(buf)];
224		psize = buf + BUFSIZ - p;
225	}
226
227	if (medep->med_errno < 0) {
228		if ((emsg = med_errnum_to_str(medep->med_errno)) != NULL)
229			(void) snprintf(p, psize, "%s", emsg);
230		else
231			(void) snprintf(p, psize, dgettext(TEXT_DOMAIN,
232			    "unknown mediator errno %d\n"), medep->med_errno);
233	} else {
234		if ((emsg = strerror(medep->med_errno)) != NULL)
235			(void) snprintf(p, psize, "%s", emsg);
236		else
237			(void) snprintf(p, psize, dgettext(TEXT_DOMAIN,
238			    "errno %d out of range"), medep->med_errno);
239	}
240	(void) mderror(ep, MDE_MED_ERROR, buf);
241
242	/* cleanup, return success */
243out:
244	if (medep->med_node != NULL)
245		Free(medep->med_node);
246	if (medep->med_misc != NULL)
247		Free(medep->med_misc);
248	(void) memset(medep, 0, sizeof (*medep));
249	return (rval);
250}
251
252static med_handle_t *
253open_medd_wrap(
254	md_h_t		*mdhp,
255	long		time_out,
256	md_error_t	*ep
257)
258{
259	med_handle_t		*hp = NULL;
260	int			i;
261	char    		*hnm;
262
263	assert(mdhp && mdhp->a_cnt > 0);
264
265	/* Loop through the hosts listed */
266	i = min(mdhp->a_cnt, MAX_HOST_ADDRS) - 1;
267	for (; i >= 0; i--) {
268		hnm = mdhp->a_nm[i];
269
270		if ((hp = open_medd(hnm, time_out, ep)) == NULL) {
271			if (mdanyrpcerror(ep) && i != 0) {
272				mdclrerror(ep);
273				continue;
274			}
275		}
276		return (hp);
277	}
278
279	rpc_createerr.cf_stat = RPC_CANTSEND;
280	rpc_createerr.cf_error.re_status = 0;
281	(void) mdrpccreateerror(ep, mdhp->a_nm[0],
282	    dgettext(TEXT_DOMAIN, "medd open wrap"));
283
284	return (NULL);
285}
286
287static int
288setup_med_transtab(md_error_t *ep)
289{
290	mddb_med_t_parm_t	*tp = NULL;
291	struct	stat		statb;
292	int			i;
293	size_t			alloc_size = 0;
294	int			err = 0;
295
296
297	if ((tp = Zalloc(sizeof (mddb_med_t_parm_t))) == NULL)
298		return (mdsyserror(ep, ENOMEM, "setup_med_transtab"));
299
300	if (metaioctl(MD_MED_GET_TLEN, tp, &tp->med_tp_mde, NULL) != 0) {
301		err = mdstealerror(ep, &tp->med_tp_mde);
302		goto out;
303	}
304
305	if (tp->med_tp_setup == 1)
306		goto out;
307
308	alloc_size = (sizeof (mddb_med_t_parm_t) - sizeof (mddb_med_t_ent_t)) +
309	    (sizeof (mddb_med_t_ent_t) * tp->med_tp_nents);
310
311	if ((tp = Realloc(tp, alloc_size)) == NULL) {
312		err = mdsyserror(ep, ENOMEM, "setup_med_transtab");
313		goto out;
314	}
315
316	if (metaioctl(MD_MED_GET_T, tp, &tp->med_tp_mde, NULL) != 0) {
317		err = mdstealerror(ep, &tp->med_tp_mde);
318		goto out;
319	}
320
321	for (i = 0; i < tp->med_tp_nents; i++) {
322		if (meta_stat(tp->med_tp_ents[i].med_te_nm, &statb) == -1) {
323			md_perror("setup_med_transtab(): stat():");
324			tp->med_tp_ents[i].med_te_dev = NODEV64;
325		} else {
326			tp->med_tp_ents[i].med_te_dev =
327			    meta_expldev(statb.st_rdev);
328		}
329	}
330
331	if (metaioctl(MD_MED_SET_T, tp, &tp->med_tp_mde, NULL) != 0)
332		err = mdstealerror(ep, &tp->med_tp_mde);
333
334out:
335	Free(tp);
336	return (err);
337}
338
339/*
340 * Externals
341 */
342
343/*
344 * NULLPROC - just returns a response
345 */
346int
347clnt_med_null(
348	char			*hostname,
349	md_error_t		*ep
350)
351{
352	med_handle_t		*hp;
353	med_err_t		res;
354
355	/* initialize */
356	mdclrerror(ep);
357
358	/* do it */
359	if ((hp = open_medd(hostname, CL_DEF_TMO, ep)) == NULL)
360		return (-1);
361
362	if (med_null_1(NULL, &res, hp->clntp) != RPC_SUCCESS)
363		(void) mdrpcerror(ep, hp->clntp, hostname,
364		    dgettext(TEXT_DOMAIN, "medd nullproc"));
365
366	close_medd(hp);
367
368	xdr_free(xdr_med_err_t, (char *)&res);
369
370	if (! mdisok(ep))
371		return (-1);
372
373	return (0);
374}
375
376/*
377 * Update the mediator information on the mediator.
378 * This function does the same functionality as
379 * clnt_med_upd_data() except that it takes different
380 * argument so that host which is just a mediator, can
381 * still update its mediator record.
382 */
383int
384clnt_user_med_upd_data(
385	md_h_t	*mdhp,
386	bool_t	obandiskset,
387	char	*setname,
388	uint_t	setnum,
389	med_data_t	*meddp,
390	md_error_t	*ep
391)
392{
393	med_handle_t    	*hp;
394	med_upd_data_args_t	args;
395	med_err_t		res;
396
397	/* Initialize */
398	mdclrerror(ep);
399	(void) memset(&args, 0, sizeof (args));
400	(void) memset(&res, 0, sizeof (res));
401
402	/* Build args */
403	if (obandiskset)
404		args.med.med_caller = Strdup(MED_MN_CALLER);
405	else
406		args.med.med_caller = Strdup(mynode());
407
408	args.med.med_setname = Strdup(setname);
409	args.med.med_setno = setnum;
410	args.med_data = *meddp;
411
412	if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
413		return (-1);
414
415	if (med_upd_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
416		(void) mdrpcerror(ep, hp->clntp, hp->hostname,
417		    dgettext(TEXT_DOMAIN, "medd get record"));
418	else
419		(void) meddstealerror(ep, &res);
420
421	close_medd(hp);
422
423	xdr_free(xdr_med_upd_data_args_t, (char *)&args);
424	xdr_free(xdr_med_err_t, (char *)&res);
425
426	if (! mdisok(ep))
427		return (-1);
428
429	return (0);
430}
431
432/*
433 * Get the mediator information from the client.
434 * The code does same functinality as clnt_med_get_data()
435 * except that it takes different arguments so that
436 * host which doesn't have set information, can still
437 * get access to mediator information
438 */
439int
440clnt_user_med_get_data(
441	md_h_t	*mdhp,
442	bool_t	obandiskset,
443	char	*setname,
444	uint_t	setnum,
445	med_data_t	*meddp,
446	md_error_t	*ep
447)
448{
449	int			rval = -1;
450	med_handle_t		*hp;
451	med_args_t		args;
452	med_get_data_res_t	res;
453
454	/* Initialize */
455	mdclrerror(ep);
456	(void) memset(&args, 0, sizeof (args));
457	(void) memset(&res, 0, sizeof (res));
458
459	/* Build args */
460	if (obandiskset)
461		args.med.med_caller = Strdup(MED_MN_CALLER);
462	else
463		args.med.med_caller = Strdup(mynode());
464
465	args.med.med_setname = Strdup(setname);
466	args.med.med_setno = setnum;
467
468	if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
469		return (-1);
470
471	if (med_get_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
472		(void) mdrpcerror(ep, hp->clntp, hp->hostname,
473		    dgettext(TEXT_DOMAIN, "medd get record"));
474	else
475		(void) meddstealerror(ep, &res.med_status);
476
477	close_medd(hp);
478
479	if (mdisok(ep)) {
480		/* copy the mediator data in meddp */
481		(void) memmove(meddp, &res.med_data, sizeof (med_data_t));
482		rval = 0;
483	}
484
485	xdr_free(xdr_med_args_t, (char *)&args);
486	xdr_free(xdr_med_get_data_res_t, (char *)&res);
487
488	return (rval);
489}
490
491
492/*
493 * Update the mediator information on the mediator.
494 * *** This is not normally called from user code, the kernel does this! ***
495 */
496int
497clnt_med_upd_data(
498	md_h_t			*mdhp,
499	mdsetname_t		*sp,
500	med_data_t		*meddp,
501	md_error_t		*ep
502)
503{
504	med_handle_t		*hp;
505	med_upd_data_args_t	args;
506	med_err_t		res;
507	md_set_desc		*sd;
508
509	/* initialize */
510	mdclrerror(ep);
511	(void) memset(&args, 0, sizeof (args));
512	(void) memset(&res, 0, sizeof (res));
513
514	/* build args */
515	if ((sd = metaget_setdesc(sp, ep)) == NULL)
516		return (-1);
517
518	if (MD_MNSET_DESC(sd))
519		/*
520		 * In the MN diskset, use a generic nodename, multiowner, as
521		 * the node initiating the RPC request.  This allows
522		 * any node to access mediator information.
523		 *
524		 * MN diskset reconfig cycle forces consistent
525		 * view of set/node/drive/mediator information across all nodes
526		 * in the MN diskset.  This allows the relaxation of
527		 * node name checking in rpc.metamedd for MN disksets.
528		 *
529		 * In the traditional diskset, only a calling node that is
530		 * in the mediator record's diskset nodelist can access
531		 * mediator data.
532		 */
533		args.med.med_caller = Strdup(MED_MN_CALLER);
534	else
535		args.med.med_caller = Strdup(mynode());
536	args.med.med_setname = Strdup(sp->setname);
537	args.med.med_setno = sp->setno;
538	args.med_data = *meddp;
539
540	/* do it */
541	if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
542		return (-1);
543
544	if (med_upd_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
545		(void) mdrpcerror(ep, hp->clntp, hp->hostname,
546		    dgettext(TEXT_DOMAIN, "medd update data"));
547	else
548		(void) meddstealerror(ep, &res);
549
550	close_medd(hp);
551
552	xdr_free(xdr_med_upd_data_args_t, (char *)&args);
553	xdr_free(xdr_med_err_t, (char *)&res);
554
555	if (! mdisok(ep))
556		return (-1);
557
558	return (0);
559}
560
561/*
562 * Get the mediator data for this client from the mediator
563 */
564int
565clnt_med_get_data(
566	md_h_t			*mdhp,
567	mdsetname_t		*sp,
568	med_data_t		*meddp,
569	md_error_t		*ep
570)
571{
572	med_handle_t		*hp;
573	med_args_t		args;
574	med_get_data_res_t	res;
575	int			rval = -1;
576	md_set_desc		*sd;
577
578	/* initialize */
579	mdclrerror(ep);
580	(void) memset(&args, 0, sizeof (args));
581	(void) memset(&res, 0, sizeof (res));
582
583	/* build args */
584	if ((sd = metaget_setdesc(sp, ep)) == NULL)
585		return (-1);
586
587	if (MD_MNSET_DESC(sd))
588		/*
589		 * In the MN diskset, use a generic nodename, multiowner, as
590		 * the node initiating the RPC request.  This allows
591		 * any node to access mediator information.
592		 *
593		 * MN diskset reconfig cycle forces consistent
594		 * view of set/node/drive/mediator information across all nodes
595		 * in the MN diskset.  This allows the relaxation of
596		 * node name checking in rpc.metamedd for MN disksets.
597		 *
598		 * In the traditional diskset, only a calling node that is
599		 * in the mediator record's diskset nodelist can access
600		 * mediator data.
601		 */
602		args.med.med_caller = Strdup(MED_MN_CALLER);
603	else
604		args.med.med_caller = Strdup(mynode());
605	args.med.med_setname = Strdup(sp->setname);
606	args.med.med_setno = sp->setno;
607
608	/* do it */
609	if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
610		return (-1);
611
612	if (med_get_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
613		(void) mdrpcerror(ep, hp->clntp, hp->hostname,
614		    dgettext(TEXT_DOMAIN, "medd get data"));
615	else
616		(void) meddstealerror(ep, &res.med_status);
617
618	close_medd(hp);
619
620	if (mdisok(ep)) {
621		/* do something with the results */
622		(void) memmove(meddp, &res.med_data, sizeof (med_data_t));
623		rval = 0;
624	}
625
626	xdr_free(xdr_med_args_t, (char *)&args);
627	xdr_free(xdr_med_get_data_res_t, (char *)&res);
628
629	return (rval);
630}
631
632/*
633 * Update the mediator record on the mediator.
634 */
635int
636clnt_med_upd_rec(
637	md_h_t			*mdhp,
638	mdsetname_t		*sp,
639	med_rec_t		*medrp,
640	md_error_t		*ep
641)
642{
643	med_handle_t		*hp;
644	med_upd_rec_args_t	args;
645	med_err_t		res;
646	md_set_desc		*sd;
647
648	/* initialize */
649	mdclrerror(ep);
650	(void) memset(&args, 0, sizeof (args));
651	(void) memset(&res, 0, sizeof (res));
652
653	/* build args */
654	if ((sd = metaget_setdesc(sp, ep)) == NULL)
655		return (-1);
656
657	if (MD_MNSET_DESC(sd))
658		/*
659		 * In the MN diskset, use a generic nodename, multiowner, as
660		 * the node initiating the RPC request.  This allows
661		 * any node to access mediator information.
662		 *
663		 * MN diskset reconfig cycle forces consistent
664		 * view of set/node/drive/mediator information across all nodes
665		 * in the MN diskset.  This allows the relaxation of
666		 * node name checking in rpc.metamedd for MN disksets.
667		 *
668		 * In the traditional diskset, only a calling node that is
669		 * in the mediator record's diskset nodelist can access
670		 * mediator data.
671		 */
672		args.med.med_caller = Strdup(MED_MN_CALLER);
673	else
674		args.med.med_caller = Strdup(mynode());
675	args.med.med_setname = Strdup(sp->setname);
676	args.med.med_setno = sp->setno;
677	args.med_flags = 0;
678	args.med_rec = *medrp;			/* structure assignment */
679
680	/* do it */
681	if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
682		return (-1);
683
684	if (med_upd_rec_1(&args, &res, hp->clntp) != RPC_SUCCESS)
685		(void) mdrpcerror(ep, hp->clntp, hp->hostname,
686		    dgettext(TEXT_DOMAIN, "medd update record"));
687	else
688		(void) meddstealerror(ep, &res);
689
690	close_medd(hp);
691
692	xdr_free(xdr_med_upd_rec_args_t, (char *)&args);
693	xdr_free(xdr_med_err_t, (char *)&res);
694
695	if (! mdisok(ep))
696		return (-1);
697
698	return (0);
699}
700
701/*
702 * Get the mediator record for this client from the mediator
703 */
704int
705clnt_med_get_rec(
706	md_h_t			*mdhp,
707	mdsetname_t		*sp,
708	med_rec_t		*medrp,
709	md_error_t		*ep
710)
711{
712	med_handle_t		*hp;
713	med_args_t		args;
714	med_get_rec_res_t	res;
715	int			rval = -1;
716	md_set_desc		*sd;
717
718	/* initialize */
719	mdclrerror(ep);
720	(void) memset(&args, 0, sizeof (args));
721	(void) memset(&res, 0, sizeof (res));
722
723	/* build args */
724	if ((sd = metaget_setdesc(sp, ep)) == NULL)
725		return (-1);
726
727	if (MD_MNSET_DESC(sd))
728		/*
729		 * In the MN diskset, use a generic nodename, multiowner, as
730		 * the node initiating the RPC request.  This allows
731		 * any node to access mediator information.
732		 *
733		 * MN diskset reconfig cycle forces consistent
734		 * view of set/node/drive/mediator information across all nodes
735		 * in the MN diskset.  This allows the relaxation of
736		 * node name checking in rpc.metamedd for MN disksets.
737		 *
738		 * In the traditional diskset, only a calling node that is
739		 * in the mediator record's diskset nodelist can access
740		 * mediator data.
741		 */
742		args.med.med_caller = Strdup(MED_MN_CALLER);
743	else
744		args.med.med_caller = Strdup(mynode());
745	args.med.med_setname = Strdup(sp->setname);
746	args.med.med_setno = sp->setno;
747
748	/* do it */
749	if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
750		return (-1);
751
752	if (med_get_rec_1(&args, &res, hp->clntp) != RPC_SUCCESS)
753		(void) mdrpcerror(ep, hp->clntp, hp->hostname,
754		    dgettext(TEXT_DOMAIN, "medd get record"));
755	else
756		(void) meddstealerror(ep, &res.med_status);
757
758	close_medd(hp);
759
760	if (mdisok(ep)) {
761		/* do something with the results */
762		(void) memmove(medrp, &res.med_rec, sizeof (med_rec_t));
763		rval = 0;
764	}
765
766	xdr_free(xdr_med_args_t, (char *)&args);
767	xdr_free(xdr_med_get_rec_res_t, (char *)&res);
768
769	return (rval);
770}
771
772/*
773 * Get the name of the host from the mediator daemon.
774 */
775int
776clnt_med_hostname(
777	char			*hostname,
778	char			**ret_hostname,
779	md_error_t		*ep
780)
781{
782	med_handle_t		*hp;
783	med_hnm_res_t		res;
784	int			rval = -1;
785
786	/* initialize */
787	mdclrerror(ep);
788	(void) memset(&res, 0, sizeof (res));
789
790	/* No args */
791
792	/* do it */
793	if ((hp = open_medd(hostname, CL_DEF_TMO, ep)) == NULL)
794		return (-1);
795
796	if (med_hostname_1(NULL, &res, hp->clntp) != RPC_SUCCESS)
797		(void) mdrpcerror(ep, hp->clntp, hostname,
798		    dgettext(TEXT_DOMAIN, "medd hostname"));
799	else
800		(void) meddstealerror(ep, &res.med_status);
801
802	close_medd(hp);
803
804	if (mdisok(ep)) {
805		/* do something with the results */
806		rval = 0;
807
808		if (ret_hostname != NULL)
809			*ret_hostname = Strdup(res.med_hnm);
810	}
811
812	xdr_free(xdr_med_hnm_res_t, (char *)&res);
813
814	return (rval);
815}
816
817int
818meta_med_hnm2ip(md_hi_arr_t *mp, md_error_t *ep)
819{
820	int		i, j;
821	int		max_meds;
822
823	if ((max_meds = get_max_meds(ep)) == 0)
824		return (-1);
825
826	for (i = 0; i < max_meds; i++) {
827		mp->n_lst[i].a_flg = 0;
828		/* See if this is the local host */
829		if (mp->n_lst[i].a_cnt > 0 &&
830		    strcmp(mp->n_lst[i].a_nm[0], mynode()) == NULL)
831			mp->n_lst[i].a_flg |= NMIP_F_LOCAL;
832
833		for (j = 0; j < mp->n_lst[i].a_cnt; j++) {
834			struct hostent	*hp;
835			char		*hnm = mp->n_lst[i].a_nm[j];
836
837			/*
838			 * Cluster nodename support
839			 *
840			 * See if the clustering code can give us an IP addr
841			 * for the stored name. If not, find it the old way
842			 * which will use the public interface.
843			 */
844			if (sdssc_get_priv_ipaddr(mp->n_lst[i].a_nm[j],
845			    (struct in_addr *)&mp->n_lst[i].a_ip[j]) !=
846			    SDSSC_OKAY) {
847				if ((hp = gethostbyname(hnm)) == NULL)
848					return (mdsyserror(ep, EADDRNOTAVAIL,
849					    hnm));
850
851				/* We only do INET addresses */
852				if (hp->h_addrtype != AF_INET)
853					return (mdsyserror(ep, EPFNOSUPPORT,
854					    hnm));
855
856				/* We take the first address only */
857				if (*hp->h_addr_list) {
858					(void) memmove(&mp->n_lst[i].a_ip[j],
859					    *hp->h_addr_list,
860					    sizeof (struct in_addr));
861				} else
862					return (mdsyserror(ep, EADDRNOTAVAIL,
863					    hnm));
864			}
865
866		}
867	}
868	return (0);
869}
870
871int
872meta_h2hi(md_h_arr_t *mdhp, md_hi_arr_t *mdhip, md_error_t *ep)
873{
874	int			i, j;
875	int			max_meds;
876
877	if ((max_meds = get_max_meds(ep)) == 0)
878		return (-1);
879
880	mdhip->n_cnt = mdhp->n_cnt;
881
882	for (i = 0; i < max_meds; i++) {
883		mdhip->n_lst[i].a_flg = 0;
884		mdhip->n_lst[i].a_cnt = mdhp->n_lst[i].a_cnt;
885		if (mdhp->n_lst[i].a_cnt == 0)
886			continue;
887		for (j = 0; j < mdhp->n_lst[i].a_cnt; j++)
888			(void) strcpy(mdhip->n_lst[i].a_nm[j],
889			    mdhp->n_lst[i].a_nm[j]);
890	}
891	return (0);
892}
893
894int
895meta_hi2h(md_hi_arr_t *mdhip, md_h_arr_t *mdhp, md_error_t *ep)
896{
897	int			i, j;
898	int			max_meds;
899
900	if ((max_meds = get_max_meds(ep)) == 0)
901		return (-1);
902
903	mdhp->n_cnt = mdhip->n_cnt;
904	for (i = 0; i < max_meds; i++) {
905		mdhp->n_lst[i].a_cnt = mdhip->n_lst[i].a_cnt;
906		if (mdhip->n_lst[i].a_cnt == 0)
907			continue;
908		for (j = 0; j < mdhip->n_lst[i].a_cnt; j++)
909			(void) strcpy(mdhp->n_lst[i].a_nm[j],
910			    mdhip->n_lst[i].a_nm[j]);
911	}
912	return (0);
913}
914
915int
916setup_med_cfg(
917	mdsetname_t		*sp,
918	mddb_config_t		*cp,
919	int			force,
920	md_error_t		*ep
921)
922{
923	md_set_desc		*sd;
924	int			i;
925	int			max_meds;
926
927	if (metaislocalset(sp))
928		return (0);
929
930	if ((sd = metaget_setdesc(sp, ep)) == NULL)
931		return (-1);
932
933	if (setup_med_transtab(ep))
934		return (-1);
935
936	if (meta_h2hi(&sd->sd_med, &cp->c_med, ep))
937		return (-1);
938
939	/* Make sure the ip addresses are current */
940	if (meta_med_hnm2ip(&cp->c_med, ep))
941		return (-1);
942
943	if (force)
944		return (0);
945
946	if ((max_meds = get_max_meds(ep)) == 0)
947		return (-1);
948
949	/* Make sure metamedd still running on host - only chk nodename */
950	for (i = 0; i < max_meds; i++) {
951		char		*hostname;
952		char		*hnm;
953
954		if (sd->sd_med.n_lst[i].a_cnt == 0)
955			continue;
956
957		hnm = sd->sd_med.n_lst[i].a_nm[0];
958
959		if (clnt_med_hostname(hnm, &hostname, ep))
960			return (mddserror(ep, MDE_DS_NOMEDONHOST, sp->setno,
961			    hnm, NULL, sp->setname));
962		Free(hostname);
963	}
964	return (0);
965}
966
967/*
968 * This is a general routine to get mediator information from
969 * file /etc/lvm/meddb. Commands medstat and metainit use this
970 * routine to get mediator information from all mediator hosts or update
971 * its mediator record respectively.
972 */
973int
974meta_mediator_info_from_file(char *sname, int verbose, md_error_t *ep)
975{
976	uint_t		c;
977	int		i;
978	int		j;
979	int		fd;
980	int		rec_size;
981	char		*setname;
982	uint_t		setnum;
983	med_rec_t	*rec_buf = NULL;
984	med_db_hdr_t	*dbhbr;
985	med_rec_t	*medrecp;
986	med_data_t	medd;
987	med_data_t	save_medd;
988	md_h_t		mdh;
989	uint_t		latest_med_dat_cc = 0;
990	int		retval = 0;
991	int		medok = 0;
992	int		golden = 0;
993	bool_t		obandiskset;
994	int		isSetFound = 0;
995
996	/* Open the meddb file */
997	if ((fd = open(MED_DB_FILE, O_RDONLY, 0)) == -1) {
998
999		/*
1000		 * During the start up of the SVM services, this function
1001		 * will be called with an empty sname. In that case it is
1002		 * entirely possible for the MED_DB_FILE not to exist.
1003		 * If so, then no need to report an error.
1004		 */
1005		if (sname != NULL) {
1006			(void) mdsyserror(ep, errno, MED_DB_FILE);
1007			mde_perror(ep, dgettext(TEXT_DOMAIN,
1008			    "Error in opening meddb file"));
1009			return (1);
1010		}
1011		return (0);
1012	}
1013
1014	/* Initialize rec_size */
1015	rec_size = roundup(sizeof (med_rec_t), DEV_BSIZE);
1016
1017	/* Allocate a record buffer */
1018	if ((rec_buf = malloc(rec_size)) == NULL) {
1019		(void) mdsyserror(ep, errno, MED_DB_FILE);
1020		mde_perror(ep, dgettext(TEXT_DOMAIN,
1021		    "Error in allocating memory"));
1022		goto out;
1023	}
1024
1025	/* read the file header */
1026	if ((read(fd, rec_buf, rec_size)) != rec_size) {
1027		(void) mdsyserror(ep, EINVAL, MED_DB_FILE);
1028		mde_perror(ep, dgettext(TEXT_DOMAIN,
1029		    "Error in reading mediator record"));
1030		goto out;
1031	}
1032
1033	dbhbr = (med_db_hdr_t *)rec_buf;
1034
1035	/* Number of records in the mediator file */
1036	c = dbhbr->med_dbh_nm;
1037
1038	for (i = 0; i < c; i++) {
1039		(void) memset(rec_buf, 0, rec_size);
1040
1041		if (read(fd, rec_buf, rec_size) == -1) {
1042			(void) mdsyserror(ep, errno, MED_DB_FILE);
1043			mde_perror(ep, dgettext(TEXT_DOMAIN,
1044			    "Error in reading mediator record"));
1045			goto out;
1046		}
1047
1048		medrecp = (med_rec_t *)rec_buf;
1049
1050		/*
1051		 * For oban diskset first entry in the rec_nodes field is
1052		 * "multiowner" and all other entries are empty.
1053		 * Check if this is really multiowner diskset.
1054		 */
1055
1056		if ((strcmp(medrecp->med_rec_nodes[0], MED_MN_CALLER) == 0) &&
1057		    (medrecp->med_rec_nodes[1][0] == '\0'))
1058			obandiskset = TRUE;
1059		else
1060			obandiskset = FALSE;
1061
1062		if (sname != NULL) {
1063			/*
1064			 * Continue if the set name is not in our interest.
1065			 * This is required when this routine is called
1066			 * from medstat
1067			 */
1068
1069			if (strcmp(sname, medrecp->med_rec_snm) != 0) {
1070				continue;
1071			}
1072
1073			if (verbose)
1074				(void) printf("%8.8s\t\t%6.6s\t%6.6s\n",
1075				    gettext("Mediator"), gettext("Status"),
1076				    gettext("Golden"));
1077
1078			isSetFound = 1;
1079			setname = sname;
1080		} else {
1081			setname = medrecp->med_rec_snm;
1082		}
1083		setnum = medrecp->med_rec_sn;
1084		(void) memset(&medd, '\0', sizeof (medd));
1085		(void) memset(&mdh, '\0', sizeof (mdh));
1086		(void) memset(&save_medd, '\0', sizeof (save_medd));
1087		latest_med_dat_cc = 0;
1088
1089		for (j = 0; j < MED_MAX_HOSTS; j++) {
1090			/*
1091			 * It is possible for the n_lst[j] slot to be empty
1092			 * if the mediator node has already been removed so
1093			 * go to the next slot.
1094			 */
1095			if (medrecp->med_rec_meds.n_lst[j].a_cnt == 0)
1096				continue;
1097			mdh = medrecp->med_rec_meds.n_lst[j];
1098
1099			if ((sname != NULL) && (verbose))
1100				(void) printf("%-17.17s\t",
1101				    medrecp->med_rec_meds.n_lst[j].a_nm[0]);
1102
1103			if (clnt_user_med_get_data(&mdh, obandiskset,
1104			    setname, setnum, &medd, ep) == -1) {
1105				if (sname == NULL) {
1106					continue;
1107				} else {
1108					if (mdanyrpcerror(ep)) {
1109						if (verbose)
1110							(void) printf("%s\n",
1111							    gettext("Unreach"
1112							    "able"));
1113						continue;
1114					} else if (mdiserror(ep,
1115					    MDE_MED_ERROR)) {
1116						if (verbose)
1117							(void) printf("%s\n",
1118							    gettext("Bad"));
1119					} else {
1120						if (verbose)
1121							(void) printf("%s\n",
1122							    gettext("Fatal"));
1123					}
1124					mde_perror(ep, "");
1125					if (mdiserror(ep, MDE_MED_ERROR))
1126						continue;
1127					goto out;
1128				}
1129			} else {
1130				/*
1131				 * Make sure this node has the correct value
1132				 * for the mediator record. If not we want the
1133				 * highest value from the other nodes. Save it
1134				 * for updating once the loop through all the
1135				 * mediator nodes has completed.
1136				 */
1137				if (sname == NULL) {
1138					if (latest_med_dat_cc <
1139					    medd.med_dat_cc) {
1140						latest_med_dat_cc =
1141						    medd.med_dat_cc;
1142						(void) memcpy(&save_medd, &medd,
1143						    sizeof (medd));
1144					}
1145				} else {
1146					if (verbose)
1147						(void) printf("%s",
1148						    gettext("Ok"));
1149					if (medd.med_dat_fl & MED_DFL_GOLDEN) {
1150						if (verbose)
1151							(void) printf("\t%s",
1152							    gettext("Yes"));
1153						golden++;
1154					} else {
1155						if (verbose)
1156							(void) printf("\t%s",
1157							    gettext("No"));
1158					}
1159					if (verbose)
1160						(void) printf("\n");
1161						medok++;
1162				}
1163			}
1164		}
1165		if (sname == NULL) {
1166
1167			/*
1168			 * Mediators only become active when there are
1169			 * replica updates to the sets and this can only
1170			 * occur when there is a disk in the set.
1171			 * If there are no disks found then the save_medd
1172			 * structure will be empty. If save_medd is empty,
1173			 * do not update the set.
1174			 */
1175			if (save_medd.med_dat_sn == 0)
1176				continue;
1177			/*
1178			 * Update the latest mediator information
1179			 * on this node
1180			 */
1181			(void) strlcpy(mdh.a_nm[0], mynode(),
1182			    sizeof (mdh.a_nm[0]));
1183			mdh.a_cnt = 1;
1184			if (clnt_user_med_upd_data(&mdh, obandiskset,
1185			    setname, setnum, &save_medd, ep) == -1) {
1186				/*
1187				 * We had some errors while updaing the
1188				 * record. This means this metaset is
1189				 * not updated with latest mediator
1190				 * information.
1191				 */
1192				mde_perror(ep, "");
1193			}
1194
1195		} else {
1196			if (golden) {
1197				retval = 0;
1198				goto out;
1199			}
1200			if (medok < ((medrecp->med_rec_meds.n_cnt / 2) + 1))
1201				retval = 1;
1202		}
1203	}
1204
1205out:
1206	if ((sname != NULL) && (isSetFound == 0)) {
1207		(void) mderror(ep, MDE_NO_SET, sname);
1208		mde_perror(ep, "");
1209		retval = 1;
1210	}
1211	if (rec_buf != NULL)
1212		Free(rec_buf);
1213	if (close(fd) < 0) {
1214		(void) mdsyserror(ep, errno, MED_DB_FILE);
1215		mde_perror(ep, dgettext(TEXT_DOMAIN,
1216		    "Error in closing meddb file"));
1217		return (1);
1218	}
1219	return (retval);
1220}
1221