xref: /titanic_41/usr/src/cmd/lvm/util/metaset.c (revision ea8dc4b6d2251b437950c0056bc626b311c73c27)
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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Metadevice diskset utility.
30  */
31 
32 #include <meta.h>
33 #include <sys/lvm/md_mddb.h>
34 #include <sdssc.h>
35 
36 enum metaset_cmd {
37 	notspecified,
38 	add,
39 	balance,
40 	delete,
41 	cluster,
42 	isowner,
43 	purge,
44 	query,
45 	release,
46 	take,
47 	join,			/* Join a multinode diskset */
48 	withdraw		/* Withdraw from a multinode diskset */
49 };
50 
51 enum cluster_cmd {
52 	ccnotspecified,
53 	clusterversion,		/* Return the version of the cluster I/F */
54 	clusterdisksin,		/* List disks in a given diskset */
55 	clustertake,		/* back door for Cluster take */
56 	clusterrelease,		/* ditto */
57 	clusterpurge,		/* back door for Cluster purge */
58 	clusterproxy		/* proxy the args after '--' to primary */
59 };
60 
61 static void
62 usage(
63 	mdsetname_t	*sp,
64 	char		*string)
65 {
66 	if ((string != NULL) && (*string != '\0'))
67 		md_eprintf("%s\n", string);
68 	(void) fprintf(stderr, gettext(
69 "usage:	%s -s setname -a [-A enable | disable] -h hostname ...\n"
70 "	%s -s setname -a [-M] -h hostname ...\n"
71 "	%s -s setname -a [-M] [-l length] [-L] drivename ...\n"
72 "	%s -s setname -d [-M] -h hostname ...\n"
73 "	%s -s setname -d [-M] -f -h all-hostnames\n"
74 "	%s -s setname -d [-M] [-f] drivename ...\n"
75 "	%s -s setname -d [-M] [-f] hostname ...\n"
76 "	%s -s setname -A enable | disable\n"
77 "	%s -s setname -t [-f]\n"
78 "	%s -s setname -r\n"
79 "	%s [-s setname] -j [-M]\n"
80 "	%s [-s setname] -w [-M]\n"
81 "	%s -s setname -P [-M]\n"
82 "	%s -s setname -b [-M]\n"
83 "	%s -s setname -o [-M] [-h hostname]\n"
84 "	%s [-s setname]\n"
85 "\n"
86 "		hostname = contents of /etc/nodename\n"
87 "		drivename = cNtNdN no slice\n"
88 "		[-M] for multi-owner set is optional except on set creation\n"),
89 	myname, myname, myname, myname, myname, myname, myname, myname,
90 	myname, myname, myname, myname, myname, myname, myname, myname);
91 	md_exit(sp, (string == NULL) ? 0 : 1);
92 }
93 
94 /*
95  * The svm.sync rc script relies heavily on the metaset output.
96  * Any changes to the metaset output MUST verify that the rc script
97  * does not break. Not doing so may potentially leave the system
98  * unusable. You have been WARNED.
99  */
100 static int
101 printset(mdsetname_t *sp, md_error_t *ep)
102 {
103 	int			i, j;
104 	md_set_desc		*sd;
105 	md_drive_desc		*dd, *p;
106 	int			max_meds;
107 	md_mnnode_desc		*nd;
108 
109 	if ((sd = metaget_setdesc(sp, ep)) == NULL)
110 		return (-1);
111 
112 	/*
113 	 * Only get set owner information for traditional diskset.
114 	 * This set owner information is stored in the node records
115 	 * for a MN diskset.
116 	 */
117 	if (!(MD_MNSET_DESC(sd))) {
118 		if (metaget_setownership(sp, ep) == -1)
119 			return (-1);
120 	}
121 
122 	if (((dd = metaget_drivedesc(sp, (MD_BASICNAME_OK | PRINT_FAST),
123 	    ep)) == NULL) && !mdisok(ep))
124 		return (-1);
125 
126 	if (MD_MNSET_DESC(sd)) {
127 		(void) printf(gettext(
128 		"\nMulti-owner Set name = %s, Set number = %d, Master = %s\n"),
129 		    sp->setname, sp->setno, sd->sd_mn_master_nodenm);
130 		if ((sd->sd_mn_master_nodeid == MD_MN_INVALID_NID) &&
131 		    (dd != NULL)) {
132 			(void) printf(gettext(
133 				"Master and owner information unavailable "
134 				"until joined (metaset -j)\n"));
135 		}
136 	} else {
137 		(void) printf(gettext(
138 		    "\nSet name = %s, Set number = %d\n"),
139 		    sp->setname, sp->setno);
140 	}
141 
142 	if (MD_MNSET_DESC(sd)) {
143 		(void) printf(gettext("\n%-19.19s %-14.14s %-6.6s\n"),
144 			gettext("Host"), gettext("Owner"), gettext("Member"));
145 		nd = sd->sd_nodelist;
146 		while (nd) {
147 			/*
148 			 * Don't print nodes that aren't ok since they may be
149 			 * removed from config during a reconfig cycle.  If a
150 			 * node was being added to a diskset and the entire
151 			 * cluster went down but the node being added was unable
152 			 * to reboot, there's no way to know if that node had
153 			 * its own node record set to OK or not.  So, node
154 			 * record is left in ADD state during reconfig cycle.
155 			 * When that node reboots and returns to the cluster,
156 			 * the reconfig cycle will either remove the node
157 			 * record (if not marked OK on that node) or will mark
158 			 * it OK on all nodes.
159 			 * It is very important to only remove a node record
160 			 * from the other nodes when that node record is not
161 			 * marked OK on its own node - otherwise, different
162 			 * nodes would have different nodelists possibly
163 			 * causing different nodes to to choose different
164 			 * masters.
165 			 */
166 			if (!(nd->nd_flags & MD_MN_NODE_OK)) {
167 				nd = nd->nd_next;
168 				continue;
169 			}
170 			if ((nd->nd_flags & MD_MN_NODE_ALIVE) &&
171 			    (nd->nd_flags & MD_MN_NODE_OWN)) {
172 				(void) printf(
173 				    gettext("  %-17.17s  %-12.12s  %-4.4s\n"),
174 				    nd->nd_nodename, gettext("multi-owner"),
175 				    gettext("Yes"));
176 			} else /* Should never be able to happen */
177 			    if ((!(nd->nd_flags & MD_MN_NODE_ALIVE)) &&
178 			    (nd->nd_flags & MD_MN_NODE_OWN)) {
179 				(void) printf(
180 				    gettext("  %-17.17s  %-12.12s  %-4.4s\n"),
181 				    nd->nd_nodename, gettext("multi-owner"),
182 				    gettext("No"));
183 			} else if ((nd->nd_flags & MD_MN_NODE_ALIVE) &&
184 			    (!(nd->nd_flags & MD_MN_NODE_OWN))) {
185 				(void) printf(
186 				    gettext("  %-17.17s  %-12.12s  %-4.4s\n"),
187 				    nd->nd_nodename, gettext(""),
188 				    gettext("Yes"));
189 			} else if ((!(nd->nd_flags & MD_MN_NODE_ALIVE)) &&
190 			    (!(nd->nd_flags & MD_MN_NODE_OWN))) {
191 				(void) printf(
192 				    gettext("  %-17.17s  %-12.12s  %-4.4s\n"),
193 				    nd->nd_nodename, gettext(""),
194 				    gettext("No"));
195 			}
196 			nd = nd->nd_next;
197 		}
198 	} else {
199 		(void) printf("\n%-19.19s %-5.5s\n",
200 			gettext("Host"), gettext("Owner"));
201 		for (i = 0; i < MD_MAXSIDES; i++) {
202 			/* Skip empty slots */
203 			if (sd->sd_nodes[i][0] == '\0')
204 				continue;
205 
206 			/*
207 			 * Standard hostname field is 17 bytes but metaset will
208 			 * display up to MD_MAX_NODENAME, def in meta_basic.h
209 			 */
210 			(void) printf("  %-17.*s  %s\n", MD_MAX_NODENAME,
211 			    sd->sd_nodes[i], (sd->sd_flags & MD_SR_AUTO_TAKE ?
212 				(sd->sd_isown[i] ? gettext("Yes (auto)") :
213 				    gettext("No (auto)"))
214 				: (sd->sd_isown[i] ? gettext("Yes") : "")));
215 		}
216 	}
217 
218 	if (sd->sd_med.n_cnt > 0)
219 		(void) printf("\n%-19.19s %-7.7s\n",
220 		    gettext("Mediator Host(s)"), gettext("Aliases"));
221 
222 	if ((max_meds = get_max_meds(ep)) == 0)
223 		return (-1);
224 
225 	for (i = 0; i < max_meds; i++) {
226 		if (sd->sd_med.n_lst[i].a_cnt == 0)
227 			continue;
228 		(void) printf("  %-17.17s   ", sd->sd_med.n_lst[i].a_nm[0]);
229 		for (j = 1; j < sd->sd_med.n_lst[i].a_cnt; j++) {
230 			(void) printf("%s", sd->sd_med.n_lst[i].a_nm[j]);
231 			if (sd->sd_med.n_lst[i].a_cnt - j > 1)
232 				(void) printf(gettext(", "));
233 		}
234 		(void) printf("\n");
235 	}
236 
237 	if (dd) {
238 		int	len = 0;
239 
240 
241 		/*
242 		 * Building a format string on the fly that will
243 		 * be used in (f)printf. This allows the length
244 		 * of the ctd to vary from small to large without
245 		 * looking horrible.
246 		 */
247 		for (p = dd; p != NULL; p = p->dd_next)
248 			len = max(len, strlen(p->dd_dnp->cname));
249 
250 		len += 2;
251 		(void) printf("\n%-*.*s %-5.5s\n", len, len,
252 		    gettext("Drive"),
253 		    gettext("Dbase"));
254 		for (p = dd; p != NULL; p = p->dd_next) {
255 			(void) printf("\n%-*.*s %-5.5s\n", len, len,
256 			    p->dd_dnp->cname,
257 			    (p->dd_dbcnt ? gettext("Yes") :
258 			    gettext("No")));
259 		}
260 	}
261 
262 	return (0);
263 }
264 
265 static int
266 printsets(mdsetname_t *sp, md_error_t *ep)
267 {
268 	int			i;
269 	mdsetname_t		*sp1;
270 	set_t			max_sets;
271 
272 	/*
273 	 * print setname given.
274 	 */
275 	if (! metaislocalset(sp)) {
276 		if (printset(sp, ep))
277 			return (-1);
278 		return (0);
279 	}
280 
281 	if ((max_sets = get_max_sets(ep)) == 0)
282 		return (-1);
283 
284 	/*
285 	 * Print all known sets
286 	 */
287 	for (i = 1; i < max_sets; i++) {
288 		if ((sp1 = metasetnosetname(i, ep)) == NULL) {
289 			if (! mdiserror(ep, MDE_NO_SET))
290 				break;
291 			mdclrerror(ep);
292 			continue;
293 		}
294 
295 		if (printset(sp1, ep))
296 			break;
297 	}
298 	if (! mdisok(ep))
299 		return (-1);
300 
301 	return (0);
302 }
303 
304 /*
305  * Print the current versionn of the cluster contract private interface.
306  */
307 static void
308 printclusterversion()
309 {
310 	printf("%s\n", METASETIFVERSION);
311 }
312 
313 /*
314  * Print the disks that make up the given disk set. This is used
315  * exclusively by Sun Cluster and is contract private.
316  * Should never be called with sname of a Multinode diskset.
317  */
318 static int
319 printdisksin(char *sname, md_error_t *ep)
320 {
321 	mdsetname_t	*sp;
322 	md_drive_desc	*dd, *p;
323 
324 	if ((sp = metasetname(sname, ep)) == NULL) {
325 
326 		/*
327 		 * During a deletion of a set the associated service is
328 		 * put offline. The SC3.0 reservation code calls disksuite
329 		 * to find a list of disks associated with the set so that
330 		 * it can release the reservation on those disks. In this
331 		 * case there won't be any disks or even a set left. So just
332 		 * return.
333 		 */
334 		return (0);
335 	}
336 
337 	if (metaget_setownership(sp, ep) == -1)
338 		return (-1);
339 
340 	if (((dd = metaget_drivedesc(sp, (MD_BASICNAME_OK | PRINT_FAST),
341 	    ep)) == NULL) && !mdisok(ep))
342 		return (-1);
343 
344 	for (p = dd; p != NULL; p = p->dd_next)
345 		(void) printf("%s\n", p->dd_dnp->rname);
346 
347 	return (0);
348 }
349 
350 static void
351 parse_printset(int argc, char **argv)
352 {
353 	int		c;
354 	mdsetname_t	*sp = NULL;
355 	char		*sname = MD_LOCAL_NAME;
356 	md_error_t	status = mdnullerror;
357 	md_error_t	*ep = &status;
358 
359 	/* reset and parse args */
360 	optind = 1;
361 	opterr = 1;
362 	while ((c = getopt(argc, argv, "s:")) != -1) {
363 		switch (c) {
364 		case 's':
365 			sname = optarg;
366 			break;
367 		default:
368 			usage(sp, gettext("unknown options"));
369 		}
370 	}
371 
372 	argc -= optind;
373 	argv += optind;
374 
375 	if (argc != 0)
376 		usage(sp, gettext("too many args"));
377 
378 	if ((sp = metasetname(sname, ep)) == NULL) {
379 		mde_perror(ep, "");
380 		md_exit(sp, 1);
381 	}
382 
383 	if (printsets(sp, ep) && !mdiserror(ep, MDE_SMF_NO_SERVICE)) {
384 		mde_perror(ep, "");
385 		md_exit(sp, 1);
386 	}
387 
388 	if (meta_smf_isonline(meta_smf_getmask(), ep) == 0) {
389 		mde_perror(ep, "");
390 		md_exit(sp, 1);
391 	}
392 
393 	md_exit(sp, 0);
394 }
395 
396 static void
397 parse_add(int argc, char **argv)
398 {
399 	int			c,
400 				created_set,
401 				hosts = FALSE,
402 				meds = FALSE,
403 				auto_take = FALSE,
404 				force_label = FALSE,
405 				default_size = TRUE;
406 	mdsetname_t		*sp = NULL;
407 	char			*sname = MD_LOCAL_NAME;
408 	md_error_t		status = mdnullerror,
409 				*ep = &status;
410 	mddrivenamelist_t	*dnlp = NULL;
411 	mddrivenamelist_t	*p;
412 	daddr_t			dbsize,
413 				nblks;
414 	mdsetname_t		*local_sp = NULL;
415 	int			multi_node = 0;
416 	md_set_desc		*sd;
417 	rval_e			sdssc_rval;
418 
419 	/* reset and parse args */
420 	optind = 1;
421 	opterr = 1;
422 	while ((c = getopt(argc, argv, "MaA:hl:Lms:")) != -1) {
423 		switch (c) {
424 		case 'M':
425 			multi_node = 1;
426 			break;
427 		case 'A':
428 			/* verified sub-option in main */
429 			if (strcmp(optarg, "enable") == 0)
430 				auto_take = TRUE;
431 			break;
432 		case 'a':
433 			break;
434 		case 'h':
435 		case 'm':
436 			if (meds == TRUE || hosts == TRUE)
437 				usage(sp, gettext(
438 				    "only one -m or -h option allowed"));
439 
440 			if (default_size == FALSE || force_label == TRUE)
441 				usage(sp, gettext(
442 				    "conflicting options"));
443 
444 			if (c == 'h')
445 				hosts = TRUE;
446 			else
447 				meds = TRUE;
448 			break;
449 		case 'l':
450 			if (hosts == TRUE || meds == TRUE)
451 				usage(sp, gettext(
452 				    "conflicting options"));
453 			if (sscanf(optarg, "%ld", &dbsize) != 1) {
454 				md_eprintf(gettext(
455 				    "%s: bad format\n"), optarg);
456 				usage(sp, "");
457 			}
458 
459 			default_size = FALSE;
460 			break;
461 		case 'L':
462 			/* Same criteria as -l */
463 			if (hosts == TRUE || meds == TRUE)
464 				usage(sp, gettext(
465 				    "conflicting options"));
466 			force_label = TRUE;
467 			break;
468 		case 's':
469 			sname = optarg;
470 			break;
471 		default:
472 			usage(sp, gettext(
473 			    "unknown options"));
474 		}
475 	}
476 
477 	/* Can only use -A enable when creating the single-node set */
478 	if (auto_take && hosts != TRUE)
479 		usage(sp, gettext("conflicting options"));
480 
481 	argc -= optind;
482 	argv += optind;
483 
484 	/*
485 	 * Add hosts
486 	 */
487 	if (hosts == TRUE) {
488 
489 		if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
490 			mde_perror(ep, "");
491 			md_exit(local_sp, 1);
492 		}
493 
494 		if (meta_lock(local_sp, TRUE, ep) != 0) {
495 			mde_perror(ep, "");
496 			md_exit(local_sp, 1);
497 		}
498 
499 		/*
500 		 * Keep track of Cluster set creation. Need to complete
501 		 * the transaction no matter if the set was created or not.
502 		 */
503 		created_set = 0;
504 
505 		/*
506 		 * Have no set, cannot take the lock, so only take the
507 		 * local lock.
508 		 */
509 		if ((sp = metasetname(sname, ep)) == NULL) {
510 			sdssc_rval = 0;
511 			if (multi_node) {
512 				/*
513 				 * When running on a cluster system that
514 				 * does not support MN disksets, the routine
515 				 * sdssc_mo_create_begin will be bound
516 				 * to the SVM routine not_bound_error
517 				 * which returns SDSSC_NOT_BOUND_ERROR.
518 				 *
519 				 * When running on a cluster system that
520 				 * does support MN disksets, the routine
521 				 * sdssc_mo_create_begin will be bound to
522 				 * the sdssc_mo_create_begin routine in
523 				 * library libsdssc_so.  A call to
524 				 * sdssc_mo_create_begin will return with
525 				 * either SDSSC_ERROR or SDSSC_OKAY. If
526 				 * an SDSSC_OKAY is returned, then the
527 				 * cluster framework has allocated a
528 				 * set number for this new set that is unique
529 				 * across traditional and MN disksets.
530 				 * Libmeta will get this unique set number
531 				 * by calling sdssc_get_index.
532 				 *
533 				 * When running on a non-cluster system,
534 				 * the routine sdssc_mo_create_begin
535 				 * will be bound to the SVM routine
536 				 * not_bound which returns SDSSC_NOT_BOUND.
537 				 * In this case, all sdssc routines will
538 				 * return SDSSC_NOT_BOUND.  No need to check
539 				 * for return value of SDSSC_NOT_BOUND since
540 				 * the libmeta call to get the set number
541 				 * (sdssc_get_index) will also fail with
542 				 * SDSSC_NOT_BOUND causing libmeta to
543 				 * determine its own set number.
544 				 */
545 				sdssc_rval = sdssc_mo_create_begin(sname, argc,
546 					argv, SDSSC_PICK_SETNO);
547 				if (sdssc_rval == SDSSC_NOT_BOUND_ERROR) {
548 					mderror(ep, MDE_NOT_MN, NULL);
549 					mde_perror(ep,
550 					"Cluster node does not support "
551 					"multi-owner diskset operations");
552 					md_exit(local_sp, 1);
553 				} else if (sdssc_rval == SDSSC_ERROR) {
554 					mde_perror(ep, "");
555 					md_exit(local_sp, 1);
556 				}
557 			} else {
558 				sdssc_rval = sdssc_create_begin(sname, argc,
559 					argv, SDSSC_PICK_SETNO);
560 				if (sdssc_rval == SDSSC_ERROR) {
561 					mde_perror(ep, "");
562 					md_exit(local_sp, 1);
563 				}
564 			}
565 			/*
566 			 * Created diskset (as opposed to adding a
567 			 * host to an existing diskset).
568 			 */
569 			created_set = 1;
570 
571 			sp = Zalloc(sizeof (*sp));
572 			sp->setname = Strdup(sname);
573 			sp->lockfd = MD_NO_LOCK;
574 			mdclrerror(ep);
575 		} else {
576 			if ((sd = metaget_setdesc(sp, ep)) == NULL) {
577 				mde_perror(ep, "");
578 				md_exit(local_sp, 1);
579 			}
580 			if (MD_MNSET_DESC(sd)) {
581 				multi_node = 1;
582 			}
583 
584 			/*
585 			 * can't add hosts to an existing set & enable
586 			 * auto-take
587 			 */
588 			if (auto_take)
589 				usage(sp, gettext("conflicting options"));
590 
591 			/*
592 			 * Have a valid set, take the set lock also.
593 			 *
594 			 * A MN diskset does not use the set meta_lock but
595 			 * instead uses the clnt_lock of rpc.metad and the
596 			 * suspend/resume feature of the rpc.mdcommd.  Can't
597 			 * use set meta_lock since class 1 messages are
598 			 * grabbing this lock and if this thread is holding
599 			 * the set meta_lock then no rpc.mdcommd suspend
600 			 * can occur.
601 			 */
602 			if (!multi_node) {
603 				if (meta_lock(sp, TRUE, ep) != 0) {
604 					mde_perror(ep, "");
605 					md_exit(local_sp, 1);
606 				}
607 			}
608 		}
609 
610 		if (meta_set_addhosts(sp, multi_node, argc, argv, auto_take,
611 		    ep)) {
612 			if (created_set)
613 				sdssc_create_end(sname, SDSSC_CLEANUP);
614 			mde_perror(&status, "");
615 			if (!multi_node)
616 				(void) meta_unlock(sp, ep);
617 			md_exit(local_sp, 1);
618 		}
619 
620 		if (created_set)
621 			sdssc_create_end(sname, SDSSC_COMMIT);
622 
623 		else {
624 			/*
625 			 * If adding hosts to existing diskset,
626 			 * call DCS svcs
627 			 */
628 			sdssc_add_hosts(sname, argc, argv);
629 		}
630 		if (!multi_node)
631 			(void) meta_unlock(sp, ep);
632 		md_exit(local_sp, 0);
633 	}
634 
635 	/*
636 	 * Add mediators
637 	 */
638 	if (meds == TRUE) {
639 
640 		if ((sp = metasetname(sname, ep)) == NULL) {
641 			mde_perror(ep, "");
642 			md_exit(local_sp, 1);
643 		}
644 
645 		if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
646 			mde_perror(ep, "");
647 			md_exit(local_sp, 1);
648 		}
649 
650 		if ((sd = metaget_setdesc(sp, ep)) == NULL) {
651 			mde_perror(ep, "");
652 			md_exit(local_sp, 1);
653 		}
654 		if (MD_MNSET_DESC(sd)) {
655 			multi_node = 1;
656 		}
657 
658 		if (meta_lock(local_sp, TRUE, ep) != 0) {
659 			mde_perror(ep, "");
660 			md_exit(local_sp, 1);
661 		}
662 		/*
663 		 * A MN diskset does not use the set meta_lock but
664 		 * instead uses the clnt_lock of rpc.metad and the
665 		 * suspend/resume feature of the rpc.mdcommd.  Can't
666 		 * use set meta_lock since class 1 messages are
667 		 * grabbing this lock and if this thread is holding
668 		 * the set meta_lock then no rpc.mdcommd suspend
669 		 * can occur.
670 		 */
671 		if (!multi_node) {
672 			if (meta_lock(sp, TRUE, ep) != 0) {
673 				mde_perror(ep, "");
674 				md_exit(local_sp, 1);
675 			}
676 		}
677 
678 		if (meta_set_addmeds(sp, argc, argv, ep)) {
679 			mde_perror(&status, "");
680 			if (!multi_node)
681 				(void) meta_unlock(sp, ep);
682 			md_exit(local_sp, 1);
683 		}
684 
685 		if (!multi_node)
686 			(void) meta_unlock(sp, ep);
687 		md_exit(local_sp, 0);
688 	}
689 
690 	/*
691 	 * Add drives
692 	 */
693 	if ((sp = metasetname(sname, ep)) == NULL) {
694 		mde_perror(ep, "");
695 		md_exit(local_sp, 1);
696 	}
697 
698 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
699 		mde_perror(ep, "");
700 		md_exit(local_sp, 1);
701 	}
702 
703 	/* Determine if diskset is a MN diskset or not */
704 	if ((sd = metaget_setdesc(sp, ep)) == NULL) {
705 		mde_perror(ep, "");
706 		md_exit(local_sp, 1);
707 	}
708 	if (MD_MNSET_DESC(sd)) {
709 		multi_node = 1;
710 	}
711 
712 	if (meta_lock(local_sp, TRUE, ep) != 0) {
713 		mde_perror(ep, "");
714 		md_exit(local_sp, 1);
715 	}
716 
717 	/* Make sure database size is within limits */
718 	if (default_size == FALSE) {
719 		if ((multi_node && dbsize < MDDB_MN_MINBLKS) ||
720 		    (!multi_node && dbsize < MDDB_MINBLKS))
721 			usage(sp, gettext(
722 			    "size (-l) is too small"));
723 
724 		if ((multi_node && dbsize > MDDB_MN_MAXBLKS) ||
725 		    (!multi_node && dbsize > MDDB_MAXBLKS))
726 			usage(sp, gettext(
727 			    "size (-l) is too big"));
728 	}
729 
730 	/*
731 	 * Have a valid set, take the set lock also.
732 	 *
733 	 * A MN diskset does not use the set meta_lock but
734 	 * instead uses the clnt_lock of rpc.metad and the
735 	 * suspend/resume feature of the rpc.mdcommd.  Can't
736 	 * use set meta_lock since class 1 messages are
737 	 * grabbing this lock and if this thread is holding
738 	 * the set meta_lock then no rpc.mdcommd suspend
739 	 * can occur.
740 	 */
741 	if (!multi_node) {
742 		if (meta_lock(sp, TRUE, ep) != 0) {
743 			mde_perror(ep, "");
744 			md_exit(local_sp, 1);
745 		}
746 	}
747 
748 
749 	/*
750 	 * If using the default size,
751 	 *   then let's adjust the default to the minimum
752 	 *   size currently in use.
753 	 */
754 	if (default_size) {
755 		dbsize = multi_node ? MD_MN_DBSIZE : MD_DBSIZE;
756 		if ((nblks = meta_db_minreplica(sp, ep)) < 0)
757 			mdclrerror(ep);
758 		else
759 			dbsize = nblks;	/* adjust replica size */
760 	}
761 
762 	if ((c = metadrivenamelist(&sp, &dnlp, argc, argv, ep)) < 0) {
763 		mde_perror(ep, "");
764 		if (!multi_node)
765 			(void) meta_unlock(sp, ep);
766 		md_exit(local_sp, 1);
767 	}
768 
769 	if (c == 0) {
770 		md_perror(gettext(
771 		    "No drives specified to add.\n"));
772 		if (!multi_node)
773 			(void) meta_unlock(sp, ep);
774 		md_exit(local_sp, 1);
775 	}
776 
777 	if (meta_set_adddrives(sp, dnlp, dbsize, force_label, ep)) {
778 		metafreedrivenamelist(dnlp);
779 		mde_perror(ep, "");
780 		if (!multi_node)
781 			(void) meta_unlock(sp, ep);
782 		md_exit(local_sp, 1);
783 	}
784 
785 	/*
786 	 * MN disksets don't have a device id in the master block
787 	 * For traditional disksets, check for the drive device
788 	 * id not fitting in the master block
789 	 */
790 	if (!multi_node) {
791 		for (p = dnlp; p != NULL; p = p->next) {
792 			int 		fd;
793 			ddi_devid_t	devid;
794 			mdname_t	*np;
795 
796 			np = metaslicename(p->drivenamep, 0, ep);
797 			if (np == NULL)
798 				continue;
799 
800 			if ((fd = open(np->rname, O_RDONLY | O_NDELAY)) < 0)
801 				continue;
802 
803 			if (devid_get(fd, &devid) == 0) {
804 				size_t len;
805 
806 				len = devid_sizeof(devid);
807 				if (len > (DEV_BSIZE - sizeof (mddb_mb_t)))
808 					(void) mddserror(ep,
809 					    MDE_DS_NOTSELFIDENTIFY, NULL, NULL,
810 					    np->rname, NULL);
811 				devid_free(devid);
812 			} else {
813 				(void) mddserror(ep, MDE_DS_NOTSELFIDENTIFY,
814 				    NULL, NULL, np->rname, NULL);
815 			}
816 			(void) close(fd);
817 		}
818 	}
819 
820 	/*
821 	 * MN disksets don't use DCS clustering services.
822 	 * For traditional disksets:
823 	 * There's not really much we can do here if this call fails.
824 	 * The drives have been added to the set and DiskSuite believes
825 	 * it owns the drives.
826 	 * Relase the set and hope for the best.
827 	 */
828 	if ((!multi_node) &&
829 	    (sdssc_notify_service(sname, Make_Primary) == SDSSC_ERROR)) {
830 		meta_set_release(sp, ep);
831 		printf(gettext(
832 		    "Sun Clustering failed to make set primary\n"));
833 	}
834 
835 	metafreedrivenamelist(dnlp);
836 	if (!multi_node)
837 		(void) meta_unlock(sp, ep);
838 	md_exit(local_sp, 0);
839 }
840 
841 static void
842 parse_balance(int argc, char **argv)
843 {
844 	int		c;
845 	mdsetname_t	*sp = NULL;
846 	char		*sname = MD_LOCAL_NAME;
847 	md_error_t	status = mdnullerror;
848 	md_set_desc	*sd;
849 	int		multi_node = 0;
850 
851 	/* reset and parse args */
852 	optind = 1;
853 	opterr = 1;
854 	while ((c = getopt(argc, argv, "Mbs:")) != -1) {
855 		switch (c) {
856 		case 'M':
857 			break;
858 		case 'b':
859 			break;
860 		case 's':
861 			sname = optarg;
862 			break;
863 		default:
864 			usage(sp, gettext("unknown options"));
865 		}
866 	}
867 
868 	argc -= optind;
869 	argv += optind;
870 
871 	if (argc != 0)
872 		usage(sp, gettext("too many args"));
873 
874 	if ((sp = metasetname(sname, &status)) == NULL) {
875 		mde_perror(&status, "");
876 		md_exit(sp, 1);
877 	}
878 	if ((sd = metaget_setdesc(sp, &status)) == NULL) {
879 		mde_perror(&status, "");
880 		md_exit(sp, 1);
881 	}
882 	if (MD_MNSET_DESC(sd)) {
883 		multi_node = 1;
884 	}
885 	/*
886 	 * Have a valid set, take the set lock also.
887 	 *
888 	 * A MN diskset does not use the set meta_lock but
889 	 * instead uses the clnt_lock of rpc.metad and the
890 	 * suspend/resume feature of the rpc.mdcommd.  Can't
891 	 * use set meta_lock since class 1 messages are
892 	 * grabbing this lock and if this thread is holding
893 	 * the set meta_lock then no rpc.mdcommd suspend
894 	 * can occur.
895 	 */
896 	if (!multi_node) {
897 		if (meta_lock(sp, TRUE, &status) != 0) {
898 			mde_perror(&status, "");
899 			md_exit(sp, 1);
900 		}
901 	}
902 
903 	if (meta_set_balance(sp, &status) != 0) {
904 		mde_perror(&status, "");
905 		md_exit(sp, 1);
906 	}
907 	md_exit(sp, 0);
908 }
909 
910 static void
911 parse_autotake(int argc, char **argv)
912 {
913 	int			c;
914 	int			enable = 0;
915 	mdsetname_t		*sp = NULL;
916 	char			*sname = MD_LOCAL_NAME;
917 	md_error_t		status = mdnullerror;
918 	md_error_t		*ep = &status;
919 
920 	/* reset and parse args */
921 	optind = 1;
922 	opterr = 1;
923 	while ((c = getopt(argc, argv, "A:s:")) != -1) {
924 		switch (c) {
925 		case 'A':
926 			/* verified sub-option in main */
927 			if (strcmp(optarg, "enable") == 0)
928 				enable = 1;
929 			break;
930 		case 's':
931 			/* verified presence of setname in main */
932 			sname = optarg;
933 			break;
934 		default:
935 			usage(sp, gettext("unknown options"));
936 		}
937 	}
938 
939 	if ((sp = metasetname(sname, ep)) == NULL) {
940 		mde_perror(ep, "");
941 		md_exit(sp, 1);
942 	}
943 
944 	if (meta_lock(sp, TRUE, ep) != 0) {
945 		mde_perror(ep, "");
946 		md_exit(sp, 1);
947 	}
948 
949 	if (meta_check_ownership(sp, ep) != 0) {
950 		mde_perror(ep, "");
951 		md_exit(sp, 1);
952 	}
953 
954 	if (meta_set_auto_take(sp, enable, ep) != 0) {
955 		mde_perror(ep, "");
956 		md_exit(sp, 1);
957 	}
958 
959 	md_exit(sp, 0);
960 }
961 
962 static void
963 parse_del(int argc, char **argv)
964 {
965 	int			c;
966 	mdsetname_t		*sp = NULL;
967 	char			*sname = MD_LOCAL_NAME;
968 	int			hosts = FALSE;
969 	int			meds = FALSE;
970 	int			forceflg = FALSE;
971 	md_error_t		status = mdnullerror;
972 	md_error_t		*ep = &status;
973 	mddrivenamelist_t	*dnlp = NULL;
974 	mdsetname_t		*local_sp = NULL;
975 	md_set_desc		*sd;
976 	int			multi_node = 0;
977 
978 	/* reset and parse args */
979 	optind = 1;
980 	opterr = 1;
981 	while ((c = getopt(argc, argv, "Mdfhms:")) != -1) {
982 		switch (c) {
983 		case 'M':
984 			break;
985 		case 'd':
986 			break;
987 		case 'f':
988 			forceflg = TRUE;
989 			break;
990 		case 'h':
991 		case 'm':
992 			if (meds == TRUE || hosts == TRUE)
993 				usage(sp, gettext(
994 				    "only one -m or -h option allowed"));
995 
996 			if (c == 'h')
997 				hosts = TRUE;
998 			else
999 				meds = TRUE;
1000 			break;
1001 		case 's':
1002 			sname = optarg;
1003 			break;
1004 		default:
1005 			usage(sp, gettext("unknown options"));
1006 		}
1007 	}
1008 
1009 	argc -= optind;
1010 	argv += optind;
1011 
1012 	if ((sp = metasetname(sname, ep)) == NULL) {
1013 		mde_perror(ep, "");
1014 		md_exit(local_sp, 1);
1015 	}
1016 
1017 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
1018 		mde_perror(ep, "");
1019 		md_exit(local_sp, 1);
1020 	}
1021 
1022 	if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1023 		mde_perror(ep, "");
1024 		md_exit(local_sp, 1);
1025 	}
1026 	if (MD_MNSET_DESC(sd))
1027 		multi_node = 1;
1028 
1029 	if (meta_lock(local_sp, TRUE, ep) != 0) {
1030 		mde_perror(ep, "");
1031 		md_exit(local_sp, 1);
1032 	}
1033 
1034 	/*
1035 	 * Have a valid set, take the set lock also.
1036 	 *
1037 	 * A MN diskset does not use the set meta_lock but
1038 	 * instead uses the clnt_lock of rpc.metad and the
1039 	 * suspend/resume feature of the rpc.mdcommd.  Can't
1040 	 * use set meta_lock since class 1 messages are
1041 	 * grabbing this lock and if this thread is holding
1042 	 * the set meta_lock then no rpc.mdcommd suspend
1043 	 * can occur.
1044 	 */
1045 	if (!multi_node) {
1046 		if (meta_lock(sp, TRUE, ep) != 0) {
1047 			mde_perror(ep, "");
1048 			md_exit(local_sp, 1);
1049 		}
1050 	}
1051 
1052 	/*
1053 	 * Delete hosts
1054 	 */
1055 	if (hosts == TRUE) {
1056 		if (meta_check_ownership(sp, ep) != 0) {
1057 			/*
1058 			 * If we don't own the set bail out here otherwise
1059 			 * we could delete the node from the DCS service
1060 			 * yet not delete the host from the set.
1061 			 */
1062 			mde_perror(ep, "");
1063 			if (!multi_node)
1064 				(void) meta_unlock(sp, ep);
1065 			md_exit(local_sp, 1);
1066 		}
1067 		if (sdssc_delete_hosts(sname, argc, argv) == SDSSC_ERROR) {
1068 		    if (!metad_isautotakebyname(sname)) {
1069 			/*
1070 			 * SC could have been installed after the set was
1071 			 * created.  We still want to be able to delete these
1072 			 * sets.
1073 			 */
1074 			md_perror(gettext(
1075 			    "Failed to delete hosts from DCS service"));
1076 			if (!multi_node)
1077 				(void) meta_unlock(sp, ep);
1078 			md_exit(local_sp, 1);
1079 		    }
1080 		}
1081 		if (meta_set_deletehosts(sp, argc, argv, forceflg, ep)) {
1082 			if (sdssc_add_hosts(sname, argc, argv) == SDSSC_ERROR) {
1083 				(void) printf(gettext(
1084 				    "Failed to restore host(s) in DCS "
1085 				    "database\n"));
1086 			}
1087 			mde_perror(ep, "");
1088 			if (!multi_node)
1089 				(void) meta_unlock(sp, ep);
1090 			md_exit(local_sp, 1);
1091 		}
1092 		if (!multi_node)
1093 			(void) meta_unlock(sp, ep);
1094 		md_exit(local_sp, 0);
1095 	}
1096 
1097 	/*
1098 	 * Delete mediators
1099 	 */
1100 	if (meds == TRUE) {
1101 		if (meta_set_deletemeds(sp, argc, argv, forceflg, ep)) {
1102 			mde_perror(ep, "");
1103 			if (!multi_node)
1104 				(void) meta_unlock(sp, ep);
1105 			md_exit(local_sp, 1);
1106 		}
1107 		if (!multi_node)
1108 			(void) meta_unlock(sp, ep);
1109 		md_exit(local_sp, 0);
1110 	}
1111 
1112 	/*
1113 	 * Delete drives
1114 	 */
1115 
1116 	if ((c = metadrivenamelist(&sp, &dnlp, argc, argv, ep)) < 0) {
1117 		mde_perror(ep, "");
1118 		if (!multi_node)
1119 			(void) meta_unlock(sp, ep);
1120 		md_exit(local_sp, 1);
1121 	}
1122 
1123 	if (c == 0) {
1124 		md_perror(gettext(
1125 		    "No drives specified to delete.\n"));
1126 		if (!multi_node)
1127 			(void) meta_unlock(sp, ep);
1128 		md_exit(local_sp, 1);
1129 	}
1130 
1131 	if (meta_set_deletedrives(sp, dnlp, forceflg, ep)) {
1132 		metafreedrivenamelist(dnlp);
1133 		mde_perror(ep, "");
1134 		if (!multi_node)
1135 			(void) meta_unlock(sp, ep);
1136 		md_exit(local_sp, 1);
1137 	}
1138 
1139 	metafreedrivenamelist(dnlp);
1140 	if (!multi_node)
1141 		(void) meta_unlock(sp, ep);
1142 	md_exit(local_sp, 0);
1143 }
1144 
1145 static void
1146 parse_isowner(int argc, char **argv)
1147 {
1148 	int		c;
1149 	mdsetname_t	*sp = NULL;
1150 	char		*sname = MD_LOCAL_NAME;
1151 	md_error_t	status = mdnullerror;
1152 	md_error_t	*ep = &status;
1153 	char		*host = NULL;
1154 
1155 	/* reset and parse args */
1156 	optind = 1;
1157 	opterr = 1;
1158 	while ((c = getopt(argc, argv, "Moh:s:")) != -1) {
1159 		switch (c) {
1160 		case 'M':
1161 			break;
1162 		case 'o':
1163 			break;
1164 		case 'h':
1165 			if (host != NULL) {
1166 				usage(sp, gettext(
1167 				    "only one -h option allowed"));
1168 			}
1169 			host = optarg;
1170 			break;
1171 		case 's':
1172 			sname = optarg;
1173 			break;
1174 		default:
1175 			usage(sp, gettext("unknown options"));
1176 		}
1177 	}
1178 
1179 	argc -= optind;
1180 	argv += optind;
1181 
1182 	if (argc != 0)
1183 		usage(sp, gettext("too many args"));
1184 
1185 	if ((sp = metasetname(sname, ep)) == NULL) {
1186 		mde_perror(ep, "");
1187 		md_exit(sp, 1);
1188 	}
1189 
1190 	if (host == NULL) {
1191 		if (meta_check_ownership(sp, ep) != 0) {
1192 			mde_perror(ep, "");
1193 			md_exit(sp, 1);
1194 		}
1195 	} else {
1196 		if (meta_check_ownership_on_host(sp, host, ep) != 0) {
1197 			mde_perror(ep, "");
1198 			md_exit(sp, 1);
1199 		}
1200 	}
1201 	md_exit(sp, 0);
1202 }
1203 
1204 static void
1205 parse_purge(int argc, char **argv)
1206 {
1207 	int		c;
1208 	mdsetname_t	*sp = NULL;
1209 	mdsetname_t	*local_sp = NULL;
1210 	md_drive_desc	*dd;
1211 	char		*sname = MD_LOCAL_NAME;
1212 	char		*thishost = mynode();
1213 	md_error_t	status = mdnullerror;
1214 	md_error_t	*ep = &status;
1215 	int		bypass_cluster_purge = 0;
1216 	int		forceflg = FALSE;
1217 	int		ret = 0;
1218 	int		multi_node = 0;
1219 	md_set_desc		*sd;
1220 
1221 	optind = 1;
1222 	opterr = 1;
1223 	while ((c = getopt(argc, argv, "C:fPs:")) != -1) {
1224 		switch (c) {
1225 		case 'M':
1226 			break;
1227 		case 'C':
1228 			bypass_cluster_purge = 1;
1229 			break;
1230 		case 'f':
1231 			forceflg = TRUE;
1232 			break;
1233 		case 'P':
1234 			break;
1235 		case 's':
1236 			sname = optarg;
1237 			break;
1238 		default:
1239 			usage(sp, gettext("unknown options"));
1240 		}
1241 	}
1242 
1243 	argc -= optind;
1244 	argv += optind;
1245 
1246 	if (argc != 0)
1247 		usage(sp, gettext("too many arguments"));
1248 
1249 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
1250 		mde_perror(ep, "");
1251 		md_exit(local_sp, 1);
1252 	}
1253 
1254 	if (meta_lock(local_sp, TRUE, ep) != 0) {
1255 		mde_perror(ep, "");
1256 		md_exit(local_sp, 1);
1257 	}
1258 
1259 	if ((sp = metasetname(sname, ep)) == NULL) {
1260 		mde_perror(ep, "");
1261 		md_exit(sp, 1);
1262 	}
1263 
1264 	if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1265 		mde_perror(ep, "");
1266 		md_exit(local_sp, 1);
1267 	}
1268 	if (MD_MNSET_DESC(sd))
1269 		multi_node = 1;
1270 
1271 	if (!multi_node) {
1272 		if (meta_lock(sp, TRUE, ep) != 0) {
1273 			mde_perror(ep, "");
1274 			md_exit(local_sp, 1);
1275 		}
1276 	}
1277 
1278 	/* Must not own the set if purging it from this host */
1279 	if (meta_check_ownership(sp, ep) == 0) {
1280 		/*
1281 		 * Need to see if there are disks in the set, if not then
1282 		 * there is no ownership but meta_check_ownership returns 0
1283 		 */
1284 		dd = metaget_drivedesc(sp, (MD_BASICNAME_OK | PRINT_FAST), ep);
1285 		if (!mdisok(ep)) {
1286 			mde_perror(ep, "");
1287 			if (!multi_node)
1288 				(void) meta_unlock(sp, ep);
1289 			md_exit(local_sp, 1);
1290 		}
1291 		if (dd != NULL) {
1292 			(void) printf(gettext
1293 			    ("Must not be owner of the set when purging it\n"));
1294 			if (!multi_node)
1295 				(void) meta_unlock(sp, ep);
1296 			md_exit(local_sp, 1);
1297 		}
1298 	}
1299 	/*
1300 	 * Remove the node from the DCS service
1301 	 */
1302 	if (!bypass_cluster_purge) {
1303 		if (sdssc_delete_hosts(sname, 1, &thishost) == SDSSC_ERROR) {
1304 			md_perror(gettext
1305 			    ("Failed to purge hosts from DCS service"));
1306 			if (!multi_node)
1307 				(void) meta_unlock(sp, ep);
1308 			md_exit(local_sp, 1);
1309 		}
1310 	}
1311 
1312 	if ((ret = meta_set_purge(sp, bypass_cluster_purge, forceflg,
1313 	    ep)) != 0) {
1314 		if (!bypass_cluster_purge) {
1315 			if (sdssc_add_hosts(sname, 1, &thishost) ==
1316 			    SDSSC_ERROR) {
1317 				(void) printf(gettext(
1318 				    "Failed to restore host in DCS "
1319 				    "database\n"));
1320 			}
1321 		}
1322 		mde_perror(ep, "");
1323 		if (!multi_node)
1324 			(void) meta_unlock(sp, ep);
1325 		md_exit(local_sp, ret);
1326 	}
1327 
1328 	if (!multi_node)
1329 		(void) meta_unlock(sp, ep);
1330 	md_exit(local_sp, 0);
1331 }
1332 
1333 static void
1334 parse_query(int argc, char **argv)
1335 {
1336 	int		c;
1337 	mdsetname_t	*sp = NULL;
1338 	mddb_dtag_lst_t	*dtlp = NULL;
1339 	mddb_dtag_lst_t	*tdtlp;
1340 	char		*sname = MD_LOCAL_NAME;
1341 	md_error_t	status = mdnullerror;
1342 
1343 	/* reset and parse args */
1344 	optind = 1;
1345 	opterr = 1;
1346 	while ((c = getopt(argc, argv, "Mqs:")) != -1) {
1347 		switch (c) {
1348 		case 'M':
1349 			break;
1350 		case 'q':
1351 			break;
1352 		case 's':
1353 			sname = optarg;
1354 			break;
1355 		default:
1356 			usage(sp, gettext("unknown options"));
1357 		}
1358 	}
1359 
1360 	argc -= optind;
1361 	argv += optind;
1362 
1363 	if (argc != 0)
1364 		usage(sp, gettext("too many args"));
1365 
1366 	if ((sp = metasetname(sname, &status)) == NULL) {
1367 		mde_perror(&status, "");
1368 		md_exit(sp, 1);
1369 	}
1370 
1371 	if (meta_lock(sp, TRUE, &status) != 0) {
1372 		mde_perror(&status, "");
1373 		md_exit(sp, 1);
1374 	}
1375 
1376 	if (meta_set_query(sp, &dtlp, &status) != 0) {
1377 		mde_perror(&status, "");
1378 		md_exit(sp, 1);
1379 	}
1380 
1381 	if (dtlp != NULL)
1382 		(void) printf("The following tag(s) were found:\n");
1383 
1384 	for (tdtlp = dtlp; tdtlp != NULL; tdtlp = dtlp) {
1385 		dtlp = tdtlp->dtl_nx;
1386 		(void) printf("%2d - %s - %s", tdtlp->dtl_dt.dt_id,
1387 		    tdtlp->dtl_dt.dt_hn,
1388 		    ctime((long *)&tdtlp->dtl_dt.dt_tv.tv_sec));
1389 		Free(tdtlp);
1390 	}
1391 
1392 	md_exit(sp, 0);
1393 }
1394 
1395 /* Should never be called with sname of a Multinode diskset. */
1396 static void
1397 parse_releaseset(int argc, char **argv)
1398 {
1399 	int		c;
1400 	mdsetname_t	*sp = NULL;
1401 	md_error_t	status = mdnullerror;
1402 	md_error_t	*ep = &status;
1403 	char		*sname = MD_LOCAL_NAME;
1404 	sdssc_boolean_e	cluster_release = SDSSC_False;
1405 	sdssc_version_t	vers;
1406 	rval_e		rval;
1407 	md_set_desc	*sd;
1408 
1409 	/* reset and parse args */
1410 	optind = 1;
1411 	opterr = 1;
1412 	while ((c = getopt(argc, argv, "C:s:r")) != -1) {
1413 		switch (c) {
1414 		case 'C':
1415 			cluster_release = SDSSC_True;
1416 			break;
1417 		case 's':
1418 			sname = optarg;
1419 			break;
1420 		case 'r':
1421 			break;
1422 		default:
1423 			usage(sp, gettext("unknown options"));
1424 		}
1425 	}
1426 
1427 	argc -= optind;
1428 	argv += optind;
1429 
1430 	if (argc > 0)
1431 		usage(sp, gettext("too many args"));
1432 
1433 	memset(&vers, 0, sizeof (vers));
1434 
1435 	if ((sdssc_version(&vers) == SDSSC_OKAY) &&
1436 	    (vers.major == 3) &&
1437 	    (cluster_release == SDSSC_False)) {
1438 
1439 		/*
1440 		 * If the release is being done by the user via the CLI
1441 		 * we need to notify the DCS to release this node as being
1442 		 * the primary. The reason nothing else needs to be done
1443 		 * is due to the fact that the reservation code will exec
1444 		 * metaset -C release to complete the operation.
1445 		 */
1446 		rval = sdssc_notify_service(sname, Release_Primary);
1447 		if (rval == SDSSC_ERROR) {
1448 			printf(gettext(
1449 			    "metaset: failed to notify DCS of release\n"));
1450 		}
1451 		md_exit(NULL, rval == SDSSC_ERROR);
1452 	}
1453 
1454 	if ((sp = metasetname(sname, ep)) == NULL) {
1455 
1456 		/*
1457 		 * It's entirely possible for the SC3.0 reservation code
1458 		 * to call for DiskSet to release a diskset and have that
1459 		 * diskset not exist. During a diskset removal DiskSuite
1460 		 * maybe able to remove all traces of the diskset before
1461 		 * the reservation code execs metaset -C release in which
1462 		 * case the metasetname will fail, but the overall command
1463 		 * shouldn't.
1464 		 */
1465 		if (vers.major == 3)
1466 			md_exit(sp, 0);
1467 		else {
1468 			mde_perror(ep, "");
1469 			md_exit(sp, 1);
1470 		}
1471 	}
1472 
1473 	if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1474 		mde_perror(ep, "");
1475 		md_exit(sp, 1);
1476 	}
1477 
1478 	if (sd->sd_flags & MD_SR_AUTO_TAKE) {
1479 		md_eprintf(gettext("cannot release auto-take diskset\n"));
1480 		md_exit(sp, 1);
1481 	}
1482 
1483 	if (meta_lock_nowait(sp, ep) != 0) {
1484 		mde_perror(ep, "");
1485 		md_exit(sp, 10);	/* special errcode */
1486 	}
1487 
1488 	if (meta_set_release(sp, ep)) {
1489 		mde_perror(ep, "");
1490 		md_exit(sp, 1);
1491 	}
1492 	md_exit(sp, 0);
1493 }
1494 
1495 /* Should never be called with sname of a Multinode diskset. */
1496 static void
1497 parse_takeset(int argc, char **argv)
1498 {
1499 	int		c;
1500 	mdsetname_t	*sp = NULL;
1501 	int		flags = 0;
1502 	char		*sname = MD_LOCAL_NAME;
1503 	mhd_mhiargs_t	mhiargs;
1504 	char 		*cp = NULL;
1505 	int		pos = -1;	/* position of timeout value */
1506 	int		usetag = 0;
1507 	static char	*nullopts[] = { NULL };
1508 	md_error_t	status = mdnullerror;
1509 	md_error_t	*ep = &status;
1510 	sdssc_boolean_e	cluster_take = SDSSC_False;
1511 	sdssc_version_t	vers;
1512 	rval_e		rval;
1513 
1514 	/* reset and parse args */
1515 	optind = 1;
1516 	opterr = 1;
1517 	while ((c = getopt(argc, argv, "C:fs:tu:y")) != -1) {
1518 		switch (c) {
1519 		case 'C':
1520 			cluster_take = SDSSC_True;
1521 			break;
1522 		case 'f':
1523 			flags |= TAKE_FORCE;
1524 			break;
1525 		case 's':
1526 			sname = optarg;
1527 			break;
1528 		case 't':
1529 			break;
1530 		case 'u':
1531 			usetag = atoi(optarg);
1532 			flags |= TAKE_USETAG;
1533 			break;
1534 		case 'y':
1535 			flags |= TAKE_USEIT;
1536 			break;
1537 		default:
1538 			usage(sp, gettext("unknown options"));
1539 		}
1540 	}
1541 
1542 	mhiargs = defmhiargs;
1543 
1544 	argc -= optind;
1545 	argv += optind;
1546 
1547 	if (argc > 1)
1548 		usage(sp, gettext("too many args"));
1549 
1550 	/*
1551 	 * If we have a list of timeout value overrides, handle it here
1552 	 */
1553 	while (argv[0] != NULL && *argv[0] != '\0') {
1554 		/*
1555 		 * The use of the nullopts[] "token list" here is to make
1556 		 * getsubopts() simply parse a comma separated list
1557 		 * returning either "" or the contents of the field, the
1558 		 * end condition is exaustion of the initial string, which
1559 		 * is modified in the process.
1560 		 */
1561 		(void) getsubopt(&argv[0], nullopts, &cp);
1562 
1563 		c = 0;			/* re-use c as temp value of timeout */
1564 
1565 		if (*cp != '-')		/* '-' uses default */
1566 			c = atoi(cp);
1567 
1568 		if (c < 0) {
1569 			usage(sp, gettext(
1570 			    "time out values must be > 0"));
1571 		}
1572 
1573 		if (++pos > 3) {
1574 			usage(sp, gettext(
1575 			    "too many timeout values specified."));
1576 		}
1577 
1578 		if (c == 0)		/* 0 or "" field uses default */
1579 			continue;
1580 
1581 		/*
1582 		 * Assign temp value to appropriate structure member based on
1583 		 * its position in the comma separated list.
1584 		 */
1585 		switch (pos) {
1586 		    case 0:
1587 			mhiargs.mh_ff = c;
1588 			break;
1589 
1590 		    case 1:
1591 			mhiargs.mh_tk.reinstate_resv_delay = c;
1592 			break;
1593 
1594 		    case 2:
1595 			mhiargs.mh_tk.min_ownership_delay = c;
1596 			break;
1597 
1598 		    case 3:
1599 			mhiargs.mh_tk.max_ownership_delay = c;
1600 			break;
1601 		}
1602 	}
1603 
1604 	memset(&vers, 0, sizeof (vers));
1605 
1606 	if ((sdssc_version(&vers) == SDSSC_OKAY) &&
1607 	    (vers.major == 3) &&
1608 	    (cluster_take == SDSSC_False)) {
1609 
1610 		/*
1611 		 * If the take is beging done by the user via the CLI we need
1612 		 * to notify the DCS to make this current node the primary.
1613 		 * The SC3.0 reservation code will in turn exec metaset with
1614 		 * the -C take arg to complete this operation.
1615 		 */
1616 		if ((rval = sdssc_notify_service(sname, Make_Primary)) ==
1617 		    SDSSC_ERROR) {
1618 			printf(gettext(
1619 			    "metaset: failed to notify DCS of take\n"));
1620 		}
1621 		md_exit(NULL, rval == SDSSC_ERROR);
1622 	}
1623 
1624 	if ((sp = metasetname(sname, ep)) == NULL) {
1625 		mde_perror(ep, "");
1626 		md_exit(sp, 1);
1627 	}
1628 
1629 	if ((vers.major == 3) && (meta_check_ownership(sp, ep) == 0)) {
1630 
1631 		/*
1632 		 * If we're running in a cluster environment and this
1633 		 * node already owns the set. Don't bother trying to
1634 		 * take the set again. There's one case where an adminstrator
1635 		 * is adding disks to a set for the first time. metaset
1636 		 * will take the ownership of the set at that point. During
1637 		 * that add operation SC3.0 notices activity on the device
1638 		 * and also tries to perform a take operation. The SC3.0 take
1639 		 * will fail because the adminstrative add has the set locked
1640 		 */
1641 		md_exit(sp, 0);
1642 	}
1643 
1644 	if (meta_lock_nowait(sp, ep) != 0) {
1645 		mde_perror(ep, "");
1646 		md_exit(sp, 10);	/* special errcode */
1647 	}
1648 
1649 	if (meta_set_take(sp, &mhiargs, flags, usetag, &status)) {
1650 		mde_perror(&status, "");
1651 		if (mdismddberror(&status, MDE_DB_TAGDATA))
1652 			md_exit(sp, 2);
1653 		if (mdismddberror(&status, MDE_DB_ACCOK))
1654 			md_exit(sp, 3);
1655 		if (mdismddberror(&status, MDE_DB_STALE))
1656 			md_exit(sp, 66);
1657 		md_exit(sp, 1);
1658 	}
1659 	md_exit(sp, 0);
1660 }
1661 
1662 /*
1663  * Joins a node to a specific set or to all multinode disksets known
1664  * by this node.  If set is specified then caller should have verified
1665  * that the set is a multinode diskset.
1666  *
1667  * If an error occurs, metaset exits with a 1.
1668  * If there is no error, metaset exits with a 0.
1669  */
1670 static void
1671 parse_joinset(int argc, char **argv)
1672 {
1673 	int		c;
1674 	mdsetname_t	*sp = NULL, *local_sp = NULL;
1675 	char		*sname = MD_LOCAL_NAME;
1676 	md_error_t	status = mdnullerror;
1677 	md_error_t	*ep = &status;
1678 	md_set_desc	*sd;
1679 	char		buf[BUFSIZ];
1680 	char		*p = buf;
1681 	set_t		max_sets, setno;
1682 	int		err, cumm_err = 0;
1683 	size_t		bufsz;
1684 
1685 	bufsz = sizeof (buf);
1686 	/* reset and parse args */
1687 	optind = 1;
1688 	opterr = 1;
1689 	while ((c = getopt(argc, argv, "Ms:j")) != -1) {
1690 		switch (c) {
1691 		case 'M':
1692 			break;
1693 		case 'j':
1694 			break;
1695 		case 's':
1696 			sname = optarg;
1697 			break;
1698 		default:
1699 			usage(sp, gettext("unknown options"));
1700 		}
1701 	}
1702 
1703 	argc -= optind;
1704 	argv += optind;
1705 
1706 	if (argc > 1)
1707 		usage(sp, gettext("too many args"));
1708 
1709 	/*
1710 	 * If no setname option was used, then join all disksets
1711 	 * that this node knows about.   Attempt to join all
1712 	 * disksets that this node knows about.
1713 	 *
1714 	 * Additional text is added to the error messages during
1715 	 * this section of code in order to help the user understand
1716 	 * why the 'join of all sets' failed and which set caused
1717 	 * the failure.
1718 	 */
1719 
1720 	/*
1721 	 * Hold local set lock throughout this call to keep
1722 	 * other actions from interfering (such as creating a new
1723 	 * set, etc.).
1724 	 */
1725 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
1726 		mde_perror(ep, "");
1727 		md_exit(sp, 1);
1728 	}
1729 
1730 	if (meta_lock(local_sp, TRUE, ep) != 0) {
1731 		mde_perror(ep, "");
1732 		md_exit(local_sp, 1);
1733 	}
1734 
1735 	if (strcmp(sname, MD_LOCAL_NAME) == 0) {
1736 		/*
1737 		 * If no set name is given, then walk through all sets
1738 		 * on this node which could include:
1739 		 * 	- MN disksets
1740 		 *	- traditional disksets
1741 		 *	- non-existent disksets
1742 		 * Attempt to join the MN disksets.
1743 		 * If the join of one set fails, print out an error message
1744 		 * about that set and continue the walk.
1745 		 */
1746 		if ((max_sets = get_max_sets(ep)) == 0) {
1747 			mde_perror(ep, "");
1748 			md_exit(local_sp, 1);
1749 		}
1750 
1751 		/* Start walking through all possible disksets */
1752 		for (setno = 1; setno < max_sets; setno++) {
1753 			if ((sp = metasetnosetname(setno, ep)) == NULL) {
1754 				if (mdiserror(ep, MDE_NO_SET)) {
1755 					/* No set for this setno - continue */
1756 					mdclrerror(ep);
1757 					continue;
1758 				} else {
1759 					(void) sprintf(p, gettext(
1760 					"Unable to get set %d information"),
1761 					    setno);
1762 					mde_perror(ep, p);
1763 					cumm_err = 1;
1764 					mdclrerror(ep);
1765 					continue;
1766 				}
1767 			}
1768 
1769 			/* If setname is there, set desc should exist. */
1770 			if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1771 				(void) snprintf(p, bufsz, gettext(
1772 				    "Unable to get set %s desc information"),
1773 				    sp->setname);
1774 				mde_perror(ep, p);
1775 				cumm_err = 1;
1776 				mdclrerror(ep);
1777 				continue;
1778 			}
1779 
1780 			/* Only check MN disksets */
1781 			if (!MD_MNSET_DESC(sd)) {
1782 				continue;
1783 			}
1784 
1785 			/*
1786 			 * Return value of 0 is success.
1787 			 * Return value of -1 means a failure.
1788 			 * Return value of -2 means set could not be
1789 			 * joined, but shouldn't cause an error.
1790 			 * Reasons would be:
1791 			 * 	- no drives in set
1792 			 * 	- node already joined to set
1793 			 * Return value of -3 means joined stale set.
1794 			 * Can't check for all reasons here
1795 			 * since set isn't locked yet across all
1796 			 * nodes in the cluster.  The call
1797 			 * to libmeta routine, meta_set_join, will
1798 			 * lock across the cluster and perform
1799 			 * the checks.
1800 			 */
1801 			if ((err = meta_set_join(sp, ep)) == -1) {
1802 				/* Print error of diskset join failure */
1803 				(void) snprintf(p, bufsz,
1804 				    gettext("Join to diskset %s failed"),
1805 				    sp->setname);
1806 				mde_perror(ep, p);
1807 				cumm_err = 1;
1808 				mdclrerror(ep);
1809 				continue;
1810 			}
1811 
1812 			if (err == -3) {
1813 				/* Print error of diskset join failure */
1814 				(void) snprintf(p, bufsz,
1815 				    gettext("Joined to stale diskset %s"),
1816 				    sp->setname);
1817 				mde_perror(ep, p);
1818 				mdclrerror(ep);
1819 			}
1820 
1821 			mdclrerror(ep);
1822 		}
1823 
1824 		md_exit(local_sp, cumm_err);
1825 	}
1826 
1827 	/*
1828 	 * Code for a specific set is much simpler.
1829 	 * Error messages don't need extra text since specific setname
1830 	 * was used.
1831 	 * Don't need to lock the local set, just the specific set given.
1832 	 */
1833 	if ((sp = metasetname(sname, ep)) == NULL) {
1834 		mde_perror(ep, "");
1835 		md_exit(local_sp, 1);
1836 	}
1837 
1838 	/*
1839 	 * Fail command if meta_set_join returns -1.
1840 	 *
1841 	 * Return of 0 means that node joined set.
1842 	 *
1843 	 * Return of -2 means that node was unable to
1844 	 * join a set since that set had no drives
1845 	 * or that had already joined the set.  No
1846 	 * need to fail the command for these reasons.
1847 	 *
1848 	 * Return of -3 means that set is stale.
1849 	 * Return a value of 66 to historically match traditional disksets.
1850 	 */
1851 	if ((err = meta_set_join(sp, ep)) == -1) {
1852 		mde_perror(&status, "");
1853 		md_exit(local_sp, 1);
1854 	}
1855 
1856 	if (err == -3) {
1857 		/* Print error of diskset join failure */
1858 		(void) snprintf(p, bufsz,
1859 		    gettext("Joined to stale diskset %s"),
1860 		    sp->setname);
1861 		mde_perror(&status, "");
1862 		md_exit(local_sp, 66);
1863 	}
1864 
1865 	md_exit(local_sp, 0);
1866 }
1867 
1868 /*
1869  * Withdraws a node from a specific set or from all multinode disksets known
1870  * by this node.  If set is specified then caller should have verified
1871  * that the set is a multinode diskset.
1872  *
1873  * If an error occurs, metaset exits with a 1.
1874  * If there is no error, metaset exits with a 0.
1875  */
1876 static void
1877 parse_withdrawset(int argc, char **argv)
1878 {
1879 	int		c;
1880 	mdsetname_t	*sp = NULL, *local_sp = NULL;
1881 	char		*sname = MD_LOCAL_NAME;
1882 	md_error_t	status = mdnullerror;
1883 	md_error_t	*ep = &status;
1884 	char		buf[BUFSIZ];
1885 	char		*p = buf;
1886 	md_set_desc	*sd;
1887 	set_t		max_sets, setno;
1888 	int		err, cumm_err = 0;
1889 	size_t		bufsz;
1890 
1891 	bufsz = sizeof (buf);
1892 	/* reset and parse args */
1893 	optind = 1;
1894 	opterr = 1;
1895 	while ((c = getopt(argc, argv, "Ms:w")) != -1) {
1896 		switch (c) {
1897 		case 'M':
1898 			break;
1899 		case 'w':
1900 			break;
1901 		case 's':
1902 			sname = optarg;
1903 			break;
1904 		default:
1905 			usage(sp, gettext("unknown options"));
1906 		}
1907 	}
1908 
1909 	argc -= optind;
1910 	argv += optind;
1911 
1912 	if (argc > 1)
1913 		usage(sp, gettext("too many args"));
1914 
1915 	/*
1916 	 * If no setname option was used, then withdraw from all disksets
1917 	 * that this node knows about.
1918 	 *
1919 	 * Additional text is added to the error messages during
1920 	 * this section of code in order to help the user understand
1921 	 * why the 'withdraw from all sets' failed and which set caused
1922 	 * the failure.
1923 	 */
1924 
1925 	/*
1926 	 * Hold local set lock throughout this call to keep
1927 	 * other actions from interfering (such as creating a new
1928 	 * set, etc.).
1929 	 */
1930 	if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
1931 		mde_perror(ep, "");
1932 		md_exit(sp, 1);
1933 	}
1934 
1935 	if (meta_lock(local_sp, TRUE, ep) != 0) {
1936 		mde_perror(ep, "");
1937 		md_exit(local_sp, 1);
1938 	}
1939 
1940 	if (strcmp(sname, MD_LOCAL_NAME) == 0) {
1941 		/*
1942 		 * If no set name is given, then walk through all sets
1943 		 * on this node which could include:
1944 		 * 	- MN disksets
1945 		 *	- traditional disksets
1946 		 *	- non-existent disksets
1947 		 * Attempt to withdraw from the MN disksets.
1948 		 * If the withdraw of one set fails, print out an error
1949 		 * message about that set and continue the walk.
1950 		 */
1951 		if ((max_sets = get_max_sets(ep)) == 0) {
1952 			mde_perror(ep, "");
1953 			md_exit(local_sp, 1);
1954 		}
1955 
1956 		/* Start walking through all possible disksets */
1957 		for (setno = 1; setno < max_sets; setno++) {
1958 			if ((sp = metasetnosetname(setno, ep)) == NULL) {
1959 				if (mdiserror(ep, MDE_NO_SET)) {
1960 					/* No set for this setno - continue */
1961 					mdclrerror(ep);
1962 					continue;
1963 				} else {
1964 					(void) sprintf(p, gettext(
1965 					    "Unable to get set %d information"),
1966 					    setno);
1967 					mde_perror(ep, p);
1968 					cumm_err = 1;
1969 					mdclrerror(ep);
1970 					continue;
1971 				}
1972 			}
1973 
1974 			/* If setname is there, set desc should exist. */
1975 			if ((sd = metaget_setdesc(sp, ep)) == NULL) {
1976 				(void) snprintf(p, bufsz, gettext(
1977 				    "Unable to get set %s desc information"),
1978 				    sp->setname);
1979 				mde_perror(ep, p);
1980 				cumm_err = 1;
1981 				mdclrerror(ep);
1982 				continue;
1983 			}
1984 
1985 			/* Only check MN disksets */
1986 			if (!MD_MNSET_DESC(sd)) {
1987 				continue;
1988 			}
1989 
1990 			/*
1991 			 * Return value of 0 is success.
1992 			 * Return value of -1 means a failure.
1993 			 * Return value of -2 means set could not be
1994 			 * withdrawn from, but this shouldn't cause
1995 			 * an error.  Reasons would be:
1996 			 * 	- no drives in set
1997 			 * 	- node already withdrawn from set
1998 			 * Can't check for all reasons here
1999 			 * since set isn't locked yet across all
2000 			 * nodes in the cluster.  The call
2001 			 * to libmeta routine, meta_set_withdraw, will
2002 			 * lock across the cluster and perform
2003 			 * the checks.
2004 			 */
2005 			if ((err = meta_set_withdraw(sp, ep)) == -1) {
2006 				/* Print error of diskset withdraw failure */
2007 				(void) snprintf(p, bufsz,
2008 				    gettext("Withdraw from diskset %s failed"),
2009 				    sp->setname);
2010 				mde_perror(ep, p);
2011 				mdclrerror(ep);
2012 				cumm_err = 1;
2013 				continue;
2014 			}
2015 
2016 			if (err == -2) {
2017 				mdclrerror(ep);
2018 				continue;
2019 			}
2020 
2021 			mdclrerror(ep);
2022 		}
2023 		md_exit(local_sp, cumm_err);
2024 	}
2025 
2026 
2027 	/*
2028 	 * Code for a specific set is much simpler.
2029 	 * Error messages don't need extra text since specific setname
2030 	 * was used.
2031 	 * Don't need to lock the local set, just the specific set given.
2032 	 */
2033 	if ((sp = metasetname(sname, ep)) == NULL) {
2034 		mde_perror(ep, "");
2035 		md_exit(local_sp, 1);
2036 	}
2037 
2038 	/*
2039 	 * Fail command if meta_set_withdraw returns -1.
2040 	 *
2041 	 * Return of 0 means that node withdrew from set.
2042 	 *
2043 	 * Return of -2 means that node was unable to
2044 	 * withdraw from a set since that set had no drives
2045 	 * or node was not joined to set.  No
2046 	 * need to fail the command for these reasons.
2047 	 */
2048 	if (meta_set_withdraw(sp, ep) == -1) {
2049 		mde_perror(&status, "");
2050 		md_exit(local_sp, 1);
2051 	}
2052 
2053 	md_exit(local_sp, 0);
2054 }
2055 
2056 /*
2057  * Should never be called with sname of a Multinode diskset.
2058  */
2059 static void
2060 parse_cluster(int argc, char **argv)
2061 {
2062 	int			c,
2063 				error,
2064 				new_argc,
2065 				x;
2066 	enum cluster_cmd	cmd = ccnotspecified;
2067 	char			*hostname = SDSSC_PROXY_PRIMARY,
2068 				*argument = NULL,
2069 				*sname = MD_LOCAL_NAME,
2070 				primary_node[SDSSC_NODE_NAME_LEN],
2071 				**new_argv = NULL,
2072 				**np = NULL;
2073 	mdsetname_t		*sp = NULL;
2074 	md_error_t		status = mdnullerror;
2075 	md_error_t		*ep = &status;
2076 
2077 	/* reset and parse args */
2078 	optind = 1;
2079 	opterr = 1;
2080 	while ((c = getopt(argc, argv, "C:s:h:ftu:yr")) != -1) {
2081 		switch (c) {
2082 		case 'C':
2083 			if (cmd != ccnotspecified) {
2084 				md_exit(sp, -1);
2085 			}
2086 			argument = optarg;
2087 
2088 			if (strcmp(argument, "disksin") == 0) {
2089 				cmd = clusterdisksin;
2090 			} else if (strcmp(argument, "version") == 0) {
2091 				cmd = clusterversion;
2092 			} else if (strcmp(argument, "release") == 0) {
2093 				cmd = clusterrelease;
2094 			} else if (strcmp(argument, "take") == 0) {
2095 				cmd = clustertake;
2096 			} else if (strcmp(argument, "proxy") == 0) {
2097 				cmd = clusterproxy;
2098 			} else if (strcmp(argument, "purge") == 0) {
2099 				cmd = clusterpurge;
2100 			} else {
2101 				md_exit(sp, -1);
2102 			}
2103 
2104 			break;
2105 
2106 		case 'h':
2107 			hostname = optarg;
2108 			break;
2109 
2110 		case 's':
2111 			sname = optarg;
2112 			break;
2113 
2114 		case 'f':
2115 		case 't':
2116 		case 'u':
2117 		case 'y':
2118 		case 'r':
2119 			break;
2120 
2121 		default:
2122 			md_exit(sp, -1);
2123 		}
2124 	}
2125 
2126 	/* Now call the appropriate command function. */
2127 	switch (cmd) {
2128 	case clusterversion:
2129 	    printclusterversion();
2130 	    break;
2131 
2132 	case clusterdisksin:
2133 	    if (printdisksin(sname, ep)) {
2134 		md_exit(sp, -1);
2135 	    }
2136 	    break;
2137 
2138 	case clusterrelease:
2139 	    parse_releaseset(argc, argv);
2140 	    break;
2141 
2142 	case clustertake:
2143 	    parse_takeset(argc, argv);
2144 	    break;
2145 
2146 	case clusterproxy:
2147 		/* Should never get here if sname is for MN diskset */
2148 
2149 		if ((new_argv = calloc(argc, sizeof (char *))) == NULL) {
2150 			printf(gettext("Out of memory\n"));
2151 			md_exit(sp, 1);
2152 		}
2153 
2154 		np = new_argv;
2155 		new_argc = 0;
2156 		memset(primary_node, '\0', SDSSC_NODE_NAME_LEN);
2157 
2158 		for (x = 0; x < argc; x++) {
2159 			if (strcmp(argv[x], "-C") == 0) {
2160 
2161 				/*
2162 				 * Need to skip the '-C proxy' args so
2163 				 * just increase x by one and the work is
2164 				 * done.
2165 				 */
2166 				x++;
2167 			} else {
2168 				*np++ = strdup(argv[x]);
2169 				new_argc++;
2170 			}
2171 		}
2172 
2173 		switch (sdssc_get_primary_host(sname, primary_node,
2174 		    SDSSC_NODE_NAME_LEN)) {
2175 		case SDSSC_ERROR:
2176 			md_exit(sp, 1);
2177 			break;
2178 
2179 		case SDSSC_NO_SERVICE:
2180 			if (hostname != SDSSC_PROXY_PRIMARY) {
2181 				(void) strlcpy(primary_node, hostname,
2182 				    SDSSC_NODE_NAME_LEN);
2183 			}
2184 			break;
2185 		}
2186 
2187 		if (sdssc_cmd_proxy(new_argc, new_argv,
2188 		    primary_node[0] == '\0' ? SDSSC_PROXY_PRIMARY :
2189 		    primary_node, &error) == SDSSC_PROXY_DONE) {
2190 			md_exit(sp, error);
2191 		} else {
2192 			printf(gettext(
2193 			    "Couldn't proxy command\n"));
2194 			md_exit(sp, 1);
2195 		}
2196 		break;
2197 
2198 	case clusterpurge:
2199 		parse_purge(argc, argv);
2200 		break;
2201 
2202 	default:
2203 	    break;
2204 	}
2205 
2206 	md_exit(sp, 0);
2207 }
2208 
2209 /*
2210  * parse args and do it
2211  */
2212 int
2213 main(int argc, char *argv[])
2214 {
2215 	enum metaset_cmd	cmd = notspecified;
2216 	md_error_t		status = mdnullerror;
2217 	md_error_t		*ep = &status;
2218 	mdsetname_t		*sp = NULL;
2219 	char			*hostname = SDSSC_PROXY_PRIMARY,
2220 				*sname = MD_LOCAL_NAME,
2221 				*auto_take_option = NULL,
2222 				primary_node[SDSSC_NODE_NAME_LEN];
2223 	int			error,
2224 				c,
2225 				auto_take = FALSE,
2226 				stat;
2227 	md_set_desc		*sd;
2228 	int			mflag = 0;
2229 	int			multi_node = 0;
2230 	rval_e			sdssc_res;
2231 
2232 	/*
2233 	 * Get the locale set up before calling any other routines
2234 	 * with messages to ouput.  Just in case we're not in a build
2235 	 * environment, make sure that TEXT_DOMAIN gets set to
2236 	 * something.
2237 	 */
2238 #if !defined(TEXT_DOMAIN)
2239 #define	TEXT_DOMAIN "SYS_TEST"
2240 #endif
2241 	(void) setlocale(LC_ALL, "");
2242 	(void) textdomain(TEXT_DOMAIN);
2243 
2244 	sdssc_res = sdssc_bind_library();
2245 	if (sdssc_res == SDSSC_ERROR) {
2246 		printf(gettext(
2247 		    "%s: Interface error with libsds_sc.so\n"), argv[0]);
2248 		exit(1);
2249 	}
2250 
2251 	/* initialize */
2252 	if (md_init(argc, argv, 0, 1, ep) != 0) {
2253 		mde_perror(ep, "");
2254 		md_exit(sp, 1);
2255 	}
2256 
2257 	optind = 1;
2258 	opterr = 1;
2259 
2260 	/*
2261 	 * NOTE: The "C" option is strictly for cluster use. it is not
2262 	 * and should not be documented for the customer. - JST
2263 	 */
2264 	while ((c = getopt(argc, argv, "C:MaA:bdfh:jl:Lm:oPqrs:tu:wy?"))
2265 	    != -1) {
2266 		switch (c) {
2267 		case 'M':
2268 			mflag = 1;
2269 			break;
2270 		case 'A':
2271 			auto_take = TRUE;
2272 			if (optarg == NULL || !(strcmp(optarg, "enable") == 0 ||
2273 			    strcmp(optarg, "disable") == 0))
2274 				usage(sp, gettext(
2275 				    "-A: enable or disable must be specified"));
2276 			auto_take_option = optarg;
2277 			break;
2278 		case 'a':
2279 			if (cmd != notspecified) {
2280 				usage(sp, gettext(
2281 				    "conflicting options"));
2282 			}
2283 			cmd = add;
2284 			break;
2285 		case 'b':
2286 			if (cmd != notspecified) {
2287 				usage(sp, gettext(
2288 				    "conflicting options"));
2289 			}
2290 			cmd = balance;
2291 			break;
2292 		case 'd':
2293 			if (cmd != notspecified) {
2294 				usage(sp, gettext(
2295 				    "conflicting options"));
2296 			}
2297 			cmd = delete;
2298 			break;
2299 		case 'C':	/* cluster commands */
2300 			if (cmd != notspecified) {
2301 				md_exit(sp, -1);    /* conflicting options */
2302 			}
2303 			cmd = cluster;
2304 			break;
2305 		case 'f':
2306 			break;
2307 		case 'h':
2308 			hostname = optarg;
2309 			break;
2310 		case 'j':
2311 			if (cmd != notspecified) {
2312 				usage(sp, gettext(
2313 				    "conflicting options"));
2314 			}
2315 			cmd = join;
2316 			break;
2317 		case 'l':
2318 			break;
2319 		case 'L':
2320 			break;
2321 		case 'm':
2322 			break;
2323 		case 'o':
2324 			if (cmd != notspecified) {
2325 				usage(sp, gettext(
2326 				    "conflicting options"));
2327 			}
2328 			cmd = isowner;
2329 			break;
2330 		case 'P':
2331 			if (cmd != notspecified) {
2332 				usage(sp, gettext(
2333 				    "conflicting options"));
2334 			}
2335 			cmd = purge;
2336 			break;
2337 		case 'q':
2338 			if (cmd != notspecified) {
2339 				usage(sp, gettext(
2340 				    "conflicting options"));
2341 			}
2342 			cmd = query;
2343 			break;
2344 		case 'r':
2345 			if (cmd != notspecified) {
2346 				usage(sp, gettext(
2347 				    "conflicting options"));
2348 			}
2349 			cmd = release;
2350 			break;
2351 		case 's':
2352 			sname = optarg;
2353 			break;
2354 		case 't':
2355 			if (cmd != notspecified) {
2356 				usage(sp, gettext(
2357 				    "conflicting options"));
2358 			}
2359 			cmd = take;
2360 			break;
2361 		case 'u':
2362 			break;
2363 		case 'w':
2364 			if (cmd != notspecified) {
2365 				usage(sp, gettext(
2366 				    "conflicting options"));
2367 			}
2368 			cmd = withdraw;
2369 			break;
2370 		case 'y':
2371 			break;
2372 		case '?':
2373 			if (optopt == '?')
2374 				usage(sp, NULL);
2375 			/*FALLTHROUGH*/
2376 		default:
2377 			if (cmd == cluster) {    /* cluster is silent */
2378 				md_exit(sp, -1);
2379 			} else {
2380 				usage(sp, gettext(
2381 				    "unknown command"));
2382 			}
2383 		}
2384 	}
2385 
2386 	/* check if suncluster is installed and -A enable specified */
2387 	if (auto_take && sdssc_res != SDSSC_NOT_BOUND &&
2388 	    strcmp(auto_take_option, "enable") == 0) {
2389 	    md_eprintf(gettext(
2390 		"cannot enable auto-take when SunCluster is installed\n"));
2391 	    md_exit(sp, 1);
2392 	}
2393 
2394 	/*
2395 	 * At this point we know that if the -A enable option is specified
2396 	 * for an auto-take diskset that SC is not installed on the machine, so
2397 	 * all of the sdssc calls will just be no-ops.
2398 	 */
2399 
2400 	/* list sets */
2401 	if (cmd == notspecified && auto_take == FALSE) {
2402 		parse_printset(argc, argv);
2403 		/*NOTREACHED*/
2404 	}
2405 
2406 	if (meta_check_root(ep) != 0) {
2407 		mde_perror(ep, "");
2408 		md_exit(sp, 1);
2409 	}
2410 
2411 	/* snarf MDDB */
2412 	if (meta_setup_db_locations(ep) != 0) {
2413 		mde_perror(ep, "");
2414 		md_exit(sp, 1);
2415 	}
2416 
2417 	/*
2418 	 * If sname is a diskset - check for multi_node.
2419 	 * It is possible for sname to not exist.
2420 	 */
2421 	if (strcmp(sname, MD_LOCAL_NAME)) {
2422 		if ((sp = metasetname(sname, ep)) != NULL) {
2423 			/* Set exists - check for MN diskset */
2424 			if ((sd = metaget_setdesc(sp, ep)) == NULL) {
2425 				mde_perror(ep, "");
2426 				md_exit(sp, 1);
2427 			}
2428 			if (MD_MNSET_DESC(sd)) {
2429 				/*
2430 				 * If a MN diskset always set multi_node
2431 				 * regardless of whether the -M option was
2432 				 * used or not (mflag).
2433 				 */
2434 				multi_node = 1;
2435 			} else {
2436 				/*
2437 				 * If a traditional diskset, mflag must
2438 				 * not be set.
2439 				 */
2440 				if (mflag) {
2441 					usage(sp, gettext(
2442 					    "-M option only allowed "
2443 					    "on multi-owner diskset"));
2444 				}
2445 			}
2446 		} else {
2447 			/*
2448 			 * Set name does not exist, set multi_node
2449 			 * based on -M option.
2450 			 */
2451 			if (mflag) {
2452 				multi_node = 1;
2453 			}
2454 		}
2455 	}
2456 
2457 	if (auto_take && multi_node) {
2458 		/* Can't mix multinode and auto-take on a diskset */
2459 		usage(sp,
2460 		    gettext("-A option not allowed on multi-owner diskset"));
2461 	}
2462 
2463 	/*
2464 	 * MN disksets don't use DCS clustering services, so
2465 	 * do not get primary_node for MN diskset since no command
2466 	 * proxying is done to Primary cluster node.  Do not proxy
2467 	 * MN diskset commands of join and withdraw when issued without
2468 	 * a valid setname.
2469 	 * For traditional disksets: proxy all commands except a take
2470 	 * and release.  Use first host listed as the host to send the
2471 	 * command to if there isn't already a primary
2472 	 */
2473 	if (strcmp(sname, MD_LOCAL_NAME) && (multi_node == 0) &&
2474 	    (cmd != take) && (cmd != release) &&
2475 	    (cmd != cluster) && (cmd != join) &&
2476 	    (cmd != withdraw) && (cmd != purge)) {
2477 		stat = sdssc_get_primary_host(sname, primary_node,
2478 		    SDSSC_NODE_NAME_LEN);
2479 		switch (stat) {
2480 			case SDSSC_ERROR:
2481 				return (0);
2482 
2483 			case SDSSC_NO_SERVICE:
2484 				if (hostname != SDSSC_PROXY_PRIMARY) {
2485 					(void) strlcpy(primary_node, hostname,
2486 					    SDSSC_NODE_NAME_LEN);
2487 				} else {
2488 					memset(primary_node, '\0',
2489 					    SDSSC_NODE_NAME_LEN);
2490 				}
2491 				break;
2492 		}
2493 
2494 		/*
2495 		 * We've got a complicated decision here regarding
2496 		 * the hostname. If we didn't get a primary host
2497 		 * and a host name wasn't supplied on the command line
2498 		 * then we need to revert to SDSSC_PROXY_PRIMARY. Otherwise
2499 		 * use what's been found.
2500 		 */
2501 		if (sdssc_cmd_proxy(argc, argv,
2502 		    primary_node[0] == '\0' ?
2503 			SDSSC_PROXY_PRIMARY : primary_node,
2504 		    &error) == SDSSC_PROXY_DONE) {
2505 			exit(error);
2506 		}
2507 	}
2508 
2509 	/* cluster-specific commands */
2510 	if (cmd == cluster) {
2511 		if (multi_node) {
2512 			/*
2513 			 * If a specific MN diskset is given, immediately
2514 			 * fail -C command.
2515 			 */
2516 			usage(sp, gettext(
2517 			    "-C option not allowed on multi-owner diskset"));
2518 		} else {
2519 			parse_cluster(argc, argv);
2520 			/*NOTREACHED*/
2521 		}
2522 	}
2523 
2524 	/* join MultiNode diskset */
2525 	if (cmd == join) {
2526 		/*
2527 		 * If diskset specified, verify that it exists
2528 		 * and is a multinode diskset.
2529 		 */
2530 		if (strcmp(sname, MD_LOCAL_NAME)) {
2531 			if ((sp = metasetname(sname, ep)) == NULL) {
2532 				mde_perror(ep, "");
2533 				md_exit(sp, 1);
2534 			}
2535 
2536 			if (!multi_node) {
2537 				usage(sp, gettext(
2538 				    "-j option only allowed on "
2539 				    "multi-owner diskset"));
2540 			}
2541 		}
2542 		/*
2543 		 * Start mddoors daemon here.
2544 		 * mddoors itself takes care there will be only one
2545 		 * instance running, so starting it twice won't hurt
2546 		 */
2547 		pclose(popen("/usr/lib/lvm/mddoors", "w"));
2548 		parse_joinset(argc, argv);
2549 		/*NOTREACHED*/
2550 	}
2551 
2552 	/* withdraw from MultiNode diskset */
2553 	if (cmd == withdraw) {
2554 		/*
2555 		 * If diskset specified, verify that it exists
2556 		 * and is a multinode diskset.
2557 		 */
2558 		if (strcmp(sname, MD_LOCAL_NAME)) {
2559 			if ((sp = metasetname(sname, ep)) == NULL) {
2560 				mde_perror(ep, "");
2561 				md_exit(sp, 1);
2562 			}
2563 
2564 			if (!multi_node) {
2565 				usage(sp, gettext(
2566 				    "-w option only allowed on "
2567 				    "multi-owner diskset"));
2568 			}
2569 		}
2570 		parse_withdrawset(argc, argv);
2571 		/*NOTREACHED*/
2572 	}
2573 
2574 	/* must have set for everything else */
2575 	if (strcmp(sname, MD_LOCAL_NAME) == 0)
2576 		usage(sp, gettext("setname must be specified"));
2577 
2578 	/* add hosts or drives */
2579 	if (cmd == add) {
2580 		/*
2581 		 * In the multi node case start mddoors daemon.
2582 		 * mddoors itself takes care there will be
2583 		 * only one instance running, so starting it twice won't hurt
2584 		 */
2585 		if (multi_node) {
2586 			pclose(popen("/usr/lib/lvm/mddoors", "w"));
2587 		}
2588 
2589 		parse_add(argc, argv);
2590 		/*NOTREACHED*/
2591 	}
2592 
2593 	/* re-balance the replicas */
2594 	if (cmd == balance) {
2595 		parse_balance(argc, argv);
2596 		/*NOTREACHED*/
2597 	}
2598 
2599 	/* delete hosts or drives */
2600 	if (cmd == delete) {
2601 		parse_del(argc, argv);
2602 		/*NOTREACHED*/
2603 	}
2604 
2605 	/* check ownership */
2606 	if (cmd == isowner) {
2607 		parse_isowner(argc, argv);
2608 		/*NOTREACHED*/
2609 	}
2610 
2611 	/* purge the diskset */
2612 	if (cmd == purge) {
2613 		parse_purge(argc, argv);
2614 		/*NOTREACHED*/
2615 	}
2616 
2617 	/* query for data marks */
2618 	if (cmd == query) {
2619 		parse_query(argc, argv);
2620 		/*NOTREACHED*/
2621 	}
2622 
2623 	/* release ownership */
2624 	if (cmd == release) {
2625 		if (multi_node) {
2626 			/* Can't release multinode diskset */
2627 			usage(sp, gettext(
2628 			    "-r option not allowed on multi-owner diskset"));
2629 		} else {
2630 			parse_releaseset(argc, argv);
2631 			/*NOTREACHED*/
2632 		}
2633 	}
2634 
2635 	/* take ownership */
2636 	if (cmd == take) {
2637 		if (multi_node) {
2638 			/* Can't take multinode diskset */
2639 			usage(sp, gettext(
2640 			    "-t option not allowed on multi-owner diskset"));
2641 		} else {
2642 			parse_takeset(argc, argv);
2643 			/*NOTREACHED*/
2644 		}
2645 	}
2646 
2647 	/* take ownership of auto-take sets */
2648 	if (auto_take) {
2649 		parse_autotake(argc, argv);
2650 		/*NOTREACHED*/
2651 	}
2652 
2653 	/*NOTREACHED*/
2654 	return (0);
2655 }
2656