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