xref: /titanic_50/usr/src/cmd/avs/dsw/iiadm.c (revision 78323854f26c30110c6477875241b76265792c09)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <errno.h>
29 #include <signal.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <values.h>
36 #include <locale.h>
37 #include <langinfo.h>
38 #include <sys/mman.h>
39 #include <sys/stat.h>
40 #include <sys/wait.h>
41 #include <strings.h>
42 #include <stdarg.h>
43 #include <ctype.h>
44 #include <math.h>
45 #include <sys/param.h>
46 #include <sys/mnttab.h>
47 #include <nsctl.h>
48 #include <netdb.h>
49 #include <search.h>
50 
51 #include <sys/nsctl/cfg.h>
52 #include <sys/nsctl/nsc_hash.h>
53 
54 #include <sys/unistat/spcs_s.h>
55 #include <sys/unistat/spcs_s_u.h>
56 #include <sys/unistat/spcs_errors.h>
57 #include <sys/nsctl/dsw.h>
58 #include <sys/nsctl/dsw_dev.h>		/* for bit map header format */
59 
60 #include <sys/nskernd.h>
61 
62 typedef struct mstcount_s {
63 	int count;
64 } mstcount_t;
65 typedef struct shdvol_s {
66 	char master[ DSW_NAMELEN ];
67 } shdvol_t;
68 typedef struct grptag_s {
69 	char ctag[ DSW_NAMELEN ];
70 } grptag_t;
71 hash_node_t **volhash = NULL;
72 
73 #define	DSW_TEXT_DOMAIN	"II"
74 
75 #include <dlfcn.h>
76 #define	RDC_LIB "/usr/lib/librdc.so.1"
77 static int (*self_check)(char *);
78 
79 /*
80  * Support for the special cluster tag "local" to be used with -C in a
81  * cluster for local volumes.
82  */
83 #define	II_LOCAL_TAG	"local"
84 
85 #define	II_NOT_CLUSTER	1
86 #define	II_CLUSTER	2
87 #define	II_CLUSTER_LCL	3
88 
89 static char *cfg_cluster_tag = NULL;
90 static CFGFILE *cfg = NULL;
91 
92 void sigterm(int sig);
93 
94 #define	SD_BIT_CLR(bmap, bit)		(bmap &= ~(1 << bit))
95 #define	SD_BIT_ISSET(bmap, bit)		((bmap & (1 << bit)) != 0)
96 
97 #define	MAX_LINE_SIZE 256	/* maximum characters per line in config file */
98 #define	MAX_GROUPS 1024		/* maximum number of groups to support */
99 #define	MAX_CLUSTERS 1024	/* maximum number of resource groups */
100 
101 unsigned long	bm_size;		/* size in bytes of bitmap */
102 unsigned long	bm_actual;		/* original number of bits in bitmap */
103 int	debug = 0;
104 
105 int	dsw_fd;
106 
107 #define	LD_II		0x00000001
108 #define	LD_DSVOLS	0x00000002
109 #define	LD_SVOLS	0x00000004
110 #define	LD_SHADOWS	0x00000008
111 
112 static int reload_vols = 0;
113 static int config_locked = 0;
114 static int last_lock;
115 
116 /*
117  * names for do_copy() flags.
118  */
119 
120 enum	copy_update {Copy = 0, Update};
121 enum	copy_direction {ToShadow = 0, ToMaster};
122 enum	copy_wait {WaitForStart = 0, WaitForEnd};
123 
124 char	*cmdnam;
125 
126 unsigned char	*allocate_bitmap(char *);
127 void		usage(char *);
128 void		enable(char *, char *, char *, char *);
129 int		disable(char *);
130 void		bitmap_op(char *, int, int, int, int);
131 void		print_status(dsw_config_t *, int);
132 int		abort_copy(char *);
133 int		reset(char *);
134 int		overflow(char *);
135 void		iiversion(void);
136 int		wait_for_copy(char *);
137 int		export(char *);
138 void		list_volumes(void);
139 void		dsw_error(char *, spcs_s_info_t *);
140 void		InitEnv();
141 static void	check_dg_is_local(char *dgname);
142 static int	check_resource_group(char *volume);
143 static int	check_diskgroup(char *path, char *result);
144 static int	check_cluster();
145 static void	unload_ii_vols();
146 static void	load_ii_vols(CFGFILE *);
147 static int	perform_autosv();
148 static int	is_exported(char *);
149 static void	conform_name(char **);
150 static void	do_attach(dsw_config_t *);
151 static int	ii_lock(CFGFILE *, int);
152 static void	verify_groupname(char *grp, int testDash);
153 
154 void	dsw_list_clusters(char *);
155 void	dsw_enable(int, char **);
156 void	dsw_disable(int, char **);
157 void	dsw_copy_to_shadow(int, char **);
158 void	dsw_update_shadow(int, char **);
159 void	dsw_copy_to_master(int, char **);
160 void	dsw_update_master(int, char **);
161 void	dsw_abort_copy(int, char **);
162 void	dsw_display_status(int, char **);
163 void	dsw_display_bitmap(int, char **);
164 void	dsw_reset(int, char **);
165 void	dsw_overflow(int, char **);
166 void	dsw_version(int, char **);
167 void	dsw_wait(int, char **);
168 void	dsw_list_volumes(int, char **);
169 void	dsw_list_group_volumes();
170 void	dsw_export(int, char **);
171 void	dsw_import(int, char **);
172 void	dsw_join(int, char **);
173 void	dsw_attach(int, char **);
174 void	dsw_detach(int, char **);
175 void	dsw_params(int, char **);
176 void	dsw_olist(int, char **);
177 void	dsw_ostat(int, char **);
178 void	dsw_move_2_group(int, char **);
179 void	dsw_list_groups();
180 void	check_iishadow(char *);
181 
182 extern char *optarg;
183 extern int optind, opterr, optopt;
184 
185 int	Aflg;
186 int	Cflg;
187 int	CLflg;
188 int	Dflg;
189 int	Eflg;
190 int	Iflg;
191 int	Jflg;
192 int	Lflg;
193 int	Oflg;
194 int	Pflg;
195 int	Qflg;
196 int	Rflg;
197 int	aflg;
198 int	bflg;
199 int	cflg;
200 int	dflg;
201 int	eflg;
202 int	fflg;
203 int	gflg;
204 int	gLflg;
205 int	hflg;
206 int	iflg;
207 int	lflg;
208 int	mflg;
209 int	nflg;
210 int	pflg;
211 int	uflg;
212 int	vflg;
213 int	wflg;
214 
215 int	errflg;
216 #ifdef DEBUG
217 const char single_opts[] =
218 	"a:b:c:d:e:f:g:hilmnpu:vw:A:C:D:E:I:J:LO:PQ:R:";
219 #else
220 /* no b or f flags */
221 const char single_opts[] = "a:c:d:e:g:hilmnpu:vw:A:C:D:E:I:J:LO:PQ:R:";
222 #endif
223 const char group_opts[] = "ac:de:ilmnpu:wA:C:DELPR";
224 const char *opt_list = single_opts;
225 
226 char	buf[CFG_MAX_BUF];
227 char	key[CFG_MAX_KEY];
228 char	last_overflow[DSW_NAMELEN];
229 int	setnumber;
230 char	*group_name;
231 char	**group_volumes;
232 enum copy_direction direction;
233 char	*param_delay, *param_unit;
234 char	*overflow_file;
235 
236 #ifdef lint
237 int
238 iiadm_lintmain(int argc, char *argv[])
239 #else
240 int
241 main(int argc, char *argv[])
242 #endif
243 {
244 	int c;
245 	int actions = 0;
246 	int ac;
247 	char *av[1024];
248 
249 	InitEnv();
250 
251 	memset(av, 0, sizeof (av));
252 	cmdnam = argv[0];
253 	while ((c = getopt(argc, argv, opt_list)) != EOF)
254 		switch (c) {
255 		case 'c':
256 			cflg++;
257 			actions++;
258 			if (strcmp(optarg, "m") == 0) {
259 				av[0] = "copy_to_master";
260 				direction = ToMaster;
261 			} else if (strcmp(optarg, "s") == 0) {
262 				av[0] = "copy_to_shadow";
263 				direction = ToShadow;
264 			} else {
265 				errflg ++;
266 				usage(gettext(
267 					"must specify m or s with -c"));
268 			}
269 			ac = 2;
270 			break;
271 		case 'd':
272 			dflg++;
273 			actions++;
274 			av[0] = "disable";
275 			av[1] = optarg;
276 			ac = 2;
277 			break;
278 		case 'e':
279 			eflg++;
280 			actions++;
281 			av[0] = "enable";
282 			if (strcmp(optarg, "ind") == 0)
283 				av[4] = "independent";
284 			else if (strcmp(optarg, "dep") == 0)
285 				av[4] = "dependent";
286 			else {
287 				errflg ++;
288 				usage(gettext(
289 					"must specify ind or dep with -e"));
290 			}
291 			ac = 1;
292 			break;
293 		case 'g':
294 			gflg++;
295 			opt_list = group_opts;
296 			group_name = optarg;
297 			if (group_name && *group_name == '-') {
298 				gLflg = (strcmp("-L", group_name) == 0);
299 				if (gLflg)
300 					actions++;
301 			}
302 			verify_groupname(group_name, !gLflg);
303 			break;
304 		case 'h':
305 			hflg++;
306 			actions++;
307 			break;
308 		case 'u':
309 			uflg++;
310 			actions++;
311 			if (strcmp(optarg, "m") == 0) {
312 				av[0] = "update_master";
313 				direction = ToMaster;
314 			} else if (strcmp(optarg, "s") == 0) {
315 				av[0] = "update_shadow";
316 				direction = ToShadow;
317 			} else {
318 				errflg ++;
319 				usage(gettext(
320 					"must specify m or s with -u"));
321 			}
322 			ac = 2;
323 			break;
324 		case 'i':
325 			iflg++;
326 			actions++;
327 			av[0] = "display_status";
328 			break;
329 		case 'l':
330 			lflg++;
331 			actions++;
332 			av[0] = "list_config";
333 			ac = 1;
334 			break;
335 		case 'm':
336 			mflg++;
337 			actions++;
338 			av[0] = "move_to_group";
339 			ac = 1;
340 			break;
341 		case 'n':
342 			nflg++;
343 			break;
344 		case 'p':
345 			pflg++;
346 			break;
347 		case 'b':
348 			bflg++;
349 			actions++;
350 			av[0] = "display_bitmap";
351 			av[1] = optarg;
352 			ac = 2;
353 			break;
354 		case 'a':
355 			aflg++;
356 			actions++;
357 			av[0] = "abort_copy";
358 			av[1] = optarg;
359 			ac = 2;
360 			break;
361 		case 'v':
362 			vflg++;
363 			actions++;
364 			av[1] = "version";
365 			ac = 1;
366 			break;
367 		case 'w':
368 			wflg++;
369 			actions++;
370 			av[0] = "wait";
371 			av[1] = optarg;
372 			ac = 2;
373 			break;
374 		case 'A':
375 			Aflg++;
376 			actions++;
377 			av[0] = "attach";
378 			av[1] = optarg;
379 			ac = 2;
380 			break;
381 		case 'C':
382 			Cflg++;
383 			cfg_cluster_tag = optarg;
384 			if (cfg_cluster_tag && *cfg_cluster_tag == '-') {
385 				CLflg = (strcmp("-L", cfg_cluster_tag) == 0);
386 				if (CLflg)
387 					actions++;
388 			}
389 			break;
390 		case 'D':
391 			Dflg++;
392 			actions++;
393 			av[0] = "detach";
394 			av[1] = optarg;
395 			ac = 2;
396 			break;
397 		case 'O':
398 			Oflg++;
399 			actions++;
400 			av[0] = "overflow";
401 			av[1] = optarg;
402 			ac = 2;
403 			break;
404 		case 'R':
405 			Rflg++;
406 			actions++;
407 			av[0] = "reset";
408 			av[1] = optarg;
409 			ac = 2;
410 			break;
411 		case 'E':
412 			Eflg++;
413 			actions++;
414 			av[0] = "export";
415 			av[1] = optarg;
416 			ac = 2;
417 			break;
418 		case 'I':
419 			Iflg++;
420 			actions++;
421 			av[0] = "import";
422 			av[1] = optarg;
423 			ac = 2;
424 			break;
425 		case 'J':
426 			Jflg++;
427 			actions++;
428 			av[0] = "join";
429 			av[1] = optarg;
430 			ac = 2;
431 			break;
432 		case 'P':
433 			Pflg++;
434 			actions++;
435 			av[0] = "parameter";
436 			ac = 1;
437 			break;
438 		case 'L':
439 			Lflg++;
440 			actions++;
441 			/* If -g group -L, force error */
442 			if (group_name) actions++;
443 			av[0] = "LIST";
444 			ac = 1;
445 			break;
446 		case 'Q':
447 			Qflg++;
448 			actions++;
449 			av[0] = "query";
450 			av[1] = optarg;
451 			ac = 2;
452 			break;
453 		case '?':
454 			errflg++;
455 			break;
456 		}
457 	if (hflg) {
458 		usage(NULL);
459 		exit(0);
460 		}
461 
462 	if (errflg)
463 		usage(gettext("unrecognized argument"));
464 	switch (actions) {
465 		case 0:
466 			if (argc > 1)
467 				usage(gettext("must specify an action flag"));
468 
469 			/* default behavior is to list configuration */
470 			lflg++; av[0] = "list_config"; ac = 1;
471 			break;
472 		case 1:
473 			break;
474 		default:
475 			usage(gettext("too many action flags"));
476 			break;
477 	}
478 
479 	if (gflg && (Iflg || Jflg || Oflg || Qflg))
480 		usage(gettext("can't use a group with this option"));
481 	if (!gflg && (mflg))
482 		usage(gettext("must use a group with this option"));
483 
484 	/*
485 	 * Open configuration file.
486 	 */
487 	if ((cfg = cfg_open(NULL)) == NULL) {
488 		perror("unable to access configuration");
489 		exit(2);
490 	}
491 
492 	/*
493 	 * Set write locking (CFG_WRLOCK) for:
494 	 *	iiadm -e (enable)
495 	 * 	iiadm -d (disable)
496 	 *	iiadm -A (attach overflow)
497 	 *	iiadm -D (detach overflow)
498 	 *	iiadm -g grp -m volume (move volume into group)
499 	 *	iiadm -E (export shadow [needs to update dsvol section])
500 	 *	iiadm -I (import shadow [ditto])
501 	 *	iiadm -J (join shadow [ditto])
502 	 * read locking (CFG_RDLOCK) for all other commands
503 	 */
504 	last_lock = (eflg || dflg || mflg || Aflg || Dflg || Eflg || Iflg ||
505 	    Jflg)? CFG_WRLOCK : CFG_RDLOCK;
506 	if (!cfg_lock(cfg, last_lock)) {
507 		perror("unable to lock configuration");
508 		exit(2);
509 	}
510 	config_locked = 1;
511 
512 	/*
513 	 * If we are in a cluster, set or derive a valid disk group
514 	 */
515 	switch (check_cluster()) {
516 	case II_CLUSTER:
517 		/*
518 		 * If in a Sun Cluster, can't Import an II shadow
519 		 * Must be done as -C local
520 		 */
521 		if (Iflg)
522 			dsw_error(gettext(
523 				"-I (import) only allowed as -C local"), NULL);
524 		/*FALLTHRU*/
525 	case II_CLUSTER_LCL:
526 		/*
527 		 * If a cluster tag was specified or derived, set it
528 		 */
529 		if (CLflg) {
530 			dsw_list_clusters(argv[optind]);
531 			cfg_close(cfg);
532 			exit(0);
533 		} else {
534 			cfg_resource(cfg, cfg_cluster_tag);
535 		}
536 		break;
537 	case II_NOT_CLUSTER:
538 		if (cfg_cluster_tag != NULL)
539 			dsw_error(gettext(
540 			    "-C is valid only in a Sun Cluster"), NULL);
541 		break;
542 	default:
543 		dsw_error(gettext(
544 		    "Unexpected return from check_cluster()"), NULL);
545 	}
546 
547 	/* preload the ii config */
548 	load_ii_vols(cfg);
549 	reload_vols |= LD_II;
550 
551 	if (eflg) {
552 		if (argc - optind != 3)
553 			usage(gettext("must specify 3 volumes with -e"));
554 		av[1] = argv[optind++];
555 		av[2] = argv[optind++];
556 		av[3] = argv[optind++];
557 		ac = 5;
558 		dsw_enable(ac, av);
559 	} else if (dflg) {
560 		dsw_disable(ac, av);
561 	} else if (uflg) {
562 		if (argv[optind] == NULL && group_name == NULL)
563 			usage(gettext("must specify volume with -u"));
564 		for (c = 1; argv[optind] != NULL; optind++)
565 			av[c++] = argv[optind];
566 		av[c] = NULL;
567 
568 		if (direction == ToMaster)
569 			dsw_update_master(ac, av);
570 		else
571 			dsw_update_shadow(ac, av);
572 	} else if (iflg) {
573 		if (argv[optind]) {
574 			av[1] = argv[optind];
575 			ac = 2;
576 		} else
577 			ac = 1;
578 		dsw_display_status(ac, av);
579 	} else if (bflg) {
580 		dsw_display_bitmap(ac, av);
581 	} else if (cflg) {
582 		if (argv[optind] == NULL && group_name == NULL)
583 			usage(gettext("must specify volume with -c"));
584 		for (c = 1; argv[optind] != NULL; optind++)
585 			av[c++] = argv[optind];
586 		av[c] = NULL;
587 
588 		if (direction == ToMaster)
589 			dsw_copy_to_master(ac, av);
590 		else
591 			dsw_copy_to_shadow(ac, av);
592 	} else if (aflg) {
593 		dsw_abort_copy(ac, av);
594 	} else if (Eflg) {
595 		dsw_export(ac, av);
596 	} else if (Iflg) {
597 		if (argc - optind != 1)
598 			usage(gettext("must specify 2 volumes with -I"));
599 		av[2] = argv[optind++];
600 		ac = 3;
601 		dsw_import(ac, av);
602 	} else if (Aflg) {
603 		if (group_name) {
604 			if (argc - optind != 0)
605 				usage(gettext("must specify overflow volume " \
606 				"when using groups with -A"));
607 			ac = 2;
608 		} else {
609 			if (argc - optind != 1)
610 				usage(gettext("specify 2 volumes with -A"));
611 			ac = 3;
612 			av[2] = argv[optind++];
613 		}
614 		dsw_attach(ac, av);
615 	} else if (Dflg) {
616 		dsw_detach(ac, av);
617 	} else if (Jflg) {
618 		if (argc - optind != 1)
619 			usage(gettext("must specify 2 volumes with -J"));
620 		av[2] = argv[optind++];
621 		ac = 3;
622 		dsw_join(ac, av);
623 	} else if (Pflg) {
624 		if (argc - optind == ((group_name) ? 0 : 1)) {
625 			av[1] = argv[optind++];
626 			ac = (group_name) ? 0 : 2;
627 		} else if (argc - optind == ((group_name) ? 2 : 3)) {
628 			av[1] = argv[optind++];
629 			av[2] = argv[optind++];
630 			av[3] = argv[optind++];
631 			ac = (group_name) ? 2 : 4;
632 		} else
633 			usage(gettext(
634 				"must specify delay, unit and shadow with -P"));
635 		dsw_params(ac, av);
636 	} else if (Oflg) {
637 		dsw_overflow(ac, av);
638 	} else if (Rflg) {
639 		dsw_reset(ac, av);
640 	} else if (vflg) {
641 		dsw_version(ac, av);
642 	} else if (wflg) {
643 		dsw_wait(ac, av);
644 	} else if (lflg) {
645 		if ((gflg) && (!group_name))
646 			dsw_list_group_volumes();
647 		else
648 			dsw_list_volumes(ac, av);
649 	} else if (Lflg) {
650 		dsw_olist(ac, av);
651 	} else if (gLflg) {
652 		dsw_list_groups();
653 	} else if (Qflg) {
654 		dsw_ostat(ac, av);
655 	} else if (mflg) {
656 		if (argc - optind < 1)
657 			usage(gettext("must specify one or more volumes"));
658 		for (c = 1; argv[optind] != NULL; optind++)
659 			av[c++] = argv[optind];
660 		av[c] = NULL;
661 		dsw_move_2_group(ac, av);
662 	}
663 	if (cfg)
664 		cfg_close(cfg);
665 
666 	exit(0);
667 	return (0);
668 }
669 
670 static int
671 ii_lock(CFGFILE *cfg, int locktype)
672 {
673 	last_lock = locktype;
674 	return (cfg_lock(cfg, locktype));
675 }
676 
677 static int
678 do_ioctl(int fd, int cmd, void *arg)
679 {
680 	int unlocked = 0;
681 	int rc;
682 	int save_errno;
683 
684 	if (config_locked) {
685 		switch (cmd) {
686 		case DSWIOC_ENABLE:
687 		case DSWIOC_RESUME:
688 		case DSWIOC_SUSPEND:
689 		case DSWIOC_COPY:
690 		case DSWIOC_BITMAP:
691 		case DSWIOC_DISABLE:
692 		case DSWIOC_SHUTDOWN:
693 		case DSWIOC_ABORT:
694 		case DSWIOC_RESET:
695 		case DSWIOC_OFFLINE:
696 		case DSWIOC_WAIT:
697 		case DSWIOC_ACOPY:
698 		case DSWIOC_EXPORT:
699 		case DSWIOC_IMPORT:
700 		case DSWIOC_JOIN:
701 		case DSWIOC_COPYP:
702 		case DSWIOC_OATTACH:
703 		case DSWIOC_ODETACH:
704 		case DSWIOC_SBITSSET:
705 		case DSWIOC_CBITSSET:
706 		case DSWIOC_SEGMENT:
707 		case DSWIOC_MOVEGRP:
708 		case DSWIOC_CHANGETAG:
709 			cfg_unlock(cfg);
710 			unlocked = 1;
711 			break;
712 
713 		case DSWIOC_STAT:
714 		case DSWIOC_VERSION:
715 		case DSWIOC_LIST:
716 		case DSWIOC_OCREAT:
717 		case DSWIOC_OLIST:
718 		case DSWIOC_OSTAT:
719 		case DSWIOC_OSTAT2:
720 		case DSWIOC_LISTLEN:
721 		case DSWIOC_OLISTLEN:
722 		case DSWIOC_CLIST:
723 		case DSWIOC_GLIST:
724 			break;
725 
726 		default:
727 			fprintf(stderr,
728 			    "cfg locking needs to be set for %08x\n", cmd);
729 			exit(1);
730 			break;
731 		}
732 	}
733 	if (unlocked) {
734 		/* unload vol hashes */
735 		if (reload_vols & LD_II)
736 			unload_ii_vols();
737 		if (reload_vols & LD_SHADOWS)
738 			cfg_unload_shadows();
739 		if (reload_vols & LD_DSVOLS)
740 			cfg_unload_dsvols();
741 		if (reload_vols & LD_SVOLS)
742 			cfg_unload_svols();
743 	}
744 	rc = ioctl(fd, cmd, arg);
745 	save_errno = errno;
746 	if (config_locked && unlocked) {
747 		cfg_lock(cfg, last_lock);
748 	}
749 	if (unlocked) {
750 		/* reload vol hashes */
751 		if (reload_vols & LD_SVOLS)
752 			cfg_load_svols(cfg);
753 		if (reload_vols & LD_DSVOLS)
754 			cfg_load_dsvols(cfg);
755 		if (reload_vols & LD_SHADOWS)
756 			cfg_load_shadows(cfg);
757 		if (reload_vols & LD_II)
758 			load_ii_vols(cfg);
759 	}
760 
761 	errno = save_errno;
762 	return (rc);
763 }
764 
765 static int
766 get_dsw_config(int setno, dsw_config_t *parms)
767 {
768 	char buf[CFG_MAX_BUF];
769 	char key[CFG_MAX_KEY];
770 
771 	bzero(parms, sizeof (dsw_config_t));
772 	(void) snprintf(key, sizeof (key), "ii.set%d.master", setno);
773 	if (cfg_get_cstring(cfg, key, parms->master_vol, DSW_NAMELEN) < 0)
774 		return (-1);
775 
776 	(void) snprintf(key, sizeof (key), "ii.set%d.shadow", setno);
777 	(void) cfg_get_cstring(cfg, key, parms->shadow_vol, DSW_NAMELEN);
778 
779 	(void) snprintf(key, sizeof (key), "ii.set%d.bitmap", setno);
780 	(void) cfg_get_cstring(cfg, key, parms->bitmap_vol, DSW_NAMELEN);
781 
782 	(void) snprintf(key, sizeof (key), "ii.set%d.mode", setno);
783 	(void) cfg_get_cstring(cfg, key, buf, sizeof (buf));
784 	if (strcmp(buf, "I") == 0)
785 		parms->flag |= DSW_GOLDEN;
786 
787 	(void) snprintf(key, sizeof (key), "ii.set%d.overflow", setno);
788 	(void) cfg_get_cstring(cfg, key, last_overflow, DSW_NAMELEN);
789 
790 	(void) snprintf(key, sizeof (key), "ii.set%d.group", setno);
791 	(void) cfg_get_cstring(cfg, key, parms->group_name, DSW_NAMELEN);
792 
793 	(void) snprintf(key, sizeof (key), "ii.set%d.cnode", setno);
794 	(void) cfg_get_cstring(cfg, key, parms->cluster_tag, DSW_NAMELEN);
795 	return (0);
796 }
797 
798 static int
799 find_next_cf_line(char *volume, int next)
800 {
801 	dsw_config_t cf_line;
802 
803 	for (setnumber = next; get_dsw_config(setnumber, &cf_line) == 0;
804 								setnumber++) {
805 		if (strncmp(volume, cf_line.master_vol, DSW_NAMELEN) == 0 ||
806 		    strncmp(volume, cf_line.shadow_vol, DSW_NAMELEN) == 0 ||
807 		    strncmp(volume, cf_line.bitmap_vol, DSW_NAMELEN) == 0)
808 			return (1);
809 	}
810 	return (0);
811 }
812 int
813 find_any_cf_line(char *volume)
814 {
815 	return (find_next_cf_line(volume, 1));
816 }
817 
818 static int
819 find_next_shadow_line(char *volume, int next)
820 {
821 	dsw_config_t cf_line;
822 
823 	for (setnumber = next; get_dsw_config(setnumber, &cf_line) == 0;
824 	    setnumber++) {
825 		if (strncmp(volume, cf_line.shadow_vol, DSW_NAMELEN) == 0)
826 			return (1);
827 	}
828 	return (0);
829 }
830 int
831 find_shadow_line(char *volume)
832 {
833 	return (find_next_shadow_line(volume, 1));
834 }
835 
836 /*
837  * this function is designed to be called once, subsequent calls won't
838  * free memory allocated by earlier invocations.
839  */
840 char *
841 get_overflow_list()
842 {
843 	dsw_aioctl_t *acopy_args;
844 	int rc, num;
845 
846 	num = do_ioctl(dsw_fd, DSWIOC_OLISTLEN, NULL);
847 	if (num < 0)
848 		dsw_error(gettext("Can't get overflow list length"), NULL);
849 
850 	acopy_args = malloc(sizeof (dsw_aioctl_t) + num * DSW_NAMELEN);
851 	if (acopy_args == NULL)
852 		dsw_error(gettext("Can't get memory for list enquiry"), NULL);
853 
854 	acopy_args->count = num;
855 	acopy_args->flags = 0;
856 	acopy_args->status = spcs_s_ucreate();
857 
858 	rc = do_ioctl(dsw_fd, DSWIOC_OLIST, acopy_args);
859 	if (rc == -1)
860 		dsw_error(gettext("Overflow list access failure"),
861 			&acopy_args->status);
862 	else
863 		acopy_args->shadow_vol[DSW_NAMELEN*acopy_args->count] = NULL;
864 
865 	return (acopy_args->shadow_vol);
866 }
867 
868 /*
869  * this function is designed to be called once, subsequent calls won't
870  * free memory allocated by earlier invocations.
871  */
872 
873 int
874 find_group_members(char *group)
875 {
876 	int nmembers = 0;
877 	int vector_len = 0;
878 
879 	group_volumes = NULL;
880 	for (setnumber = 1; /*CSTYLED*/; setnumber++) {
881 		(void) snprintf(key, sizeof (key), "ii.set%d.group", setnumber);
882 		if (cfg_get_cstring(cfg, key, buf,
883 					sizeof (buf)) < 0)
884 			break;
885 
886 		if (strcmp(group, buf))
887 			continue;
888 
889 		(void) snprintf(key, sizeof (key), "ii.set%d.shadow",
890 		    setnumber);
891 		if (cfg_get_cstring(cfg, key, buf,
892 					sizeof (buf)) < 0)
893 			break;
894 
895 		if (nmembers >= vector_len) {
896 			vector_len += 10;
897 			group_volumes = realloc(group_volumes, (1+vector_len) *
898 					sizeof (char *));
899 		}
900 		group_volumes[nmembers] = strdup(buf);
901 		nmembers++;
902 	}
903 	if (group_volumes)
904 		group_volumes[nmembers] = NULL;	/* terminate list */
905 	return (nmembers);
906 }
907 
908 static int
909 find_next_matching_cf_line(
910 	char *volume, dsw_config_t *conf, dsw_ioctl_t *io, int next)
911 {
912 	dsw_config_t config;
913 
914 	if (!find_next_cf_line(volume, next)) {
915 		return (0);
916 	}
917 
918 	if (conf == NULL)
919 		conf = &config;
920 	(void) get_dsw_config(setnumber, conf);
921 	if (io) {
922 		strncpy(io->shadow_vol, conf->shadow_vol, DSW_NAMELEN);
923 		io->shadow_vol[DSW_NAMELEN] = '\0';
924 	}
925 	return (1);
926 }
927 
928 int
929 find_matching_cf_line(char *volume, dsw_config_t *conf, dsw_ioctl_t *io)
930 {
931 	return (find_next_matching_cf_line(volume, conf, io, 1));
932 }
933 
934 int
935 find_shadow_config(char *volume, dsw_config_t *conf, dsw_ioctl_t *io)
936 {
937 	dsw_config_t *c, cf;
938 
939 	if (io) {
940 		bzero(io, sizeof (dsw_ioctl_t));
941 	}
942 	c = conf ? conf : &cf;
943 	setnumber = 1;
944 	/* perform action for each line of the stored config file */
945 	for ((void) snprintf(key, sizeof (key), "ii.set%d.shadow", setnumber);
946 	    cfg_get_cstring(cfg, key, c->shadow_vol, DSW_NAMELEN) >= 0;
947 	    (void) snprintf(key, sizeof (key), "ii.set%d.shadow",
948 	    ++setnumber)) {
949 		if (strncmp(volume, c->shadow_vol, DSW_NAMELEN) == 0) {
950 			(void) get_dsw_config(setnumber, c);
951 
952 			if (check_resource_group(c->bitmap_vol)) {
953 				setnumber = 0;
954 				continue;
955 			}
956 
957 			switch (check_cluster()) {
958 			case II_CLUSTER:
959 				if ((cfg_cluster_tag) &&
960 				    (strcmp(cfg_cluster_tag, c->cluster_tag)))
961 					continue;
962 				break;
963 			case II_CLUSTER_LCL:
964 				if (strlen(c->cluster_tag))
965 					continue;
966 				break;
967 			}
968 
969 			if (io) {
970 				strncpy(io->shadow_vol, c->shadow_vol,
971 								DSW_NAMELEN);
972 				io->shadow_vol[DSW_NAMELEN] = '\0';
973 			}
974 			return (1);
975 		}
976 	}
977 	return (0);
978 }
979 
980 void
981 add_cfg_entry(dsw_config_t *parms)
982 {
983 	/* insert the well-known fields first */
984 	(void) snprintf(buf, sizeof (buf), "%s %s %s %s",
985 	    parms->master_vol, parms->shadow_vol, parms->bitmap_vol,
986 	    (parms->flag & DSW_GOLDEN) ? "I" : "D");
987 
988 	if (cfg_put_cstring(cfg, "ii", buf, strlen(buf)) >=  0) {
989 		/* if we have a group name, add it */
990 		if (group_name) {
991 			if (find_any_cf_line(parms->shadow_vol)) {
992 				(void) sprintf(buf, "ii.set%d.group",
993 				    setnumber);
994 				if (cfg_put_cstring(cfg, buf,
995 					group_name, strlen(group_name)) < 0)
996 					perror("cfg_put_cstring");
997 			}
998 			else
999 				perror("cfg_location");
1000 		}
1001 
1002 		/* commit the record */
1003 		(void) cfg_commit(cfg);
1004 	}
1005 	else
1006 		perror("cfg_put_string");
1007 }
1008 
1009 void
1010 remove_iiset(int setno, char *shadow, int shd_exp)
1011 {
1012 	mstcount_t *mdata;
1013 	shdvol_t *sdata;
1014 	char sn[CFG_MAX_BUF];
1015 
1016 	if (perform_autosv()) {
1017 		if (volhash) {
1018 			unload_ii_vols();
1019 		}
1020 		load_ii_vols(cfg);
1021 		if (cfg_load_dsvols(cfg) < 0 || cfg_load_svols(cfg) < 0) {
1022 			dsw_error(gettext("Unable to parse config file"), NULL);
1023 		}
1024 
1025 		sdata = (shdvol_t *)nsc_lookup(volhash, shadow);
1026 		if (sdata) {
1027 			/*
1028 			 * Handle the normal cases of disabling a set that is
1029 			 * not an imported shadow volume
1030 			 */
1031 			if (strcmp(sdata->master, II_IMPORTED_SHADOW)) {
1032 				/*
1033 				 * Handle multiple-shadows of single master
1034 				 */
1035 				mdata = (mstcount_t *)
1036 					nsc_lookup(volhash, sdata->master);
1037 				if ((mdata) && (mdata->count == 1)) {
1038 				    if (cfg_vol_disable(cfg, sdata->master,
1039 					cfg_cluster_tag, "ii") < 0)
1040 					    dsw_error(gettext(
1041 						"SV disable of master failed"),
1042 						NULL);
1043 				}
1044 			}
1045 
1046 			/*
1047 			 * Handle disk group name of different shadow
1048 			 */
1049 			if (shd_exp) {
1050 				/*
1051 				 * If shadow is exported, then do nothing
1052 				 */
1053 				/*EMPTY*/;
1054 			} else if (cfg_cluster_tag &&
1055 				    strcmp(cfg_cluster_tag, "") &&
1056 				    cfg_dgname(shadow, sn, sizeof (sn)) &&
1057 				    strlen(sn) &&
1058 				    strcmp(sn, cfg_cluster_tag)) {
1059 					/* reload disk group volumes */
1060 					cfg_resource(cfg, sn);
1061 					cfg_unload_dsvols();
1062 					cfg_unload_svols();
1063 					(void) cfg_load_dsvols(cfg);
1064 					(void) cfg_load_svols(cfg);
1065 					if (cfg_vol_disable(cfg, shadow, sn,
1066 					    "ii") < 0)
1067 					    dsw_error(gettext(
1068 						"SV disable of shadow failed"),
1069 						NULL);
1070 					cfg_resource(cfg, cfg_cluster_tag);
1071 			} else {
1072 				if (cfg_vol_disable(cfg, shadow,
1073 				    cfg_cluster_tag, "ii") < 0)
1074 					dsw_error(gettext(
1075 					    "SV disable of shadow failed"),
1076 					    NULL);
1077 			}
1078 		}
1079 		cfg_unload_svols();
1080 		cfg_unload_dsvols();
1081 		unload_ii_vols();
1082 		reload_vols &= ~(LD_SVOLS | LD_DSVOLS | LD_II);
1083 	}
1084 
1085 	(void) sprintf(key, "ii.set%d", setno);
1086 	if (cfg_put_cstring(cfg, key, NULL, 0) < 0) {
1087 		perror("cfg_put_cstring");
1088 	}
1089 	(void) cfg_commit(cfg);
1090 }
1091 
1092 /*
1093  * determine if we are running in a Sun Cluster Environment
1094  */
1095 int
1096 check_cluster()
1097 {
1098 	static int is_cluster = -1;
1099 	int rc;
1100 #ifdef DEBUG
1101 	char *cdebug = getenv("II_SET_CLUSTER");
1102 #endif
1103 
1104 	/*
1105 	 * If this routine was previously called, just return results
1106 	 */
1107 	if (is_cluster != -1)
1108 		return (is_cluster);
1109 
1110 	/*
1111 	 * See if Sun Cluster was installed on this node
1112 	 */
1113 #ifdef DEBUG
1114 	if (cdebug) rc = atoi(cdebug);
1115 	else
1116 #endif
1117 	rc = cfg_iscluster();
1118 	if (rc > 0) {
1119 		/*
1120 		 * Determine if user specified -C local
1121 		 */
1122 		if ((cfg_cluster_tag == NULL) ||
1123 		    (strcmp(cfg_cluster_tag, II_LOCAL_TAG))) {
1124 			/*
1125 			 * We're in a Sun Cluster, and no "-C local"
1126 			 */
1127 			is_cluster = II_CLUSTER;
1128 		} else {
1129 			/*
1130 			 * We're in a Sun Cluster, but "-C local" was specified
1131 			 */
1132 			is_cluster = II_CLUSTER_LCL;
1133 			cfg_cluster_tag = "";
1134 		}
1135 		return (is_cluster);
1136 	} else if (rc == 0) {
1137 		/*
1138 		 * Not in a Sun Cluster
1139 		 */
1140 		is_cluster = II_NOT_CLUSTER;
1141 		return (is_cluster);
1142 	} else {
1143 		dsw_error(gettext("unable to ascertain environment"), NULL);
1144 		/*NOTREACHED*/
1145 	}
1146 
1147 	/* gcc */
1148 	return (is_cluster);
1149 }
1150 
1151 /*
1152  * Determine if we need to set a cfg_resource based on this volume
1153  */
1154 static int
1155 check_resource_group(char *volume)
1156 {
1157 	char diskgroup[CFG_MAX_BUF];
1158 
1159 	/*
1160 	 * If we are in a cluster, attempt to derive a new resource group
1161 	 */
1162 
1163 #ifdef DEBUG
1164 	if (getenv("II_SET_CLUSTER") || (check_cluster() == II_CLUSTER)) {
1165 #else
1166 	if (check_cluster() == II_CLUSTER) {
1167 #endif
1168 		if (check_diskgroup(volume, diskgroup)) {
1169 			if (cfg_cluster_tag == NULL) {
1170 				cfg_cluster_tag = strdup(diskgroup);
1171 				if (cfg_cluster_tag == NULL)
1172 					dsw_error(gettext(
1173 					"Memory allocation failure"), NULL);
1174 				cfg_resource(cfg, cfg_cluster_tag);
1175 				return (1);
1176 			} else {
1177 			/*
1178 			 * Check dgname and cluster tag from -C are the same.
1179 			 */
1180 			if (strcmp(diskgroup, cfg_cluster_tag) != 0) {
1181 			    char error_buffer[128];
1182 			    (void) snprintf(error_buffer, sizeof (error_buffer),
1183 				gettext(
1184 				    "-C (%s) does not match disk group "
1185 				    "name (%s) for %s"), cfg_cluster_tag,
1186 				    diskgroup, volume);
1187 				spcs_log("ii", NULL, error_buffer);
1188 				dsw_error(error_buffer, NULL);
1189 			    }
1190 			}
1191 		} else if (cfg_cluster_tag == NULL)
1192 			dsw_error(gettext(
1193 				"Point-in-Time Copy volumes, that are not "
1194 				"in a device group which has been "
1195 				"registered with SunCluster, "
1196 				"require usage of \"-C\""), NULL);
1197 	}
1198 	return (0);
1199 }
1200 
1201 static void
1202 check_dg_is_local(char *dgname)
1203 {
1204 	char error_buffer[128];
1205 	char *othernode;
1206 	int rc;
1207 
1208 	/*
1209 	 * check where this disk service is mastered
1210 	 */
1211 	rc = cfg_dgname_islocal(dgname, &othernode);
1212 	if (rc < 0) {
1213 		(void) snprintf(error_buffer, sizeof (error_buffer),
1214 		    gettext("Unable to find disk service:%s"), dgname);
1215 		dsw_error(error_buffer, NULL);
1216 	} else if (rc == 0) {
1217 		(void) snprintf(error_buffer, sizeof (error_buffer),
1218 		    gettext("disk service, %s, is active on node \"%s\"\n"
1219 		    "Please re-issue the command on that node"), dgname,
1220 		    othernode);
1221 		dsw_error(error_buffer, NULL);
1222 	}
1223 }
1224 
1225 /*
1226  * Carry out cluster based checks for a specified volume, or just
1227  * global options.
1228  */
1229 static int
1230 check_diskgroup(char *path, char *result)
1231 {
1232 	char dgname[CFG_MAX_BUF];
1233 	char error_buffer[128];
1234 
1235 #ifdef DEBUG
1236 	char *override = getenv("II_CLUSTER_TAG");
1237 	if (override) {
1238 		strcpy(result, override);
1239 		return (1);
1240 	}
1241 #endif
1242 	/*
1243 	 * Check on path name, a returned NULL dgname is valid
1244 	 */
1245 	if (cfg_dgname(path, dgname, sizeof (dgname)) == NULL) {
1246 		(void) snprintf(error_buffer, sizeof (error_buffer), gettext(
1247 		    "unable to determine disk group name for %s"), path);
1248 		dsw_error(error_buffer, NULL);
1249 	}
1250 	if (strcmp(dgname, "") == 0)
1251 		return (0);
1252 
1253 	/*
1254 	 * See if disk group is local to this node
1255 	 */
1256 	check_dg_is_local(dgname);
1257 
1258 	/*
1259 	 * Copy dgname into result
1260 	 */
1261 	strcpy(result, dgname);
1262 	return (1);
1263 }
1264 
1265 /*
1266  * sigterm (): traps specified signal , usually termination one
1267  */
1268 void
1269 sigterm(int sig)
1270 {
1271 	spcs_log("ii", NULL, gettext("%s received signal %d"), cmdnam, sig);
1272 	exit(1);
1273 }
1274 
1275 /*
1276  * sigchild; reap child and collect status.
1277  */
1278 
1279 volatile pid_t	dead_child;
1280 int	dead_stat;
1281 
1282 /*ARGSUSED*/
1283 void
1284 sigchild(int sig)
1285 {
1286 	dead_child = wait(&dead_stat);
1287 }
1288 
1289 /*
1290  * InitEnv(): initializes environment
1291  */
1292 void
1293 InitEnv()
1294 {
1295 	(void) setlocale(LC_ALL, "");
1296 	(void) textdomain(DSW_TEXT_DOMAIN);
1297 
1298 #ifndef DEBUG
1299 	sigset(SIGHUP, sigterm);
1300 	sigset(SIGINT, sigterm);
1301 	sigset(SIGQUIT, sigterm);
1302 	sigset(SIGILL, sigterm);
1303 	sigset(SIGEMT, sigterm);
1304 	sigset(SIGABRT, sigterm);
1305 	sigset(SIGFPE, sigterm);
1306 	sigset(SIGBUS, sigterm);
1307 	sigset(SIGSEGV, sigterm);
1308 	sigset(SIGTERM, sigterm);
1309 	sigset(SIGPWR, sigterm);
1310 	sigset(SIGSTOP, sigterm);
1311 	sigset(SIGTSTP, sigterm);
1312 #endif
1313 
1314 	dsw_fd = open(DSWDEV, O_RDONLY);
1315 	if (dsw_fd < 0) {
1316 		perror(DSWDEV);
1317 		exit(1);
1318 	}
1319 
1320 	setsid();
1321 }
1322 
1323 /*
1324  * print an error message, followed by decoded errno then exit.
1325  */
1326 void
1327 dsw_error(char *str, spcs_s_info_t *status)
1328 {
1329 	char *sp;
1330 
1331 	(void) fprintf(stderr, "%s: %s:\n", cmdnam, str);
1332 	if (status == NULL) {
1333 		/* deflect ESRCH */
1334 		if (ESRCH == errno) {
1335 			sp = "Set/volume not found";
1336 		} else {
1337 			sp = strerror(errno);
1338 		}
1339 		(void) fprintf(stderr, "%s\n", sp ? sp : "");
1340 	} else {
1341 		spcs_s_report(*status, stderr);
1342 		spcs_s_ufree(status);
1343 	}
1344 	if (cfg)
1345 		cfg_close(cfg);
1346 	exit(2);
1347 }
1348 
1349 
1350 #undef size
1351 
1352 void
1353 free_bitmap(unsigned char *bitmap)
1354 {
1355 	free(bitmap);
1356 }
1357 
1358 
1359 int
1360 get_bitmap(master_volume, shd_bitmap, copy_bitmap, size)
1361 	char		*master_volume;
1362 	unsigned char	*shd_bitmap;
1363 	unsigned char	*copy_bitmap;
1364 	unsigned long	size;
1365 {
1366 	dsw_bitmap_t parms;
1367 
1368 	strncpy(parms.shadow_vol, master_volume, DSW_NAMELEN);
1369 	parms.shadow_vol[DSW_NAMELEN-1] = '\0';
1370 	parms.shd_bitmap = shd_bitmap;
1371 	parms.shd_size = size;
1372 	parms.copy_bitmap = copy_bitmap;
1373 	parms.copy_size = size;
1374 
1375 	return (do_ioctl(dsw_fd, DSWIOC_BITMAP, &parms));
1376 }
1377 
1378 unsigned char *
1379 allocate_bitmap(char *shadow_volume)
1380 {
1381 	unsigned char	*shd_bitmap;
1382 	unsigned char	*copy_bitmap;
1383 	unsigned char	*p;
1384 	unsigned char	*q;
1385 	int		i;
1386 	dsw_stat_t	args;
1387 	int		stat_flags;
1388 
1389 	strncpy(args.shadow_vol, shadow_volume, DSW_NAMELEN);
1390 	args.shadow_vol[DSW_NAMELEN-1] = '\0';
1391 
1392 	args.status = spcs_s_ucreate();
1393 	if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1)
1394 		dsw_error(gettext("Stat failed"), &args.status);
1395 
1396 	stat_flags = args.stat;
1397 	if (stat_flags & DSW_BMPOFFLINE)
1398 		return (NULL);
1399 
1400 	bm_size = args.size;
1401 	bm_size = (bm_size + DSW_SIZE-1) / DSW_SIZE;
1402 	bm_actual = bm_size;
1403 	bm_size = (bm_size + DSW_BITS-1) / DSW_BITS;
1404 	spcs_s_ufree(&args.status);
1405 
1406 	p = shd_bitmap = (unsigned char *) malloc(bm_size);
1407 	if (!shd_bitmap) {
1408 		perror(gettext("malloc bitmap"));
1409 		return (NULL);
1410 	}
1411 
1412 	q = copy_bitmap = (unsigned char *) malloc(bm_size);
1413 	if (!copy_bitmap) {
1414 		perror(gettext("malloc bitmap"));
1415 		free(shd_bitmap);
1416 		return (NULL);
1417 	}
1418 
1419 	memset(shd_bitmap, 0, bm_size);
1420 	memset(copy_bitmap, 0, bm_size);
1421 
1422 	if (get_bitmap(shadow_volume, shd_bitmap, copy_bitmap, bm_size) < 0) {
1423 		free(copy_bitmap);
1424 		free(shd_bitmap);
1425 		return (NULL);
1426 	}
1427 
1428 	/*
1429 	 * "or" the copy and shadow bitmaps together to return a composite
1430 	 * bitmap that contains the total set of differences between the
1431 	 * volumes.
1432 	 */
1433 	for (i = bm_size; i-- > 0; /*CSTYLED*/)
1434 		*p++ |= *q++;
1435 
1436 	free(copy_bitmap);
1437 
1438 	return (shd_bitmap);
1439 }
1440 
1441 /*
1442  * print usage message and exit.
1443  */
1444 void
1445 usage(char *why)
1446 {
1447 	if (why) {
1448 		(void) fprintf(stderr, "%s: %s\n", cmdnam, why);
1449 
1450 		(void) fprintf(stderr, "%s\n",
1451 		    gettext("\nBrief summary:"));
1452 		(void) fprintf(stderr, "%s\n",
1453 		    gettext("\t-e {ind|dep} master_vol shadow_vol "
1454 		    "bitmap_vol"));
1455 		(void) fprintf(stderr, "%s\n",
1456 		    gettext("\t-[cu {s|m}] volume_set"));
1457 		(void) fprintf(stderr, "%s\n",
1458 		    gettext("\t-i all"));
1459 		(void) fprintf(stderr, "%s\n",
1460 		    gettext("\t-[adDEilPRw] volume_set"));
1461 		(void) fprintf(stderr, "%s\n",
1462 		    gettext("\t-g group_name [options]"));
1463 		(void) fprintf(stderr, "%s\n",
1464 		    gettext("\t-C cluster_tag [options]"));
1465 		(void) fprintf(stderr, "%s\n",
1466 		    gettext("\t-[hilLv]"));
1467 		(void) fprintf(stderr, "%s\n",
1468 		    gettext("\t-[IJ] volume_set bitmap"));
1469 		(void) fprintf(stderr, "%s\n",
1470 		    gettext("\t-A overflow_vol volume_set"));
1471 		(void) fprintf(stderr, "%s\n",
1472 		    gettext("\t-[OQ] overflow_vol"));
1473 		(void) fprintf(stderr, "%s\n",
1474 		    gettext("\t-P {delay} {units} volume_set"));
1475 
1476 		/* assume we came here due to a user mistake */
1477 		exit(1);
1478 		/* NOTREACHED */
1479 	} else {
1480 
1481 		(void) fprintf(stdout, "%s\n",
1482 		    gettext("Point-in-Time Copy Administrator CLI options"));
1483 		(void) fprintf(stdout, "%s\n",
1484 		    gettext("Usage summary:"));
1485 		(void) fprintf(stdout, "%s\n",
1486 		    gettext("\t-e ind m s b\tenable independent master shadow "
1487 		    "bitmap"));
1488 		(void) fprintf(stdout, "%s\n",
1489 		    gettext("\t-e dep m s b\tenable dependent master shadow "
1490 		    "bitmap"));
1491 		if (check_cluster() == II_CLUSTER)
1492 		    (void) fprintf(stdout, "%s\n",
1493 			gettext("\t-ne ind m s b\tenable exportable master "
1494 			"shadow bitmap"));
1495 		(void) fprintf(stdout, "%s\n",
1496 		    gettext("\t-d v\t\tdisable volume"));
1497 		(void) fprintf(stdout, "%s\n",
1498 		    gettext("\t-u s v\t\tupdate shadow volume"));
1499 		(void) fprintf(stdout, "%s\n",
1500 		    gettext("\t-u m v\t\tupdate master volume"));
1501 		(void) fprintf(stdout, "%s\n",
1502 		    gettext("\t-c s v\t\tcopy to shadow volume"));
1503 		(void) fprintf(stdout, "%s\n",
1504 		    gettext("\t-c m v\t\tcopy to master volume"));
1505 		(void) fprintf(stdout, "%s\n",
1506 		    gettext("\t-a v\t\tabort copy volume"));
1507 		(void) fprintf(stdout, "%s\n",
1508 		    gettext("\t-w v\t\twait volume"));
1509 		(void) fprintf(stdout, "%s\n",
1510 		    gettext("\t-i v\t\tdisplay volume status"));
1511 		(void) fprintf(stdout, "%s\n",
1512 		    gettext("\t-i all\t\tdisplay all volume status"));
1513 		(void) fprintf(stdout, "%s\n",
1514 		    gettext("\t-l\t\tlist all volumes"));
1515 		(void) fprintf(stdout, "%s\n",
1516 		    gettext("\t-R v\t\treset volume"));
1517 		(void) fprintf(stdout, "%s\n",
1518 		    gettext("\t-A o v\t\tattach overflow to volume"));
1519 		(void) fprintf(stdout, "%s\n",
1520 		    gettext("\t-D v\t\tdetach overflow from volume"));
1521 		(void) fprintf(stdout, "%s\n",
1522 		    gettext("\t-L\t\tlist all overflow volumes"));
1523 		(void) fprintf(stdout, "%s\n",
1524 		    gettext("\t-O o\t\tinitialize overflow"));
1525 		(void) fprintf(stdout, "%s\n",
1526 		    gettext("\t-Q o\t\tquery status of overflow"));
1527 		(void) fprintf(stdout, "%s\n",
1528 		    gettext("\t-E v\t\texport shadow volume"));
1529 		(void) fprintf(stdout, "%s\n",
1530 		    gettext("\t-I v b\t\timport volume bitmap"));
1531 		(void) fprintf(stdout, "%s\n",
1532 		    gettext("\t-J v b\t\tjoin volume bitmap"));
1533 		(void) fprintf(stdout, "%s\n",
1534 		    gettext("\t-P d u v\tset copy delay/units for volume"));
1535 		(void) fprintf(stdout, "%s\n",
1536 		    gettext("\t-P v\t\tget copy delay/units for volume"));
1537 		(void) fprintf(stdout, "%s\n",
1538 		    gettext("\t-C tag\t\tcluster resource tag"));
1539 #ifdef DEBUG
1540 		(void) fprintf(stdout, "%s\n",
1541 		    gettext("\t-b v\t\tdisplay bitmap volume"));
1542 		(void) fprintf(stdout, "%s\n",
1543 		    gettext("\t-f f\t\tuse private configuration file"));
1544 #endif
1545 		(void) fprintf(stdout, "%s\n",
1546 		    gettext("\t-v\t\tprint software versions"));
1547 		(void) fprintf(stdout, "%s\n",
1548 		    gettext("\t-n\t\tperform action without question"));
1549 		(void) fprintf(stdout, "%s\n",
1550 		    gettext("\t-p [-c|-u] {m|s}"
1551 			"enable PID locking on copy or update"));
1552 		(void) fprintf(stdout, "%s\n",
1553 		    gettext("\t-p -w v\t\tdisable PID locking"));
1554 		(void) fprintf(stdout, "%s\n",
1555 		    gettext("\t-h\t\tiiadm usage summary"));
1556 		(void) fprintf(stdout, "%s\n",
1557 		    gettext("\nUsage summary for options that support "
1558 		    "grouping (-g g):"));
1559 		(void) fprintf(stdout, "%s\n",
1560 		    gettext("\t-g g -e ind m s b group enable independent "
1561 		    "master shadow bitmap"));
1562 		(void) fprintf(stdout, "%s\n",
1563 		    gettext("\t-g g -e dep m s b group enable dependent "
1564 		    "master shadow bitmap"));
1565 		(void) fprintf(stdout, "%s\n",
1566 		    gettext("\t-g g -d\t\tdisable group"));
1567 		(void) fprintf(stdout, "%s\n",
1568 		    gettext("\t-g g -u s\tupdate shadow for all volumes in "
1569 		    "group"));
1570 		(void) fprintf(stdout, "%s\n",
1571 		    gettext("\t-g g -u m\tupdate master for all volumes in "
1572 		    "group"));
1573 		(void) fprintf(stdout, "%s\n",
1574 		    gettext("\t-g g -c s\tcopy to shadow for all volumes in "
1575 		    "group"));
1576 		(void) fprintf(stdout, "%s\n",
1577 		    gettext("\t-g g -c m\tcopy to master for all volumes in "
1578 		    "group"));
1579 		(void) fprintf(stdout, "%s\n",
1580 		    gettext("\t-g g -a\t\tabort copy for all volumes in "
1581 		    "group"));
1582 		(void) fprintf(stdout, "%s\n",
1583 		    gettext("\t-g g -w\t\twait for all volumes in group"));
1584 		(void) fprintf(stdout, "%s\n",
1585 		    gettext("\t-g g -i\t\tdisplay status of all volumes in "
1586 		    "group"));
1587 		(void) fprintf(stdout, "%s\n",
1588 		    gettext("\t-g g -l\t\tlist all volumes in group"));
1589 		(void) fprintf(stdout, "%s\n",
1590 		    gettext("\t-g -L\t\tlist all groups"));
1591 		(void) fprintf(stdout, "%s\n",
1592 		    gettext("\t-g g -m v v\tmove one or more volumes into "
1593 		    "group"));
1594 		(void) fprintf(stdout, "%s\n",
1595 		    gettext("\t-g \"\" -m v\tremove volume from group"));
1596 		(void) fprintf(stdout, "%s\n",
1597 		    gettext("\t-g g -R\t\treset all volumes in group"));
1598 		(void) fprintf(stdout, "%s\n",
1599 		    gettext("\t-g g -A o\tattach overflow to all volumes in "
1600 		    "group"));
1601 		(void) fprintf(stdout, "%s\n",
1602 		    gettext("\t-g g -D\t\tdetach overflow from all volumes in "
1603 		    "group"));
1604 		(void) fprintf(stdout, "%s\n",
1605 		    gettext("\t-g g -E\t\texport shadow volume for all "
1606 		    "volumes in group"));
1607 		(void) fprintf(stdout, "%s\n",
1608 		    gettext("\t-g g -P d u\tset copy delay/units for all "
1609 		    "volumes in group"));
1610 		(void) fprintf(stdout, "%s\n",
1611 		    gettext("\t-g g -P\t\tget copy delay/units for all "
1612 		    "volumes in group"));
1613 		(void) fprintf(stdout, "%s\n",
1614 		    gettext("\nLegend summary:"));
1615 		(void) fprintf(stdout, "%s\n",
1616 		    gettext("\tind\t\tindependent volume set"));
1617 		(void) fprintf(stdout, "%s\n",
1618 		    gettext("\tdep\t\tdependent volume set"));
1619 		(void) fprintf(stdout, "%s\n",
1620 		    gettext("\tall\t\tall configured volumes"));
1621 		(void) fprintf(stdout, "%s\n",
1622 		    gettext("\tm\t\tmaster volume"));
1623 		(void) fprintf(stdout, "%s\n",
1624 		    gettext("\ts\t\tshadow volume"));
1625 		(void) fprintf(stdout, "%s\n",
1626 		    gettext("\tv\t\tshadow volume (reference name)"));
1627 		(void) fprintf(stdout, "%s\n",
1628 		    gettext("\to\t\toverflow volume"));
1629 		(void) fprintf(stdout, "%s\n",
1630 		    gettext("\tb\t\tbitmap volume"));
1631 #ifdef DEBUG
1632 		(void) fprintf(stdout, "%s\n",
1633 		    gettext("\tf\t\tconfiguration file name"));
1634 #endif
1635 		(void) fprintf(stdout, "%s\n",
1636 		    gettext("\td\t\tdelay tick interval"));
1637 		(void) fprintf(stdout, "%s\n",
1638 		    gettext("\tu\t\tunit size"));
1639 		(void) fprintf(stdout, "%s\n",
1640 		    gettext("\tg\t\tgroup name"));
1641 
1642 		/* assume we came here because user request help text */
1643 		exit(0);
1644 		/* NOTREACHED */
1645 	}
1646 
1647 }
1648 
1649 static  char    yeschr[MAX_LINE_SIZE + 2];
1650 static  char    nochr[MAX_LINE_SIZE + 2];
1651 
1652 static int
1653 yes(void)
1654 {
1655 	int	i, b;
1656 	char	ans[MAX_LINE_SIZE + 1];
1657 
1658 	for (i = 0; /*CSTYLED*/; i++) {
1659 		b = getchar();
1660 		if (b == '\n' || b == '\0' || b == EOF) {
1661 			if (i < MAX_LINE_SIZE)
1662 				ans[i] = 0;
1663 			break;
1664 		}
1665 		if (i < MAX_LINE_SIZE)
1666 			ans[i] = b;
1667 	}
1668 	if (i >= MAX_LINE_SIZE) {
1669 		i = MAX_LINE_SIZE;
1670 		ans[MAX_LINE_SIZE] = 0;
1671 	}
1672 	if ((i == 0) || (strncmp(yeschr, ans, i))) {
1673 		if (strncmp(nochr, ans, i) == 0)
1674 			return (0);
1675 		else if (strncmp(yeschr, ans, i) == 0)
1676 			return (1);
1677 		else {
1678 			(void) fprintf(stderr, "%s %s/%s\n",
1679 			    gettext("You have to respond with"),
1680 			    yeschr, nochr);
1681 			return (2);
1682 		}
1683 	}
1684 	return (1);
1685 }
1686 
1687 static int
1688 convert_int(char *str)
1689 {
1690 	int result, rc;
1691 	char *buf;
1692 
1693 	buf = (char *)calloc(strlen(str) + 256, sizeof (char));
1694 	rc = sscanf(str, "%d%s", &result, buf);
1695 
1696 	if (rc != 1) {
1697 		(void) sprintf(buf, gettext("'%s' is not a valid number"), str);
1698 		/* dsw_error calls exit which frees 'buf' */
1699 		errno = EINVAL;
1700 		dsw_error(buf, NULL);
1701 	}
1702 	free(buf);
1703 
1704 	return (result);
1705 }
1706 
1707 void
1708 check_action(char *will_happen)
1709 {
1710 	int answer;
1711 
1712 	if (nflg || !isatty(fileno(stdin)))
1713 		return;
1714 	strncpy(yeschr, nl_langinfo(YESSTR), MAX_LINE_SIZE + 1);
1715 	strncpy(nochr, nl_langinfo(NOSTR), MAX_LINE_SIZE + 1);
1716 
1717 	/*CONSTCOND*/
1718 	while (1) {
1719 		(void) printf("%s %s/%s ", will_happen, yeschr, nochr);
1720 		answer = yes();
1721 		if (answer == 1 || answer == 0)
1722 			break;
1723 	}
1724 	if (answer == 1)
1725 		return;
1726 	exit(1);
1727 }
1728 
1729 enum	child_event {Status, CopyStart};
1730 
1731 /*
1732  * Wait for child process to get to some state, where some state may be:
1733  *
1734  *	Status		Set up the shadow enough so that it responds
1735  *			to status requests.
1736  *	CopyStart	Start copy/update operations.
1737  */
1738 
1739 int
1740 child_wait(pid_t child, enum child_event event, char *volume)
1741 {
1742 	dsw_stat_t	args;
1743 	int rc;
1744 
1745 	strncpy(args.shadow_vol, volume, DSW_NAMELEN);
1746 	args.shadow_vol[DSW_NAMELEN-1] = '\0';
1747 
1748 	for (; dead_child != child; sleep(1)) {
1749 
1750 		/* poll shadow group with a status ioctl() */
1751 		args.status = spcs_s_ucreate();
1752 		errno = 0;
1753 		rc = do_ioctl(dsw_fd, DSWIOC_STAT, &args);
1754 
1755 		spcs_s_ufree(&args.status);
1756 
1757 		if (event == Status) {
1758 			/* keep polling while we fail with DSW_ENOTFOUND */
1759 			if (rc != -1 || errno != DSW_ENOTFOUND)
1760 				return (0);
1761 		} else {
1762 			/* event == CopyStart */
1763 			if (rc == -1) {
1764 				return (1);	/* something wrong */
1765 			}
1766 			if (args.stat & DSW_COPYINGP)
1767 				return (0);	/* copying underway */
1768 		}
1769 	}
1770 	/* child died */
1771 	if (WIFEXITED(dead_stat))
1772 		return (WEXITSTATUS(dead_stat));
1773 	else
1774 		return (1);
1775 }
1776 
1777 int
1778 mounted(char *t)
1779 {
1780 	int	rdsk;
1781 	int	i;
1782 	FILE	*mntfp;
1783 	struct mnttab mntref;
1784 	struct mnttab mntent;
1785 	char	target[DSW_NAMELEN];
1786 	char	*s;
1787 
1788 	rdsk = i = 0;
1789 	for (s = target; i < DSW_NAMELEN && (*s = *t++); i++) {
1790 		if (*s == 'r' && rdsk == 0)
1791 			rdsk = 1;
1792 		else
1793 			s++;
1794 	}
1795 	*s = '\0';
1796 
1797 	mntref.mnt_special = target;
1798 	mntref.mnt_mountp = NULL;
1799 	mntref.mnt_fstype = NULL;
1800 	mntref.mnt_mntopts = NULL;
1801 	mntref.mnt_time = NULL;
1802 
1803 	if ((mntfp = fopen("/etc/mnttab", "r")) == NULL) {
1804 		dsw_error(gettext("Can not check volume against mount table"),
1805 					NULL);
1806 	}
1807 	if (getmntany(mntfp, &mntent, &mntref) != -1) {
1808 		/* found something before EOF */
1809 		(void) fclose(mntfp);
1810 		return (1);
1811 	}
1812 	(void) fclose(mntfp);
1813 	return (0);
1814 }
1815 
1816 void
1817 enable(char *master_volume, char *shadow_volume,
1818 	char *bitmap_volume, char *copy_type)
1819 {
1820 	dsw_config_t parms;
1821 	dsw_ioctl_t temp;
1822 	char	*p;
1823 	int	rc;
1824 	pid_t	child;
1825 	spcs_s_info_t *sp_info;
1826 	struct stat mstat, sstat, bstat;
1827 	char	mst_dg[DSW_NAMELEN] = {0};
1828 	char	shd_dg[DSW_NAMELEN] = {0};
1829 	char	bmp_dg[DSW_NAMELEN] = {0};
1830 	int	mvol_enabled;
1831 	char	*altname;
1832 	grptag_t *gdata;
1833 
1834 	bzero(&parms, sizeof (dsw_config_t));
1835 
1836 	if (strcmp(copy_type, "independent") == 0 ||
1837 			strcmp(copy_type, gettext("independent")) == 0)
1838 		parms.flag = DSW_GOLDEN;
1839 	else if (strcmp(copy_type, "dependent") == 0 ||
1840 			strcmp(copy_type, gettext("dependent")) == 0)
1841 		parms.flag = 0;
1842 	else
1843 		dsw_error(gettext("don't understand shadow type"), NULL);
1844 
1845 	/* validate volume names */
1846 	if (perform_autosv()) {
1847 		if (cfg_load_svols(cfg) < 0 || cfg_load_dsvols(cfg) < 0 ||
1848 		    cfg_load_shadows(cfg) < 0) {
1849 			dsw_error(gettext("Unable to parse config file"), NULL);
1850 		}
1851 		load_ii_vols(cfg);
1852 		reload_vols = LD_SVOLS | LD_DSVOLS | LD_SHADOWS | LD_II;
1853 
1854 		/* see if it's been used before under a different name */
1855 		conform_name(&master_volume);
1856 		conform_name(&shadow_volume);
1857 		rc = cfg_get_canonical_name(cfg, bitmap_volume, &altname);
1858 		if (rc < 0) {
1859 			dsw_error(gettext("Unable to parse config file"), NULL);
1860 		}
1861 		if (rc) {
1862 			errno = EBUSY;
1863 			dsw_error(gettext("Bitmap in use"), NULL);
1864 		}
1865 	}
1866 
1867 	/*
1868 	 * If not local, determine disk group names for volumes in II set
1869 	 */
1870 	switch (check_cluster()) {
1871 	case II_CLUSTER:
1872 		/*
1873 		 * Check if none or all volumes are in a disk group
1874 		 */
1875 		rc = 0;
1876 		if (check_diskgroup(master_volume, mst_dg)) rc++;
1877 		if (check_diskgroup(shadow_volume, shd_dg)) rc++;
1878 		if (check_diskgroup(bitmap_volume, bmp_dg)) rc++;
1879 		if ((rc != 0) && (rc != 3))
1880 			dsw_error(gettext(
1881 				"Not all Point-in-Time Copy volumes are "
1882 				"in a disk group"), NULL);
1883 
1884 		/*
1885 		 * If volumes are not in a disk group, but are in a
1886 		 * cluster, then "-C <tag>", must be set
1887 		 */
1888 		if (rc == 0 && cfg_cluster_tag == NULL)
1889 			dsw_error(gettext(
1890 				"Point-in-Time Copy volumes, that are not "
1891 				"in a device group which has been "
1892 				"registered with SunCluster, "
1893 				"require usage of \"-C\""), NULL);
1894 
1895 		/*
1896 		 * the same disk group
1897 		 * If -n, plus mst_dg==bmp_dg, then allow E/I/J in SunCluster
1898 		 */
1899 		if ((strcmp(mst_dg, bmp_dg)) ||
1900 		    (strcmp(mst_dg, shd_dg) && (!nflg)))
1901 			    dsw_error(gettext(
1902 				"Volumes are not in same disk group"), NULL);
1903 
1904 		/*
1905 		 * Can never enable the same shadow twice, regardless of
1906 		 * exportable shadow device group movement
1907 		 */
1908 		if (find_shadow_line(shadow_volume))
1909 			dsw_error(gettext(
1910 				"Shadow volume is already configured"), NULL);
1911 
1912 		/*
1913 		 * Groups cannot span multiple clusters
1914 		 */
1915 		if (group_name && perform_autosv()) {
1916 			gdata = (grptag_t *)nsc_lookup(volhash, group_name);
1917 			if (gdata &&
1918 			    strncmp(gdata->ctag, mst_dg, DSW_NAMELEN) != 0) {
1919 				errno = EINVAL;
1920 				dsw_error(gettext("Group contains sets not "
1921 				    "in the same cluster resource"), NULL);
1922 			}
1923 		}
1924 
1925 		/*
1926 		 * Check cluster tag and bitmap disk group
1927 		 * set latter if different
1928 		 */
1929 		if (check_resource_group(bitmap_volume)) {
1930 			/*
1931 			 * Unload and reload in the event cluster tag has
1932 			 * changed
1933 			 */
1934 			if (perform_autosv()) {
1935 				unload_ii_vols();
1936 				cfg_unload_shadows();
1937 				cfg_unload_dsvols();
1938 				cfg_unload_svols();
1939 				if (cfg_load_svols(cfg) < 0 ||
1940 				    cfg_load_dsvols(cfg) < 0 ||
1941 				    cfg_load_shadows(cfg) < 0) {
1942 					dsw_error(gettext(
1943 					    "Unable to parse config "
1944 					    "file"), NULL);
1945 				}
1946 				load_ii_vols(cfg);
1947 			}
1948 		}
1949 		/*
1950 		 * Copy cluster name into config
1951 		 */
1952 		strncpy(parms.cluster_tag, cfg_cluster_tag, DSW_NAMELEN);
1953 		break;
1954 
1955 	case II_CLUSTER_LCL:
1956 		/* ensure that the -C local won't interfere with the set */
1957 		if (group_name && perform_autosv()) {
1958 			gdata = (grptag_t *)nsc_lookup(volhash, group_name);
1959 			if (gdata) {
1960 				if (strlen(gdata->ctag) != 0) {
1961 					errno = EINVAL;
1962 					dsw_error(gettext("Unable to put set "
1963 					    "into -C local and specified "
1964 					    "group"), NULL);
1965 				}
1966 			}
1967 		}
1968 		break;
1969 	}
1970 
1971 	/*
1972 	 * If we've got a group name, add it into the config
1973 	 */
1974 	if (group_name) {
1975 		strncpy(parms.group_name, group_name, DSW_NAMELEN);
1976 	}
1977 
1978 	/*
1979 	 * Determine accessability of volumes
1980 	 */
1981 	if (stat(master_volume, &mstat) != 0)
1982 		dsw_error(gettext(
1983 			"Unable to access master volume"), NULL);
1984 	if (!S_ISCHR(mstat.st_mode))
1985 		dsw_error(gettext(
1986 			"Master volume is not a character device"), NULL);
1987 	/* check the shadow_vol hasn't be used as SNDR secondary vol */
1988 	check_iishadow(shadow_volume);
1989 	if (stat(shadow_volume, &sstat) != 0)
1990 		dsw_error(gettext(
1991 			"Unable to access shadow volume"), NULL);
1992 	if (!S_ISCHR(sstat.st_mode))
1993 		dsw_error(gettext(
1994 			"Shadow volume is not a character device"), NULL);
1995 	if (mounted(shadow_volume)) {
1996 		errno = EBUSY;
1997 		dsw_error(gettext(
1998 			"Shadow volume is mounted, unmount it first"), NULL);
1999 	}
2000 	if (mstat.st_rdev == sstat.st_rdev) {
2001 		errno = EINVAL;
2002 		dsw_error(gettext(
2003 		    "Master and shadow are the same device"), NULL);
2004 	}
2005 	if (stat(bitmap_volume, &bstat) != 0) {
2006 		dsw_error(gettext("Unable to access bitmap"), NULL);
2007 	}
2008 	if (!S_ISCHR(bstat.st_mode))
2009 		dsw_error(gettext(
2010 			"Bitmap volume is not a character device"), NULL);
2011 	if (S_ISCHR(bstat.st_mode)) {
2012 		if (mstat.st_rdev == bstat.st_rdev) {
2013 			errno = EINVAL;
2014 			dsw_error(gettext(
2015 			    "Master and bitmap are the same device"), NULL);
2016 		} else if (sstat.st_rdev == bstat.st_rdev) {
2017 			errno = EINVAL;
2018 			dsw_error(gettext(
2019 			    "Shadow and bitmap are the same device"), NULL);
2020 		}
2021 	}
2022 
2023 	strncpy(parms.master_vol, master_volume, DSW_NAMELEN);
2024 	strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
2025 	strncpy(parms.bitmap_vol, bitmap_volume, DSW_NAMELEN);
2026 	errno = 0;
2027 	parms.status = spcs_s_ucreate();
2028 
2029 	/*
2030 	 * Check that none of the member volumes forms part of another
2031 	 * InstantImage group.
2032 	 *
2033 	 * -- this check has been removed; it is done in the kernel instead
2034 	 * -- PJW
2035 	 */
2036 
2037 	/*
2038 	 * Check against overflow volumes
2039 	 */
2040 	for (p = get_overflow_list(); *p != NULL; p += DSW_NAMELEN) {
2041 		if (strncmp(master_volume, p, DSW_NAMELEN) == 0)
2042 			dsw_error(gettext(
2043 				"Master volume is already an overflow volume"),
2044 				NULL);
2045 		else if (strncmp(shadow_volume, p, DSW_NAMELEN) == 0)
2046 			dsw_error(gettext(
2047 				"Shadow volume is already an overflow volume"),
2048 				NULL);
2049 		else if (strncmp(bitmap_volume, p, DSW_NAMELEN) == 0)
2050 			dsw_error(gettext(
2051 				"Bitmap volume is already an overflow volume"),
2052 				NULL);
2053 	}
2054 
2055 	/*
2056 	 * Make sure that the shadow volume is not already configured
2057 	 */
2058 	if (find_shadow_config(shadow_volume, NULL, &temp))
2059 		dsw_error(gettext(
2060 			"Shadow volume is already configured"), NULL);
2061 	if (perform_autosv()) {
2062 		/*
2063 		 * parse the dsvol entries to see if we need to place
2064 		 * the master or shadow under SV control
2065 		 */
2066 		if (nsc_lookup(volhash, master_volume) == NULL) {
2067 			if (cfg_vol_enable(cfg, master_volume, cfg_cluster_tag,
2068 			    "ii") < 0) {
2069 				dsw_error(
2070 				    gettext("Cannot enable master volume"),
2071 				    NULL);
2072 			}
2073 			mvol_enabled = 1;
2074 		} else {
2075 			mvol_enabled = 0;
2076 		}
2077 		if (nsc_lookup(volhash, shadow_volume) == NULL) {
2078 			if (nflg) {
2079 				cfg_resource(cfg, shd_dg);
2080 				rc = cfg_vol_enable(cfg, shadow_volume,
2081 					shd_dg, "ii");
2082 				cfg_resource(cfg, cfg_cluster_tag);
2083 			} else {
2084 				rc = cfg_vol_enable(cfg, shadow_volume,
2085 					cfg_cluster_tag, "ii");
2086 			}
2087 			if (rc < 0) {
2088 				if (mvol_enabled) {
2089 					if (cfg_vol_disable(cfg,
2090 					    master_volume, cfg_cluster_tag,
2091 					    "ii") < 0)
2092 					    dsw_error(gettext(
2093 						"SV disable of master failed"),
2094 						NULL);
2095 				}
2096 				dsw_error(
2097 				    gettext("Cannot enable shadow volume"),
2098 				    NULL);
2099 			}
2100 		}
2101 		unload_ii_vols();
2102 		cfg_unload_shadows();
2103 		cfg_unload_dsvols();
2104 		cfg_unload_svols();
2105 		reload_vols = 0;
2106 	}
2107 
2108 	add_cfg_entry(&parms);
2109 	cfg_unlock(cfg);
2110 	config_locked = 0;
2111 
2112 	sigset(SIGCHLD, sigchild);
2113 	switch (child = fork()) {
2114 
2115 	case (pid_t)-1:
2116 		dsw_error(gettext("Unable to fork"), NULL);
2117 		break;
2118 
2119 	case 0:
2120 		rc = do_ioctl(dsw_fd, DSWIOC_ENABLE, &parms);
2121 		if (rc == -1 && errno != DSW_EABORTED && errno != DSW_EIO) {
2122 			/*
2123 			 * Failed to enable shadow group, log problem and remove
2124 			 * the shadow group from the config file.
2125 			 */
2126 			spcs_log("ii", &parms.status,
2127 			    gettext("Enable failed %s %s %s (%s)"),
2128 			    master_volume, shadow_volume, bitmap_volume,
2129 			    parms.flag & DSW_GOLDEN ?
2130 			    "independent" : "dependent");
2131 
2132 			if (!ii_lock(cfg, CFG_WRLOCK) ||
2133 			    !find_shadow_config(shadow_volume, NULL, &temp)) {
2134 				dsw_error(gettext(
2135 					"Enable failed, can't tidy up cfg"),
2136 					&parms.status);
2137 			}
2138 			config_locked = 1;
2139 			remove_iiset(setnumber, shadow_volume, 0);
2140 			dsw_error(gettext("Enable failed"), &parms.status);
2141 		}
2142 
2143 		if (rc == -1)
2144 			sp_info = &parms.status;
2145 		else
2146 			sp_info = NULL;
2147 		spcs_log("ii", sp_info, gettext("Enabled %s %s %s (%s)"),
2148 			master_volume, shadow_volume, bitmap_volume,
2149 			parms.flag & DSW_GOLDEN ? "independent" : "dependent");
2150 		spcs_s_ufree(&parms.status);
2151 		break;
2152 
2153 	default:
2154 		exit(child_wait(child, Status, shadow_volume));
2155 		break;
2156 	}
2157 }
2158 
2159 int
2160 reset(char *volume)
2161 {
2162 	dsw_ioctl_t args;
2163 	dsw_config_t parms;
2164 	int	rc;
2165 	int	wait_loc;
2166 	pid_t	child = (pid_t)0;
2167 	enum copy_wait wait_action;
2168 	spcs_s_info_t *stat;
2169 	dsw_stat_t prev_stat;
2170 	int stat_flags;
2171 	static int unlocked = 0;
2172 	int	do_enable = 0;
2173 	char	key[CFG_MAX_KEY];
2174 	char	optval[CFG_MAX_BUF];
2175 	unsigned int flags;
2176 
2177 	wait_action = WaitForStart;
2178 
2179 	if (unlocked && !ii_lock(cfg, CFG_RDLOCK)) {
2180 		dsw_error(gettext("Unable to set locking on the configuration"),
2181 		    NULL);
2182 	}
2183 	config_locked = 1;
2184 	if (!find_shadow_config(volume, &parms, &args))
2185 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2186 		    "group"), NULL);
2187 
2188 	cfg_unlock(cfg);
2189 	config_locked = 0;
2190 	unlocked = 1;
2191 
2192 	spcs_log("ii", NULL, gettext("Start reset %s"), volume);
2193 	strncpy(prev_stat.shadow_vol, volume, DSW_NAMELEN);
2194 	prev_stat.shadow_vol[DSW_NAMELEN - 1] = '\0';
2195 	prev_stat.status = spcs_s_ucreate();
2196 	if (do_ioctl(dsw_fd, DSWIOC_STAT, &prev_stat) == -1) {
2197 		/* set is suspended, so we do the enable processing instead */
2198 		do_enable = 1;
2199 
2200 		/* first check to see whether the set was offline */
2201 		snprintf(key, CFG_MAX_KEY, "ii.set%d.options", setnumber);
2202 		if (!ii_lock(cfg, CFG_RDLOCK)) {
2203 			dsw_error(gettext("Unable to set locking on the "
2204 			    "configuration"), NULL);
2205 		}
2206 		config_locked = 1;
2207 		unlocked = 0;
2208 		if (cfg_get_single_option(cfg, CFG_SEC_CONF, key,
2209 		    NSKERN_II_BMP_OPTION, optval, CFG_MAX_BUF) < 0) {
2210 			dsw_error(gettext("unable to read config file"), NULL);
2211 		}
2212 		cfg_unlock(cfg);
2213 		config_locked = 0;
2214 		unlocked = 1;
2215 		sscanf(optval, "%x", &flags);
2216 		if ((flags & DSW_OFFLINE) == 0) {
2217 			/* set wasn't offline - don't reset */
2218 			dsw_error(gettext("Set not offline, will not reset"),
2219 			    NULL);
2220 		}
2221 		parms.status = spcs_s_ucreate();
2222 		stat = &parms.status;
2223 		stat_flags = DSW_BMPOFFLINE;
2224 	} else {
2225 		args.status = spcs_s_ucreate();
2226 		stat = &args.status;
2227 		stat_flags = prev_stat.stat;
2228 	}
2229 	spcs_s_ufree(&prev_stat.status);
2230 
2231 	if (wait_action == WaitForStart)
2232 		sigset(SIGCHLD, sigchild);
2233 
2234 	switch (child = fork()) {
2235 
2236 	case (pid_t)-1:
2237 		dsw_error(gettext("Unable to fork"), NULL);
2238 		break;
2239 
2240 	case 0:
2241 		if (do_enable) {
2242 			rc = do_ioctl(dsw_fd, DSWIOC_ENABLE, &parms);
2243 		} else {
2244 			rc = do_ioctl(dsw_fd, DSWIOC_RESET, &args);
2245 		}
2246 		if (rc == -1 && errno != DSW_EABORTED && errno != DSW_EIO) {
2247 			spcs_log("ii", stat, gettext("Fail reset %s"), volume);
2248 			dsw_error(gettext("Reset shadow failed"), stat);
2249 		}
2250 		/* last_overflow is set during find_shadow_config */
2251 		if (strlen(last_overflow) > 0 &&
2252 		    (stat_flags & (DSW_SHDOFFLINE | DSW_BMPOFFLINE)) != 0) {
2253 			/* reattach it */
2254 			strncpy(parms.bitmap_vol, last_overflow, DSW_NAMELEN);
2255 			do_attach(&parms);
2256 		}
2257 		spcs_log("ii", stat, gettext("Finish reset %s"), volume);
2258 		spcs_s_ufree(stat);
2259 
2260 		exit(0);
2261 		break;
2262 	default:
2263 		if (wait_action == WaitForStart) {
2264 			rc = child_wait(child, CopyStart, args.shadow_vol);
2265 		} else { /* wait_action == WaitForEnd */
2266 			wait_loc = 0;
2267 			wait(&wait_loc);
2268 			if (WIFEXITED(wait_loc) && (WEXITSTATUS(wait_loc) == 0))
2269 				rc = 0;
2270 			else
2271 				rc = -1;
2272 		}
2273 		break;
2274 	}
2275 	/* if successful, remove flags entry from options field */
2276 	if (rc >= 0) {
2277 		if (!ii_lock(cfg, CFG_WRLOCK)) {
2278 			dsw_error(gettext("Unable to set locking on the "
2279 			    "configuration"), NULL);
2280 		}
2281 		config_locked = 1;
2282 		if (!find_shadow_config(volume, &parms, &args)) {
2283 			dsw_error(gettext("Volume is not in a Point-in-Time "
2284 			    "Copy group"), NULL);
2285 		}
2286 		snprintf(key, CFG_MAX_KEY, "ii.set%d.options", setnumber);
2287 		if (cfg_del_option(cfg, CFG_SEC_CONF, key, NSKERN_II_BMP_OPTION)
2288 		    < 0) {
2289 			dsw_error(gettext("Update of config failed"), NULL);
2290 		}
2291 		cfg_commit(cfg);
2292 		cfg_unlock(cfg);
2293 		config_locked = 0;
2294 	}
2295 
2296 	return (rc);
2297 }
2298 
2299 int
2300 overflow(char *volume)
2301 {
2302 	dsw_ioctl_t args;
2303 	int	rc;
2304 	spcs_s_info_t *stat;
2305 
2306 	check_action(gettext("Initialize this overflow volume?"));
2307 	if (find_matching_cf_line(volume, NULL, &args))
2308 		dsw_error(gettext("Volume is part of a Point-in-Time Copy "
2309 					    "group"), NULL);
2310 	args.status = spcs_s_ucreate();
2311 	strncpy(args.shadow_vol, volume, DSW_NAMELEN);
2312 	rc = do_ioctl(dsw_fd, DSWIOC_OCREAT, &args);
2313 	if (rc == -1) {
2314 		spcs_log("ii", &args.status,
2315 			gettext("Create overflow failed %s"), volume);
2316 		dsw_error(gettext("Create overflow failed"), &args.status);
2317 	}
2318 	if (rc == -1)
2319 		stat = &args.status;
2320 	else
2321 		stat = NULL;
2322 	spcs_log("ii", stat, gettext("Create overflow succeeded %s"), volume);
2323 	spcs_s_ufree(&args.status);
2324 
2325 	return (0);
2326 }
2327 
2328 void
2329 bitmap_op(char *master_volume, int print_bitmap, int bitmap_percent, int used,
2330     int is_compact)
2331 {
2332 	unsigned char *bitmap;
2333 	char *name;
2334 	int i, x, y;
2335 	unsigned j;
2336 	unsigned long n;
2337 	unsigned long percent;
2338 
2339 	bitmap = allocate_bitmap(master_volume);
2340 	if (bitmap == NULL)
2341 		return;
2342 
2343 	if (bitmap_percent) {
2344 		/* count the number of bits set in bitmap */
2345 		for (i = n = 0; i < bm_size; i++)
2346 			for (j = (unsigned)bitmap[i]; j; j &= j -1)
2347 				n++;
2348 		if (is_compact)
2349 			(void) printf(gettext("Chunks in map: %d used: %d\n"),
2350 			    used, n);
2351 		if (bm_actual < 100) {
2352 			percent = 0;
2353 		} else {
2354 			percent = (n * 100) / bm_actual;
2355 		}
2356 		(void) printf(gettext("Percent of bitmap set: %u\n"), percent);
2357 		percent = percent/100;
2358 		/* distinguish between 0.0000% and 0.n% of bitmap set */
2359 		if (percent < 1)
2360 			(void) printf("\t(%s)\n", n > 0 ?
2361 			    gettext("bitmap dirty") : gettext("bitmap clean"));
2362 	}
2363 
2364 	if (print_bitmap) {
2365 		name = strrchr(master_volume, '/');
2366 		if (name++ == NULL)
2367 		name = master_volume;
2368 		i = bm_size * 8;
2369 		x = (int)ceil(sqrt((double)i));
2370 		x += (8 - (x % 8));	/* round up to nearest multiple of 8 */
2371 		y = i / x;
2372 		if (y * x < i)
2373 			y++;
2374 		(void) printf("#define bm%s_width %d\n#define bm%s_height %d\n",
2375 		    name, x, name, y);
2376 		(void) printf("#define bm%s_x_hot 0\n#define bm%s_y_hot 0\n",
2377 		    name, name);
2378 		(void) printf("static char bm%s_bits[] = {\n", name);
2379 		for (i = 0; i < bm_size; i++) {
2380 			if (i % 12 == 0)
2381 				(void) printf("\n");
2382 			(void) printf("0x%02x, ", bitmap[i]);
2383 		}
2384 		y = x * y;
2385 		for (; i < y; i++) {
2386 			if (i % 12 == 0)
2387 				(void) printf("\n");
2388 			(void) printf("0x00, ");
2389 		}
2390 		(void) printf("\n};\n");
2391 	}
2392 
2393 	free_bitmap(bitmap);
2394 }
2395 
2396 static int
2397 validate_group_names(char **vol_list, char *group)
2398 {
2399 	ENTRY item, *found;
2400 	int i, rc, count;
2401 	dsw_aioctl_t *group_list;
2402 	char *ptr;
2403 
2404 	if (group == NULL || *group == NULL) {
2405 		/* no group set, just count volume list */
2406 		for (i = 0; *vol_list++ != NULL; i++)
2407 			;
2408 		return (i);
2409 	}
2410 
2411 	if ((count = do_ioctl(dsw_fd, DSWIOC_LISTLEN, NULL)) < 0)
2412 		dsw_error("DSWIOC_LISTLEN", NULL);
2413 
2414 	group_list = malloc(sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
2415 	if (group_list == NULL)
2416 		dsw_error(gettext("Failed to allocate memory"), NULL);
2417 
2418 	bzero(group_list, sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
2419 	group_list->count = count;
2420 	group_list->flags = 0;
2421 	group_list->status = spcs_s_ucreate();
2422 	strncpy(group_list->shadow_vol, group, DSW_NAMELEN);
2423 
2424 	rc = do_ioctl(dsw_fd, DSWIOC_GLIST, group_list);
2425 	if (rc < 0)
2426 		dsw_error(gettext("Group list access failure"),
2427 		    &group_list->status);
2428 
2429 	group_list->shadow_vol[DSW_NAMELEN * group_list->count] = '\0';
2430 
2431 	/* create hash and enter all volumes into it */
2432 	if (hcreate(group_list->count) == 0)
2433 		dsw_error(gettext("Failed to allocate memory"), NULL);
2434 	ptr = group_list->shadow_vol;
2435 	count = group_list->count;
2436 	i = 0;
2437 	while (i < count) {
2438 		ptr[ DSW_NAMELEN - 1 ] = '\0';
2439 		item.key = ptr;
2440 		item.data = (void *) 0;
2441 		(void) hsearch(item, ENTER);
2442 		++i;
2443 		ptr += DSW_NAMELEN;
2444 	}
2445 
2446 	/* now compare the volume list with the hash */
2447 	for (i = 0; vol_list[ i ]; i++) {
2448 		item.key = vol_list[ i ];
2449 		found = hsearch(item, FIND);
2450 		if (!found)
2451 			dsw_error(gettext("Group config does not match kernel"),
2452 			    NULL);
2453 		if (found->data != (void *) 0)
2454 			dsw_error(gettext("Duplicate volume specified"), NULL);
2455 		found->data = (void *) 1;
2456 	}
2457 	if (i != count)
2458 		dsw_error(gettext("Group config does not match kernel"), NULL);
2459 
2460 	/* everything checks out */
2461 	free(group_list);
2462 	hdestroy();
2463 
2464 	return (count);
2465 }
2466 
2467 int
2468 do_acopy(char **vol_list, enum copy_update update_mode,
2469 		enum copy_direction direction)
2470 {
2471 	dsw_aioctl_t *acopy_args;
2472 	dsw_ioctl_t copy_args;
2473 	dsw_config_t parms;
2474 	dsw_stat_t	stat_s;
2475 	int	i;
2476 	int	rc;
2477 	int	n_vols;
2478 	char	*t;
2479 	char	buf[1024];
2480 	char	*sp;
2481 	char	*ppid;
2482 
2483 	n_vols = validate_group_names(vol_list, group_name);
2484 
2485 	acopy_args = calloc(sizeof (dsw_aioctl_t) + n_vols * DSW_NAMELEN, 1);
2486 	if (acopy_args == NULL)
2487 		dsw_error(gettext("Too many volumes given for update"), NULL);
2488 
2489 	acopy_args->count = n_vols;
2490 
2491 	acopy_args->flags = 0;
2492 
2493 	if (update_mode == Update)
2494 		acopy_args->flags |= CV_BMP_ONLY;
2495 	if (direction == ToMaster)
2496 		acopy_args->flags |= CV_SHD2MST;
2497 	if (pflg) {
2498 		acopy_args->flags |= CV_LOCK_PID;
2499 #ifdef DEBUG
2500 		ppid = getenv("IIADM_PPID");
2501 		if (ppid) {
2502 			acopy_args->pid = atoi(ppid);
2503 			fprintf(stderr, "(using %s for ppid)\n", ppid);
2504 		} else {
2505 			acopy_args->pid = getppid();
2506 		}
2507 #else
2508 		acopy_args->pid = getppid();
2509 #endif
2510 	}
2511 
2512 	for (i = 0; i < n_vols; i++) {
2513 		if (!find_shadow_config(vol_list[i], &parms, &copy_args))
2514 			dsw_error(gettext("Volume is not in a Point-in-Time "
2515 			    "group"), NULL);
2516 		if (direction == ToMaster) {
2517 			t = parms.master_vol;
2518 		} else {
2519 			t = parms.shadow_vol;
2520 		}
2521 
2522 		if (mounted(t)) {
2523 			errno = EBUSY;
2524 			dsw_error(gettext("Target of copy/update is mounted, "
2525 						"unmount it first"), NULL);
2526 		}
2527 
2528 		strncpy(stat_s.shadow_vol, parms.shadow_vol, DSW_NAMELEN);
2529 		stat_s.shadow_vol[DSW_NAMELEN-1] = '\0';
2530 		stat_s.status = spcs_s_ucreate();
2531 		rc = do_ioctl(dsw_fd, DSWIOC_STAT, &stat_s);
2532 		spcs_s_ufree(&stat_s.status);
2533 		if (rc == -1) {
2534 			(void) sprintf(buf,
2535 			    gettext("Shadow group %s is suspended"),
2536 			    vol_list[i]);
2537 			dsw_error(buf, NULL);
2538 		}
2539 
2540 		if (stat_s.stat & DSW_COPYINGP) {
2541 			(void) fprintf(stderr, "%s: %s\n", cmdnam,
2542 			    gettext("Copy already in progress"));
2543 			exit(1);
2544 		}
2545 	}
2546 	acopy_args->status = spcs_s_ucreate();
2547 	for (i = 0; i < n_vols; i++) {
2548 		spcs_log("ii", NULL, gettext("Atomic %s %s %s"),
2549 			update_mode == Update ?
2550 				gettext("update") : gettext("copy"),
2551 			vol_list[i],
2552 			direction == ToMaster ?  gettext("from shadow") :
2553 			gettext("to shadow"));
2554 	}
2555 	if (group_name == NULL || *group_name == NULL) {
2556 		sp = acopy_args->shadow_vol;
2557 		for (i = 0; i < n_vols; i++, sp += DSW_NAMELEN)
2558 			strncpy(sp, vol_list[i], DSW_NAMELEN);
2559 	} else {
2560 		strncpy(acopy_args->shadow_vol, group_name, DSW_NAMELEN);
2561 		acopy_args->flags |= CV_IS_GROUP;
2562 	}
2563 	rc = do_ioctl(dsw_fd, DSWIOC_ACOPY, acopy_args);
2564 	if (rc == -1) {
2565 		i = acopy_args->count;
2566 		if (i < 0 || i >= n_vols) {
2567 			spcs_log("ii", NULL, gettext("Atomic update failed"));
2568 			(void) sprintf(buf, gettext("Update failed"));
2569 		} else {
2570 			spcs_log("ii", NULL,
2571 				gettext("Atomic update of %s failed"),
2572 				vol_list[acopy_args->count]);
2573 			(void) sprintf(buf, gettext("Update of %s failed"),
2574 			    vol_list[acopy_args->count]);
2575 		}
2576 		dsw_error(buf, &(acopy_args->status));
2577 	}
2578 	return (rc);
2579 }
2580 
2581 int
2582 do_copy(char **vol_list, enum copy_update update_mode,
2583 		enum copy_direction direction, enum copy_wait wait_action)
2584 {
2585 	dsw_ioctl_t copy_args;
2586 	dsw_config_t parms;
2587 	dsw_stat_t	stat_s;
2588 	int	rc;
2589 	int	wait_loc;
2590 	char	*t;
2591 	char	*volume;
2592 	pid_t	child = (pid_t)0;
2593 	char	*ppid;
2594 
2595 	if (vol_list[0] && vol_list[1])
2596 		return (do_acopy(vol_list, update_mode, direction));
2597 
2598 	volume = vol_list[0];
2599 	if (!find_shadow_config(volume, &parms, &copy_args))
2600 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2601 					    "group"), NULL);
2602 
2603 	cfg_unlock(cfg);
2604 	config_locked = 0;
2605 	copy_args.flags = 0;
2606 
2607 	if (update_mode == Update)
2608 		copy_args.flags |= CV_BMP_ONLY;
2609 	if (direction == ToMaster) {
2610 		copy_args.flags |= CV_SHD2MST;
2611 		t = parms.master_vol;
2612 	} else {
2613 		t = parms.shadow_vol;
2614 	}
2615 	if (pflg) {
2616 		copy_args.flags |= CV_LOCK_PID;
2617 #ifdef DEBUG
2618 		ppid = getenv("IIADM_PPID");
2619 		if (ppid) {
2620 			copy_args.pid = atoi(ppid);
2621 			fprintf(stderr, "(using %s for ppid)\n", ppid);
2622 		} else {
2623 			copy_args.pid = getppid();
2624 		}
2625 #else
2626 		copy_args.pid = getppid();
2627 #endif
2628 	}
2629 
2630 	if (mounted(t)) {
2631 		errno = EBUSY;
2632 		dsw_error(gettext("Target of copy/update is mounted, "
2633 					"unmount it first"), NULL);
2634 	}
2635 
2636 	strncpy(stat_s.shadow_vol, copy_args.shadow_vol, DSW_NAMELEN);
2637 	stat_s.shadow_vol[DSW_NAMELEN-1] = '\0';
2638 	stat_s.status = spcs_s_ucreate();
2639 	rc = do_ioctl(dsw_fd, DSWIOC_STAT, &stat_s);
2640 	spcs_s_ufree(&stat_s.status);
2641 	if (rc == -1)
2642 		dsw_error(gettext("Shadow group suspended"), NULL);
2643 
2644 	if (stat_s.stat & DSW_COPYINGP) {
2645 		(void) fprintf(stderr, "%s: %s\n", cmdnam,
2646 		    gettext("Copy already in progress"));
2647 		exit(1);
2648 	}
2649 
2650 	copy_args.status = spcs_s_ucreate();
2651 	spcs_log("ii", NULL, gettext("Start %s %s %s"),
2652 			update_mode == Update ?
2653 				gettext("update") : gettext("copy"),
2654 			volume,
2655 			direction == ToMaster ?  gettext("from shadow") :
2656 			gettext("to shadow"));
2657 
2658 	if (wait_action == WaitForStart)
2659 		sigset(SIGCHLD, sigchild);
2660 	switch (child = fork()) {
2661 
2662 	case (pid_t)-1:
2663 		dsw_error(gettext("Unable to fork"),
2664 					NULL);
2665 		break;
2666 
2667 	case 0:
2668 		rc = do_ioctl(dsw_fd, DSWIOC_COPY, &copy_args);
2669 		if (rc == -1) {
2670 			spcs_log("ii", &copy_args.status,
2671 			    gettext("Fail %s %s %s"),
2672 			    update_mode == Update ?
2673 					gettext("update") : gettext("copy"),
2674 			    volume,
2675 			    direction == ToMaster ?  gettext("from shadow")
2676 					: gettext("to shadow"));
2677 			dsw_error(gettext("Copy failed"), &copy_args.status);
2678 		}
2679 		spcs_s_ufree(&copy_args.status);
2680 		spcs_log("ii", NULL, gettext("Finish %s %s %s"),
2681 		    update_mode == Update ?
2682 				gettext("update") : gettext("copy"),
2683 		    volume,
2684 		    direction == ToMaster ?  gettext("from shadow") :
2685 				gettext("to shadow"));
2686 
2687 		exit(0);
2688 		break;
2689 	default:
2690 		if (wait_action == WaitForStart) {
2691 			rc = child_wait(child, CopyStart, copy_args.shadow_vol);
2692 		} else { /* wait_action == WaitForEnd */
2693 			wait_loc = 0;
2694 			wait(&wait_loc);
2695 			if (WIFEXITED(wait_loc) && (WEXITSTATUS(wait_loc) == 0))
2696 				rc = 0;
2697 			else
2698 				rc = 1;
2699 		}
2700 		break;
2701 	}
2702 	return (rc);
2703 }
2704 
2705 void
2706 print_status(dsw_config_t *conf, int in_config)
2707 {
2708 	dsw_stat_t args;
2709 	int	stat_flags;
2710 	static int need_sep = 0;
2711 	time_t tmp_time;
2712 
2713 	if (need_sep++ > 0)
2714 		(void) printf("--------------------------------------"
2715 		    "----------------------------------------\n");
2716 	strncpy(args.shadow_vol, conf->shadow_vol, DSW_NAMELEN);
2717 	args.shadow_vol[DSW_NAMELEN-1] = '\0';
2718 	if (in_config) {
2719 		(void) printf("%s: %s\n",
2720 		    conf->master_vol, gettext("(master volume)"));
2721 		(void) printf("%s: %s\n",
2722 		    conf->shadow_vol, gettext("(shadow volume)"));
2723 		(void) printf("%s: %s\n",
2724 		    conf->bitmap_vol, gettext("(bitmap volume)"));
2725 	}
2726 
2727 	/*
2728 	 * Do special checking on the status of this volume in a Sun Cluster
2729 	 */
2730 	if (check_cluster() == II_CLUSTER) {
2731 	    char dgname[CFG_MAX_BUF], *other_node;
2732 
2733 	    if (cfg_dgname(conf->bitmap_vol, dgname, sizeof (dgname))) {
2734 		if (strlen(dgname)) {
2735 		    int rc = cfg_dgname_islocal(dgname, &other_node);
2736 		    if (rc < 0) {
2737 			(void) printf(gettext(
2738 			    "Suspended on this node, not active elsewhere\n"));
2739 			return;
2740 		    } else if (rc == 0) {
2741 			(void) printf(gettext(
2742 				"Suspended on this node, active on %s\n"),
2743 				other_node);
2744 			return;
2745 		    }
2746 		}
2747 	    }
2748 	}
2749 
2750 	args.status = spcs_s_ucreate();
2751 	if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) {
2752 
2753 		/* Handle Not found or not in config */
2754 		if (errno != DSW_ENOTFOUND || !in_config)
2755 			dsw_error(gettext("Stat failed"), &args.status);
2756 
2757 		/* Just suspend */
2758 		(void) printf(gettext("Suspended.\n"));
2759 		return;
2760 	}
2761 
2762 	if (args.overflow_vol[0] != '\0')
2763 		(void) printf("%s: %s\n", args.overflow_vol,
2764 		    gettext("(overflow volume)"));
2765 
2766 	if (conf->group_name[0] != '\0')
2767 		(void) printf(gettext("Group name: %s\n"),
2768 			    conf->group_name);
2769 
2770 	if (conf->cluster_tag[0] != '\0')
2771 		(void) printf(gettext("Cluster tag: %s\n"),
2772 			    conf->cluster_tag);
2773 
2774 	stat_flags = args.stat;
2775 	spcs_s_ufree(&args.status);
2776 	if (stat_flags & DSW_GOLDEN)
2777 		(void) printf(gettext("Independent copy"));
2778 	else
2779 		(void) printf(gettext("Dependent copy"));
2780 
2781 	if (stat_flags & DSW_TREEMAP)
2782 		(void) printf(gettext(", compacted shadow space"));
2783 
2784 	if (stat_flags & DSW_COPYINGP)
2785 		(void) printf(gettext(", copy in progress"));
2786 	else if (stat_flags & DSW_COPYING)
2787 		(void) printf(gettext(", copy not active"));
2788 
2789 	if (stat_flags & DSW_COPYINGM)
2790 		(void) printf(gettext(", copying master to shadow"));
2791 
2792 	if (stat_flags & DSW_COPYINGS)
2793 		(void) printf(gettext(", copying shadow to master"));
2794 
2795 	if (stat_flags & DSW_COPYINGX)
2796 		(void) printf(gettext(", abort of copy requested"));
2797 
2798 	if (stat_flags & DSW_MSTOFFLINE)
2799 		(void) printf(gettext(", master volume offline"));
2800 
2801 	if (stat_flags & DSW_SHDOFFLINE)
2802 		(void) printf(gettext(", shadow volume offline"));
2803 
2804 	if (stat_flags & DSW_BMPOFFLINE)
2805 		(void) printf(gettext(", bitmap volume offline"));
2806 
2807 	if (stat_flags & DSW_OVROFFLINE)
2808 		(void) printf(gettext(", overflow volume offline"));
2809 
2810 	if (stat_flags & DSW_SHDEXPORT)
2811 		(void) printf(gettext(", shadow volume exported"));
2812 
2813 	if (stat_flags & DSW_SHDIMPORT)
2814 		(void) printf(gettext(", shadow volume imported"));
2815 
2816 	if (stat_flags & DSW_OVERFLOW)
2817 		(void) printf(gettext(", out of space"));
2818 
2819 	if (stat_flags & DSW_VOVERFLOW)
2820 		(void) printf(gettext(", spilled into overflow volume"));
2821 	(void) printf("\n");
2822 
2823 	tmp_time = args.mtime;
2824 	if (tmp_time != 0)
2825 		(void) printf("%s %s", gettext("Latest modified time:"),
2826 			ctime(&tmp_time));
2827 	else
2828 		(void) printf("%s\n", gettext("Latest modified time: unknown"));
2829 
2830 	(void) printf("%s %8llu\n", gettext("Volume size:"), args.size);
2831 	if (args.shdsize != 0) {
2832 		(void) printf("%s %lld %s %lld\n",
2833 			gettext("Shadow chunks total:"), args.shdsize,
2834 			gettext("Shadow chunks used:"), args.shdused);
2835 	}
2836 	bitmap_op(args.shadow_vol, 0, 1, 0, 0);
2837 }
2838 
2839 int
2840 abort_copy(char *volume)
2841 {
2842 	dsw_ioctl_t args;
2843 
2844 	if (!find_shadow_config(volume, NULL, &args))
2845 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2846 						"group"), NULL);
2847 	args.status = spcs_s_ucreate();
2848 	if (do_ioctl(dsw_fd, DSWIOC_ABORT, &args)  == -1)
2849 		dsw_error(gettext("Abort failed"), &args.status);
2850 	spcs_log("ii", NULL, gettext("Abort %s"), args.shadow_vol);
2851 	spcs_s_ufree(&args.status);
2852 	return (0);
2853 }
2854 
2855 void
2856 iiversion()
2857 {
2858 	dsw_version_t args;
2859 
2860 	args.status = spcs_s_ucreate();
2861 	if (do_ioctl(dsw_fd, DSWIOC_VERSION, &args)  == -1)
2862 		dsw_error(gettext("Version failed"), &args.status);
2863 	spcs_s_ufree(&args.status);
2864 #ifdef DEBUG
2865 	(void) printf(gettext("Point in Time Copy version %d.%d.%d.%d\n"),
2866 	    args.major, args.minor, args.micro, args.baseline);
2867 #else
2868 	if (args.micro) {
2869 		(void) printf(gettext("Point in Time Copy version %d.%d.%d\n"),
2870 		    args.major, args.minor, args.micro);
2871 	} else {
2872 		(void) printf(gettext("Point in Time Copy version %d.%d\n"),
2873 		    args.major, args.minor);
2874 	}
2875 #endif
2876 }
2877 
2878 void
2879 list_volumes()
2880 {
2881 	dsw_list_t args;
2882 	int i, set, found;
2883 	dsw_config_t *lp;
2884 	ENTRY item, *ip;
2885 	dsw_config_t parms;
2886 
2887 	if ((i = do_ioctl(dsw_fd, DSWIOC_LISTLEN, &args)) == -1)
2888 		dsw_error("DSWIOC_LISTLEN", NULL);
2889 
2890 	args.status = spcs_s_ucreate();
2891 	args.list_used = 0;
2892 	args.list_size = i + 4;
2893 	lp = args.list = (dsw_config_t *)
2894 	    malloc(args.list_size * sizeof (dsw_config_t));
2895 
2896 	if (args.list == NULL)
2897 		dsw_error(gettext("Failed to allocate memory"), NULL);
2898 	if (do_ioctl(dsw_fd, DSWIOC_LIST, &args)  == -1)
2899 		dsw_error(gettext("List failed"), &args.status);
2900 	spcs_s_ufree(&args.status);
2901 
2902 	/* make a hashtable */
2903 	if (args.list_used > 0) {
2904 		if (hcreate(args.list_used) == 0) {
2905 			dsw_error(gettext("Failed to allocate memory"), NULL);
2906 			/*NOTREACHED*/
2907 		}
2908 	}
2909 
2910 	/* populate the hashtable */
2911 	for (i = 0; i < args.list_used; i++, lp++) {
2912 		item.key = lp->shadow_vol;
2913 		item.data = (char *)lp;
2914 		if (hsearch(item, ENTER) == NULL) {
2915 			dsw_error(gettext("Failed to allocate memory"), NULL);
2916 			/*NOTREACHED*/
2917 		}
2918 	}
2919 
2920 	/* perform action for each line of the stored config file */
2921 	for (set = 1; get_dsw_config(set, &parms) == 0; set++) {
2922 
2923 		/* Are there any II sets configured on this node? */
2924 		if (args.list_used > 0) {
2925 			item.key = parms.shadow_vol;
2926 
2927 			/* Is this volume configured on this node? */
2928 			if (ip = hsearch(item, FIND)) {
2929 
2930 				/* Handle Imported Shadows */
2931 				/* LINTED alignment of cast ok */
2932 				lp = (dsw_config_t *)ip->data;
2933 				if (strcmp(parms.master_vol,
2934 					II_IMPORTED_SHADOW))
2935 					found = !(lp->flag & DSW_SHDIMPORT);
2936 				else
2937 					found = (lp->flag & DSW_SHDIMPORT);
2938 			}
2939 			else
2940 				found = FALSE;
2941 		}
2942 		else
2943 			found = FALSE;
2944 
2945 		if ((cfg_cluster_tag) &&
2946 			strcmp(cfg_cluster_tag, parms.cluster_tag))
2947 			continue;
2948 
2949 		if ((group_name) && strcmp(group_name, parms.group_name))
2950 			continue;
2951 
2952 		(void) printf("%s %.*s %.*s %.*s%s\n",
2953 		    (parms.flag & DSW_GOLDEN) ? "ind" : "dep",
2954 		    DSW_NAMELEN, parms.master_vol,
2955 		    DSW_NAMELEN, parms.shadow_vol,
2956 		    DSW_NAMELEN, parms.bitmap_vol,
2957 		    found ? "" : gettext(" (suspended)"));
2958 	}
2959 	hdestroy();
2960 	free(args.list);
2961 }
2962 
2963 int
2964 wait_for_copy(char *volume)
2965 {
2966 	dsw_ioctl_t parms;
2967 	int rc;
2968 	static int unlocked = 0;
2969 	char *ppid;
2970 
2971 	if (unlocked && !ii_lock(cfg, CFG_RDLOCK)) {
2972 		dsw_error(gettext("Unable to set locking on the configuration"),
2973 		    NULL);
2974 	}
2975 	config_locked = 1;
2976 	if (!find_shadow_config(volume, NULL, &parms))
2977 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2978 						"group"), NULL);
2979 	cfg_unlock(cfg);
2980 	config_locked = 0;
2981 	unlocked = 1;
2982 
2983 	parms.status = spcs_s_ucreate();
2984 	if (pflg) {
2985 #ifdef DEBUG
2986 		ppid = getenv("IIADM_PPID");
2987 		if (ppid) {
2988 			parms.pid = atoi(ppid);
2989 			fprintf(stderr, "(using %s for ppid)\n", ppid);
2990 		} else {
2991 			parms.pid = (nflg) ? -1 : getppid();
2992 		}
2993 #else
2994 		parms.pid = (nflg) ? -1 : getppid();
2995 #endif
2996 		parms.flags |= CV_LOCK_PID;
2997 	}
2998 
2999 	rc = do_ioctl(dsw_fd, DSWIOC_WAIT, &parms);
3000 	if (rc == -1)
3001 		dsw_error(gettext("Wait failed"), &parms.status);
3002 	spcs_s_ufree(&parms.status);
3003 	return (0);
3004 }
3005 
3006 int
3007 export(char *volume)
3008 {
3009 	dsw_ioctl_t parms;
3010 	dsw_config_t conf;
3011 	char *old_ctag, dgname[DSW_NAMELEN];
3012 	int rc;
3013 
3014 	if (!find_shadow_config(volume, &conf, &parms))
3015 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3016 				"group"), NULL);
3017 	if (mounted(volume))
3018 		dsw_error(gettext("Can't export a mounted volume"), NULL);
3019 
3020 	/* If this is an exportable shadow in the cluster, change ctag */
3021 	if (strlen(conf.cluster_tag) &&
3022 	    (cfg_dgname(volume, dgname, sizeof (dgname)))) {
3023 		old_ctag = cfg_cluster_tag;
3024 		cfg_resource(cfg, cfg_cluster_tag = strdup(dgname));
3025 	} else	old_ctag = NULL;
3026 
3027 	if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) {
3028 		dsw_error(gettext("Unable to parse config file"), NULL);
3029 	}
3030 	reload_vols = LD_DSVOLS | LD_SHADOWS;
3031 	conform_name(&volume);
3032 
3033 	spcs_log("ii", NULL, gettext("Export %s"), volume);
3034 	parms.status = spcs_s_ucreate();
3035 	rc = do_ioctl(dsw_fd, DSWIOC_EXPORT, &parms);
3036 	if (rc == -1)
3037 		dsw_error(gettext("Export failed"), &parms.status);
3038 	if (perform_autosv()) {
3039 		if (cfg_vol_disable(cfg, volume, cfg_cluster_tag, "ii") < 0) {
3040 			dsw_error(gettext("SV-disable failed"), NULL);
3041 		}
3042 		cfg_commit(cfg);
3043 	}
3044 
3045 	/* restore old cluster tag, if changed */
3046 	if (old_ctag != NULL)
3047 		cfg_resource(cfg, cfg_cluster_tag = old_ctag);
3048 
3049 	spcs_s_ufree(&parms.status);
3050 	return (0);
3051 }
3052 
3053 int
3054 detach(char *volume)
3055 {
3056 	dsw_ioctl_t parms;
3057 	int rc;
3058 
3059 	if (!find_shadow_config(volume, NULL, &parms))
3060 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3061 						"group"), NULL);
3062 	parms.status = spcs_s_ucreate();
3063 	rc = do_ioctl(dsw_fd, DSWIOC_ODETACH, &parms);
3064 	if (rc == 0) {
3065 		/* remove overflow from cfg line */
3066 		(void) sprintf(key, "ii.set%d.overflow", setnumber);
3067 		if (cfg_put_cstring(cfg, key, "-", 1) < 0) {
3068 				perror("cfg_put_cstring");
3069 		}
3070 		(void) cfg_commit(cfg);
3071 	} else {
3072 		spcs_log("ii", NULL, gettext("Detach of overflow %s failed"),
3073 				parms.shadow_vol);
3074 		dsw_error(gettext("Failed to detach overflow volume"),
3075 				&parms.status);
3076 	}
3077 	return (rc);
3078 }
3079 
3080 static void
3081 can_disable(char *vol)
3082 {
3083 	dsw_stat_t args;
3084 
3085 	if (mounted(vol)) {
3086 		strncpy(args.shadow_vol, vol, DSW_NAMELEN);
3087 		args.shadow_vol[DSW_NAMELEN - 1] = '\0';
3088 		args.status = spcs_s_ucreate();
3089 		if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) != -1 &&
3090 		    (args.stat & DSW_GOLDEN) == 0) {
3091 			errno = EBUSY;
3092 			dsw_error(gettext("Shadow Volume is currently mounted "
3093 			    "and dependent on the master volume"), NULL);
3094 		}
3095 		spcs_s_ufree(&args.status);
3096 	}
3097 }
3098 
3099 static void
3100 clean_up_after_failed_disable(dsw_ioctl_t *parms)
3101 {
3102 	char **p;
3103 	dsw_stat_t args;
3104 
3105 	for (p = group_volumes; *p; p++) {
3106 		strncpy(args.shadow_vol, *p, DSW_NAMELEN);
3107 		args.shadow_vol[DSW_NAMELEN - 1] = '\0';
3108 		args.status = spcs_s_ucreate();
3109 		if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) {
3110 			/* set was successfully disabled */
3111 			if (find_shadow_config(*p, NULL, NULL))
3112 				remove_iiset(setnumber, *p, 0);
3113 		}
3114 		spcs_s_ufree(&args.status);
3115 	}
3116 
3117 	dsw_error(gettext("Some sets in the group failed to disable"),
3118 	    &parms->status);
3119 }
3120 
3121 int
3122 dsw_group_or_single_disable(int argc, char *argv[])
3123 {
3124 	int rc = 0;
3125 	char **p;
3126 	dsw_ioctl_t parms;
3127 	int flags = 0;
3128 	dsw_config_t conf;
3129 	int shd_exported = 0;
3130 
3131 	if (argc != 2)
3132 		usage(gettext("Incorrect number of arguments"));
3133 
3134 	if (group_name) {
3135 		if (find_group_members(group_name) < 1)
3136 			dsw_error(gettext("Group does not exist or "
3137 			    "has no members"), NULL);
3138 		for (p = group_volumes; *p; p++) {
3139 			can_disable(*p);
3140 		}
3141 
3142 		strncpy(parms.shadow_vol, group_name, DSW_NAMELEN);
3143 		if (*group_name)
3144 			flags = CV_IS_GROUP;
3145 	} else {
3146 		if (!find_shadow_config(argv[1], &conf, &parms)) {
3147 			dsw_error(gettext("Volume is not in a Point-in-Time "
3148 			    "Copy group"), NULL);
3149 		}
3150 
3151 		can_disable(argv[1]);
3152 		flags = 0;
3153 	}
3154 
3155 	if (group_name && !*group_name) {
3156 		/* user typed iiadm -g "" -d */
3157 		for (p = group_volumes; *p; p++) {
3158 			parms.status = spcs_s_ucreate();
3159 			parms.flags = flags;
3160 			strncpy(parms.shadow_vol, *p, DSW_NAMELEN);
3161 			rc = do_ioctl(dsw_fd, DSWIOC_DISABLE, &parms);
3162 			if (rc == -1 && errno != DSW_ENOTFOUND)
3163 				dsw_error(gettext("Disable failed"),
3164 				    &parms.status);
3165 			if (!find_shadow_config(*p, NULL, NULL))
3166 				dsw_error(gettext("Volume is not in a Point-in"
3167 				    "-Time Copy group"), &parms.status);
3168 			remove_iiset(setnumber, *p, 0);
3169 			spcs_s_ufree(&parms.status);
3170 			spcs_log("ii", NULL, gettext("Disabled %s"),
3171 			    parms.shadow_vol);
3172 		}
3173 	} else {
3174 		if (is_exported(conf.shadow_vol)) {
3175 			shd_exported = 1;
3176 		}
3177 		if ((strcmp(conf.master_vol, II_IMPORTED_SHADOW) == 0) &&
3178 		    is_exported(conf.shadow_vol)) {
3179 			dsw_error(gettext(
3180 			"Imported shadow not disabled"), NULL);
3181 		}
3182 
3183 		parms.status = spcs_s_ucreate();
3184 		parms.flags = flags;
3185 		rc = do_ioctl(dsw_fd, DSWIOC_DISABLE, &parms);
3186 		if (rc == -1 && errno != DSW_ENOTFOUND) {
3187 			if (errno == DSW_EDISABLE) {
3188 				/*
3189 				 * one or more sets within the group
3190 				 * couldn't disable
3191 				 */
3192 				clean_up_after_failed_disable(&parms);
3193 			} else {
3194 				dsw_error(gettext("Disable failed"),
3195 				    &parms.status);
3196 			}
3197 		}
3198 		spcs_log("ii", NULL, gettext("Disabled %s"), parms.shadow_vol);
3199 	}
3200 
3201 
3202 	if (group_name && *group_name) {
3203 		for (p = group_volumes; *p; p++) {
3204 			if (!find_shadow_config(*p, NULL, NULL)) {
3205 				/* argh! */
3206 				fprintf(stderr, gettext("Volume '%s' is not "
3207 				    "in a Point-in-Time Copy group"), *p);
3208 			} else {
3209 				remove_iiset(setnumber, *p, 0);
3210 			}
3211 		}
3212 	} else if (!group_name) {
3213 		if (!find_shadow_config(argv[1], NULL, NULL)) {
3214 			/* argh! */
3215 			dsw_error(gettext("Volume is not in a Point-in-Time "
3216 			    "Copy group"), NULL);
3217 		}
3218 
3219 		remove_iiset(setnumber, argv[1], shd_exported);
3220 	}
3221 
3222 	return (0);
3223 }
3224 
3225 int
3226 dsw_group_or_single_op(int argc, char *argv[], int (*op)(char *))
3227 {
3228 	int rc = 0;
3229 
3230 	if (argc != 2)
3231 		usage(gettext("Incorrect number of arguments"));
3232 
3233 	if (group_name) {
3234 		if (find_group_members(group_name) < 1)
3235 			dsw_error(gettext("Group does not exist or "
3236 				"has no members"),
3237 						NULL);
3238 		for (; *group_volumes; group_volumes++)
3239 			rc |= (*op)(*group_volumes);
3240 	} else {
3241 		rc = (*op)(argv[1]);
3242 	}
3243 	return (rc);
3244 }
3245 
3246 void
3247 dsw_list_clusters(char *cluster)
3248 {
3249 	dsw_aioctl_t *acopy_args;
3250 	int rc, i, count;
3251 	char *ptr;
3252 
3253 	if ((count = do_ioctl(dsw_fd, DSWIOC_LISTLEN, NULL)) < 0)
3254 		dsw_error("DSWIOC_LISTLEN", NULL);
3255 
3256 	acopy_args = malloc(sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
3257 	if (acopy_args == NULL)
3258 		dsw_error(gettext("Can't get memory for list enquiry"), NULL);
3259 
3260 	bzero(acopy_args, sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
3261 	acopy_args->count = count;
3262 	acopy_args->flags = 0;
3263 	acopy_args->status = spcs_s_ucreate();
3264 	if (cluster)
3265 		strncpy(acopy_args->shadow_vol, cluster, DSW_NAMELEN);
3266 
3267 	rc = do_ioctl(dsw_fd, DSWIOC_CLIST, acopy_args);
3268 	if (rc == -1)
3269 		dsw_error(gettext("Cluster list access failure"),
3270 		    &acopy_args->status);
3271 
3272 	acopy_args->shadow_vol[DSW_NAMELEN*acopy_args->count] = NULL;
3273 
3274 	if (cluster) {
3275 		printf(gettext("Sets in cluster resource group %s:\n"),
3276 		    cluster);
3277 	} else {
3278 		printf(gettext("Currently configured resource groups\n"));
3279 	}
3280 	for (i = 0, ptr = acopy_args->shadow_vol; *ptr &&
3281 	    i < acopy_args->count; i++, ptr += DSW_NAMELEN) {
3282 		printf("  %-64.64s\n", ptr);
3283 	}
3284 }
3285 
3286 void
3287 dsw_enable(int argc, char *argv[])
3288 {
3289 	if (argc != 5)
3290 		usage(gettext("Incorrect number of arguments"));
3291 
3292 	enable(argv[1], argv[2], argv[3], argv[4]);
3293 	exit(0);
3294 }
3295 
3296 
3297 void
3298 dsw_disable(int argc, char *argv[])
3299 {
3300 	(void) dsw_group_or_single_disable(argc, argv);
3301 	exit(0);
3302 }
3303 
3304 
3305 void
3306 dsw_copy_to_shadow(int argc, char *argv[])
3307 {
3308 	char	**volume_list;
3309 
3310 	if (argc != 2)
3311 		usage(gettext("Incorrect number of arguments"));
3312 	if (group_name == NULL)
3313 		volume_list = ++argv;
3314 	else {
3315 		if (find_group_members(group_name) < 1)
3316 			dsw_error(gettext("Group does not exist or "
3317 				"has no members"),
3318 						NULL);
3319 		volume_list = group_volumes;
3320 	}
3321 
3322 	exit(do_copy(volume_list, Copy, ToShadow, WaitForStart));
3323 }
3324 
3325 
3326 void
3327 dsw_update_shadow(int argc, char *argv[])
3328 {
3329 	char	**volume_list;
3330 
3331 	if (argc != 2)
3332 		usage(gettext("Incorrect number of arguments"));
3333 	if (group_name == NULL)
3334 		volume_list = ++argv;
3335 	else {
3336 		if (find_group_members(group_name) < 1)
3337 			dsw_error(gettext("Group does not exist or "
3338 				"has no members"),
3339 						NULL);
3340 		volume_list = group_volumes;
3341 	}
3342 
3343 	exit(do_copy(volume_list, Update, ToShadow, WaitForStart));
3344 }
3345 
3346 
3347 void
3348 dsw_copy_to_master(int argc, char *argv[])
3349 {
3350 	char	**volume_list;
3351 
3352 	if (argc != 2)
3353 		usage(gettext("Incorrect number of arguments"));
3354 	if (group_name == NULL) {
3355 		volume_list = ++argv;
3356 		check_action(gettext("Overwrite master with shadow volume?"));
3357 	} else {
3358 		check_action(gettext("Overwrite every"
3359 			" master in this group with its shadow volume?"));
3360 		if (find_group_members(group_name) < 1)
3361 			dsw_error(gettext("Group does not exist or "
3362 				"has no members"),
3363 						NULL);
3364 		volume_list = group_volumes;
3365 	}
3366 
3367 	exit(do_copy(volume_list, Copy, ToMaster, WaitForStart));
3368 }
3369 
3370 
3371 void
3372 dsw_update_master(int argc, char *argv[])
3373 {
3374 	char	**volume_list;
3375 
3376 	if (argc != 2)
3377 		usage(gettext("Incorrect number of arguments"));
3378 	if (group_name == NULL) {
3379 		volume_list = ++argv;
3380 		check_action(gettext("Overwrite master with shadow volume?"));
3381 	} else {
3382 		check_action(gettext("Overwrite every"
3383 			" master in this group with its shadow volume?"));
3384 		if (find_group_members(group_name) < 1)
3385 			dsw_error(gettext("Group does not exist or "
3386 				"has no members"),
3387 						NULL);
3388 		volume_list = group_volumes;
3389 	}
3390 
3391 	exit(do_copy(volume_list, Update, ToMaster, WaitForStart));
3392 }
3393 
3394 
3395 void
3396 dsw_abort_copy(int argc, char *argv[])
3397 {
3398 	exit(dsw_group_or_single_op(argc, argv, abort_copy));
3399 }
3400 
3401 
3402 void
3403 dsw_display_status(int argc, char *argv[])
3404 {
3405 	dsw_config_t parms;
3406 	int	in_config;
3407 
3408 	if (argc != 2 && argc != 1)
3409 		usage(gettext("Incorrect number of arguments"));
3410 
3411 	/* "iiadm -i" and "iiadm -i all" are equivalent */
3412 	if (argc == 2 && strcmp("all", argv[1]) != 0) {
3413 		in_config = find_shadow_config(argv[1], &parms, NULL);
3414 		if (!in_config) {
3415 			(void) printf(gettext(
3416 			    "Volume is not in configuration file\n"), NULL);
3417 			(void) fflush(stdout);
3418 			strncpy(parms.shadow_vol, argv[1], DSW_NAMELEN);
3419 			parms.shadow_vol[DSW_NAMELEN] = '\0';
3420 		}
3421 		print_status(&parms, in_config);
3422 	} else if (group_name) {
3423 		if (find_group_members(group_name) < 1)
3424 			dsw_error(gettext("Group does not exist or "
3425 				"has no members"),
3426 						NULL);
3427 		for (; *group_volumes; group_volumes++) {
3428 			in_config = find_shadow_config(*group_volumes,
3429 						&parms, NULL);
3430 			if (in_config)
3431 				print_status(&parms, in_config);
3432 		}
3433 	} else {
3434 		/* perform action for each line of the stored config file */
3435 		for (setnumber = 1;
3436 			!get_dsw_config(setnumber, &parms); setnumber++) {
3437 			switch (check_cluster()) {
3438 			case II_CLUSTER:
3439 			    if ((cfg_cluster_tag) &&
3440 				(strcmp(cfg_cluster_tag, parms.cluster_tag)))
3441 				    continue;
3442 			    break;
3443 			case II_CLUSTER_LCL:
3444 			    if (strlen(parms.cluster_tag))
3445 				    continue;
3446 			    break;
3447 			}
3448 			print_status(&parms, 1);
3449 		}
3450 	}
3451 	exit(0);
3452 }
3453 
3454 void
3455 dsw_display_bitmap(int argc, char *argv[])
3456 {
3457 	dsw_config_t parms;
3458 	int	in_config;
3459 
3460 	if (argc != 2)
3461 		usage(gettext("Incorrect number of arguments"));
3462 
3463 	in_config = find_shadow_config(argv[1], &parms, NULL);
3464 	if (!in_config) {
3465 		(void) printf(gettext(
3466 		    "Volume is not in configuration file\n"), NULL);
3467 		(void) fflush(stdout);
3468 		strncpy(parms.master_vol, argv[1], DSW_NAMELEN);
3469 		parms.master_vol[DSW_NAMELEN] = '\0';
3470 	}
3471 
3472 	bitmap_op(parms.shadow_vol, 1, 0, 0, 0);
3473 	exit(0);
3474 }
3475 
3476 
3477 /*ARGSUSED*/
3478 void
3479 dsw_version(int argc, char *argv[])
3480 {
3481 	iiversion();
3482 	exit(0);
3483 }
3484 
3485 void
3486 dsw_reset(int argc, char *argv[])
3487 {
3488 	exit(dsw_group_or_single_op(argc, argv, reset));
3489 }
3490 
3491 void
3492 dsw_overflow(int argc, char *argv[])
3493 {
3494 	if (argc != 2)
3495 		usage(gettext("Incorrect number of arguments"));
3496 
3497 	exit(overflow(argv[1]));
3498 }
3499 
3500 void
3501 dsw_wait(int argc, char *argv[])
3502 {
3503 	exit(dsw_group_or_single_op(argc, argv, wait_for_copy));
3504 }
3505 
3506 /*ARGSUSED*/
3507 void
3508 dsw_list_volumes(int argc, char *argv[])
3509 {
3510 	if (argc != 1)
3511 		usage(gettext("Incorrect number of arguments"));
3512 
3513 	list_volumes();
3514 	exit(0);
3515 }
3516 
3517 void
3518 dsw_export(int argc, char *argv[])
3519 {
3520 	if (argc != 2)
3521 		usage(gettext("Incorrect number of arguments"));
3522 
3523 	exit(dsw_group_or_single_op(argc, argv, export));
3524 }
3525 
3526 void
3527 dsw_detach(int argc, char *argv[])
3528 {
3529 	(void) dsw_group_or_single_op(argc, argv, detach);
3530 	exit(0);
3531 }
3532 
3533 void
3534 import(char *shadow_volume, char *bitmap_volume)
3535 {
3536 	dsw_config_t parms = {0};
3537 	int rc = 0;
3538 	char	shd_dg[DSW_NAMELEN];
3539 	char	bmp_dg[DSW_NAMELEN];
3540 
3541 	/*
3542 	 * If importing a shadow volume and the shadow volume is already
3543 	 * configured, we only support this if we are in a Sun Cluster
3544 	 * and the current user specified a cluster tag of -C local
3545 	 */
3546 	if (find_shadow_config(shadow_volume, &parms, NULL)) {
3547 		dsw_error(gettext("Can't import volume on same node"), NULL);
3548 	}
3549 
3550 	switch (check_cluster()) {
3551 	case II_CLUSTER:
3552 	case II_CLUSTER_LCL:
3553 		(void) check_resource_group(shadow_volume);
3554 		if (cfg_cluster_tag) { /* check all volumes are in same dg */
3555 			if (cfg_dgname(shadow_volume, shd_dg, DSW_NAMELEN)
3556 			    == NULL)
3557 				dsw_error(gettext("Shadow volume not in a"
3558 				    " disk group"), NULL);
3559 			if (cfg_dgname(bitmap_volume, bmp_dg, DSW_NAMELEN)
3560 			    == NULL)
3561 				dsw_error(gettext("Bitmap volume not in a"
3562 				    " disk group"), NULL);
3563 			if (strcmp(bmp_dg, shd_dg) != 0)
3564 				dsw_error(gettext("Bitmap volume not in"
3565 				    " same disk group as shadow set members"),
3566 				    NULL);
3567 		}
3568 		break;
3569 	case II_NOT_CLUSTER:
3570 		/* do nothing */
3571 		break;
3572 	default:
3573 		dsw_error(gettext(
3574 		    "Unexpected return from check_cluster()"), NULL);
3575 	}
3576 
3577 	/* Local configuration volumes */
3578 	if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) {
3579 		dsw_error(gettext("Unable to parse config file"), NULL);
3580 	}
3581 
3582 	reload_vols = LD_DSVOLS | LD_SHADOWS;
3583 	conform_name(&shadow_volume);
3584 	strcpy(parms.master_vol, II_IMPORTED_SHADOW);
3585 	strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
3586 	parms.shadow_vol[DSW_NAMELEN-1] = '\0';
3587 	strncpy(parms.bitmap_vol, bitmap_volume, DSW_NAMELEN);
3588 	parms.bitmap_vol[DSW_NAMELEN-1] = '\0';
3589 	parms.flag = DSW_GOLDEN;
3590 
3591 	spcs_log("ii", NULL, gettext("Import %s %s"),
3592 	    parms.shadow_vol, parms.bitmap_vol);
3593 	parms.status = spcs_s_ucreate();
3594 	rc = do_ioctl(dsw_fd, DSWIOC_IMPORT, &parms);
3595 	if (rc == -1) {
3596 		spcs_log("ii", NULL, gettext("Import failed %s %s"),
3597 		    parms.shadow_vol, parms.bitmap_vol);
3598 		dsw_error(gettext("Import failed"), &parms.status);
3599 	}
3600 	if (perform_autosv()) {
3601 		if (cfg_vol_enable(cfg, shadow_volume, cfg_cluster_tag, "ii")
3602 		    < 0) {
3603 			dsw_error(gettext("SV-enable failed"), NULL);
3604 		}
3605 		/* cfg_commit is called by add_cfg_entry below */
3606 	}
3607 	spcs_s_ufree(&parms.status);
3608 	add_cfg_entry(&parms);
3609 }
3610 
3611 void
3612 dsw_import(int argc, char *argv[])
3613 {
3614 	if (argc != 3)
3615 		usage(gettext("Incorrect number of arguments"));
3616 	import(argv[1], argv[2]);
3617 
3618 	exit(0);
3619 }
3620 
3621 void
3622 join(char *shadow_volume, char *bitmap_file)
3623 {
3624 	dsw_ioctl_t shd;
3625 	dsw_config_t conf;
3626 	dsw_bitmap_t parms;
3627 	int rc = 0;
3628 	int size;
3629 	FILE *bmpfp;
3630 	uchar_t *shd_bitmap = 0;
3631 	ii_header_t header;
3632 	char dgname[DSW_NAMELEN];
3633 
3634 	if (!find_shadow_config(shadow_volume, &conf, &shd))
3635 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3636 				"group"), NULL);
3637 
3638 	/* If this is an exportable shadow in the cluster, change ctag */
3639 	if (strlen(conf.cluster_tag) &&
3640 	    (cfg_dgname(shadow_volume, dgname, sizeof (dgname))))
3641 		cfg_resource(cfg, cfg_cluster_tag = strdup(dgname));
3642 
3643 	if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) {
3644 		dsw_error(gettext("Unable to parse config file"), NULL);
3645 	}
3646 	reload_vols = LD_DSVOLS | LD_SHADOWS;
3647 	conform_name(&shadow_volume);
3648 
3649 	if ((bmpfp = fopen(bitmap_file, "r")) == NULL) {
3650 		perror(bitmap_file);
3651 		(void) fprintf(stderr,
3652 		    gettext("Can't open imported bitmap volume\n"));
3653 		exit(1);
3654 	}
3655 
3656 	if (fread(&header, sizeof (header), 1, bmpfp) != 1) {
3657 		(void) fprintf(stderr,
3658 		    gettext("Can't read imported bitmap volume\n"));
3659 		exit(1);
3660 	}
3661 
3662 	/* See if this is a bitmap header */
3663 	switch (header.ii_magic) {
3664 	case DSW_DIRTY:		/* A copy of a enable bitmap volume */
3665 	case DSW_CLEAN:
3666 		check_action(gettext("Use the never imported bitmap?"));
3667 		break;
3668 	case DSW_INVALID:	/* A valid diskable secondary bitmap */
3669 		break;
3670 	default:
3671 		(void) fprintf(stderr,
3672 		    gettext("Secondary bitmap is not a valid bitmap volume\n"));
3673 		exit(1);
3674 	}
3675 
3676 	size = FBA_SIZE(header.ii_copyfba - header.ii_shdfba);
3677 	if ((shd_bitmap = malloc(size)) == NULL) {
3678 		perror("malloc");
3679 		exit(1);
3680 	}
3681 
3682 	if (fseek(bmpfp, FBA_SIZE(header.ii_shdfba), SEEK_SET)) {
3683 		perror("fseek");
3684 		exit(1);
3685 	}
3686 
3687 	if (fread(shd_bitmap, 1, size, bmpfp) != size) {
3688 		(void) fprintf(stderr,
3689 		    gettext("Can't read imported bitmap volume\n"));
3690 		exit(1);
3691 	}
3692 
3693 	(void) fclose(bmpfp);
3694 
3695 	strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
3696 	parms.shadow_vol[DSW_NAMELEN-1] = '\0';
3697 	parms.shd_bitmap = shd_bitmap;
3698 	parms.shd_size = size;
3699 	parms.copy_bitmap = NULL;
3700 	parms.copy_size = 0;
3701 
3702 	spcs_log("ii", NULL, gettext("Join %s %s"),
3703 	    parms.shadow_vol, bitmap_file);
3704 	parms.status = spcs_s_ucreate();
3705 	rc = do_ioctl(dsw_fd, DSWIOC_JOIN, &parms);
3706 	if (rc == -1) {
3707 		spcs_log("ii", NULL, gettext("Join failed %s %s"),
3708 		    parms.shadow_vol, bitmap_file);
3709 		dsw_error(gettext("Join failed"), &parms.status);
3710 	}
3711 	if (perform_autosv()) {
3712 		rc = cfg_vol_enable(cfg, shadow_volume, cfg_cluster_tag, "ii");
3713 		if (rc < 0) {
3714 			dsw_error(gettext("SV-enable failed"), NULL);
3715 		}
3716 		cfg_commit(cfg);
3717 	}
3718 	spcs_s_ufree(&parms.status);
3719 }
3720 
3721 int
3722 params(char *shadow_volume)
3723 {
3724 	char *delay = param_delay;
3725 	char *unit = param_unit;
3726 	dsw_copyp_t parms;
3727 	int rc = 0;
3728 	int get = 0;
3729 	int new_delay;
3730 	int new_unit;
3731 
3732 	strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
3733 	parms.shadow_vol[DSW_NAMELEN-1] = '\0';
3734 	if (delay == NULL || unit == NULL) {
3735 		get = 1;
3736 		parms.copy_delay = -1;
3737 		parms.copy_unit = -1;
3738 	} else {
3739 		new_delay = parms.copy_delay = convert_int(delay);
3740 		new_unit = parms.copy_unit = convert_int(unit);
3741 	}
3742 
3743 	parms.status = spcs_s_ucreate();
3744 	rc = do_ioctl(dsw_fd, DSWIOC_COPYP, &parms);
3745 	if (rc == -1) {
3746 		(void) fprintf(stderr,
3747 		    gettext("Parameter ranges are delay(%d - %d), "
3748 		    "units(%d - %d)\n"), MIN_THROTTLE_DELAY, MAX_THROTTLE_DELAY,
3749 		    MIN_THROTTLE_UNIT, MAX_THROTTLE_UNIT);
3750 		dsw_error(gettext("Set Copy Parameters failed"), &parms.status);
3751 	}
3752 	if (!get)
3753 		spcs_log("ii", NULL, gettext("Changed copy parameters %s from "
3754 		    "%d %d to %d %d"), parms.shadow_vol, parms.copy_delay,
3755 		    parms.copy_unit, new_delay, new_unit);
3756 	else
3757 		(void) printf(gettext("volume: %s\ncopy delay: %d\ncopy unit:"
3758 		    " %d\n"), parms.shadow_vol, parms.copy_delay,
3759 		    parms.copy_unit);
3760 	spcs_s_ufree(&parms.status);
3761 	return (0);
3762 }
3763 
3764 static void
3765 do_attach(dsw_config_t *parms)
3766 {
3767 	dsw_config_t io;
3768 	int rc;
3769 	int check = 0;
3770 
3771 	spcs_log("ii", NULL, gettext("Attach %s %s"),
3772 		parms->shadow_vol, parms->bitmap_vol);
3773 	parms->status = spcs_s_ucreate();
3774 	rc = do_ioctl(dsw_fd, DSWIOC_OATTACH, parms);
3775 	if (rc == -1) {
3776 		check = 1;
3777 		/* if overflow() fails, it calls dsw_error to exit */
3778 		(void) overflow(parms->bitmap_vol);
3779 	}
3780 	spcs_s_ufree(&parms->status);
3781 	if (check == 1) {
3782 		if (!find_shadow_config(parms->shadow_vol, &io, NULL))
3783 			dsw_error(
3784 			    gettext("Volume is not in a Point-in-Time Copy "
3785 			    "group"), NULL);
3786 		strncpy(io.bitmap_vol, parms->bitmap_vol, DSW_NAMELEN);
3787 		io.bitmap_vol[DSW_NAMELEN-1] = '\0';
3788 		io.status = spcs_s_ucreate();
3789 		if (do_ioctl(dsw_fd, DSWIOC_OATTACH, &io) == -1) {
3790 			spcs_log("ii", NULL, gettext("Attach failed %s %s"),
3791 			    io.shadow_vol, parms->bitmap_vol);
3792 			dsw_error(gettext("Attach failed"), &io.status);
3793 		}
3794 		spcs_s_ufree(&io.status);
3795 	}
3796 }
3797 
3798 int
3799 attach(char *shadow_volume)
3800 {
3801 	dsw_config_t parms;
3802 	dsw_stat_t args;
3803 	char	shd_dg[DSW_NAMELEN];
3804 	char	ovr_dg[DSW_NAMELEN];
3805 
3806 	switch (check_cluster()) {
3807 	case II_CLUSTER:
3808 	case II_CLUSTER_LCL:
3809 		(void) check_resource_group(shadow_volume);
3810 		if (cfg_cluster_tag) { /* check all volumes are in same dg */
3811 			if (cfg_dgname(shadow_volume, shd_dg, DSW_NAMELEN)
3812 			    == NULL)
3813 				dsw_error(gettext("Shadow volume not in a"
3814 				    " disk group"), NULL);
3815 			if (cfg_dgname(overflow_file, ovr_dg, DSW_NAMELEN)
3816 			    == NULL)
3817 				dsw_error(gettext("Overflow volume not in a"
3818 				    " disk group"), NULL);
3819 			if (strcmp(ovr_dg, shd_dg) != 0)
3820 				dsw_error(gettext("Overflow volume not in"
3821 				    " same disk group as shadow set members"),
3822 				    NULL);
3823 		}
3824 		break;
3825 	case II_NOT_CLUSTER:
3826 		/* do nothing */
3827 		break;
3828 	default:
3829 		dsw_error(gettext(
3830 		    "Unexpected return from check_cluster()"), NULL);
3831 	}
3832 
3833 	/* assure that the overflow_file is not an II volume */
3834 	if (find_any_cf_line(overflow_file))
3835 		dsw_error(gettext(
3836 			"Overflow volume is already in a Point-in-Time Copy "
3837 			"group"), NULL);
3838 
3839 	/* use find_shadow_config() to find setnumber */
3840 	if (!find_shadow_config(shadow_volume, &parms, NULL))
3841 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3842 			"group"), NULL);
3843 
3844 	/* can only attach an overflow volume to dependent, compact shadow */
3845 	strncpy(args.shadow_vol, shadow_volume, DSW_NAMELEN);
3846 	args.shadow_vol[DSW_NAMELEN-1] = '\0';
3847 
3848 	args.status = spcs_s_ucreate();
3849 	if ((do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) ||
3850 	    !(args.stat & DSW_TREEMAP))
3851 		dsw_error(gettext("Not a compact dependent shadow"), NULL);
3852 
3853 	/* bitmap_vol is overloaded */
3854 	strncpy(parms.bitmap_vol, overflow_file, DSW_NAMELEN);
3855 	parms.bitmap_vol[DSW_NAMELEN-1] = '\0';
3856 
3857 	do_attach(&parms);
3858 
3859 	/* add overflow to cfg line */
3860 	(void) sprintf(key, "ii.set%d.overflow", setnumber);
3861 	if (cfg_put_cstring(cfg, key, overflow_file,
3862 		    strlen(overflow_file)) < 0) {
3863 		perror("cfg_put_cstring");
3864 	}
3865 	(void) cfg_commit(cfg);
3866 	return (0);
3867 }
3868 
3869 void
3870 dsw_join(int argc, char *argv[])
3871 {
3872 	if (argc != 3)
3873 		usage(gettext("Incorrect number of arguments"));
3874 
3875 	join(argv[1], argv[2]);
3876 	exit(0);
3877 }
3878 
3879 void
3880 dsw_params(int argc, char *argv[])
3881 {
3882 	if (argc != 4 && argc != 2 && argc != 0)
3883 		usage(gettext("Incorrect number of arguments"));
3884 
3885 	if ((argc == 4) || (argc == 2)) {
3886 		param_delay = argv[1];
3887 		param_unit = argv[2];
3888 		if (argc == 4) {
3889 			argv[1] = argv[3];
3890 			argv[2] = NULL;
3891 		}
3892 	}
3893 	exit(dsw_group_or_single_op(2, argv, params));
3894 }
3895 
3896 /*ARGSUSED*/
3897 void
3898 dsw_attach(int argc, char *argv[])
3899 {
3900 	overflow_file = argv[1];
3901 	argv[1] = argv[2];
3902 	(void) dsw_group_or_single_op(2, argv, attach);
3903 	exit(0);
3904 }
3905 
3906 /*ARGSUSED*/
3907 void
3908 dsw_olist(int argc, char *argv[])
3909 {
3910 	char	*sp, *overflow_list, **vol;
3911 	int	count, i;
3912 	ENTRY	item, *found;
3913 	char	key[ CFG_MAX_KEY ], buf[ CFG_MAX_BUF ];
3914 
3915 	overflow_list = get_overflow_list();
3916 
3917 	/* count entries */
3918 	count = 0;
3919 	for (sp = overflow_list; *sp; sp += DSW_NAMELEN) {
3920 		++count;
3921 	}
3922 
3923 	/* create hash (adding room for suspended overflow volumes) */
3924 	if (hcreate(count + 1024) == 0) {
3925 		dsw_error(gettext("Out of memory creating lookup table"), NULL);
3926 		/*NOTREACHED*/
3927 	}
3928 
3929 	if (count > 0) {
3930 		/* create memory to store copy of list */
3931 		vol = (char **)calloc(count, sizeof (char *));
3932 		if (!vol) {
3933 			dsw_error(
3934 			    gettext("Out of memory creating lookup table"),
3935 			    NULL);
3936 			/*NOTREACHED*/
3937 		}
3938 
3939 		/* fill hash */
3940 		for (i = 0, sp = overflow_list; *sp; sp += DSW_NAMELEN, i++) {
3941 
3942 			/* make copy of string */
3943 			vol[ i ] = (char *)malloc(DSW_NAMELEN + 1);
3944 			strncpy(vol[ i ], sp, DSW_NAMELEN);
3945 			vol[ i ][ DSW_NAMELEN ] = '\0';
3946 
3947 			item.key = vol[ i ];
3948 			item.data = (char *)0;
3949 			(void) hsearch(item, ENTER);
3950 		}
3951 	}
3952 
3953 	/* loop through config file entries */
3954 	i = 0;
3955 	cfg_rewind(cfg, CFG_SEC_CONF);
3956 
3957 	/*CONSTCOND*/
3958 	while (1) {
3959 		++i;
3960 		(void) snprintf(key, CFG_MAX_KEY, "ii.set%d.overflow", i);
3961 		if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
3962 			break;
3963 		}
3964 
3965 		/* has this set got an overflow volume? */
3966 		if (!*buf) {
3967 			continue;
3968 		}
3969 
3970 		/* look up overflow in hash */
3971 		item.key = buf;
3972 		if (count > 0 && (found = hsearch(item, FIND)) != NULL) {
3973 			if (0 == (int)found->data) {
3974 				(void) printf("%s\n", buf);
3975 				found->data = (char *)1;
3976 				(void) hsearch(*found, ENTER);
3977 			}
3978 		} else {
3979 			/* must be part of a suspended set */
3980 			(void) printf("%s (attached to suspended set)\n", buf);
3981 			item.key = buf;
3982 			item.data = (char *)1;
3983 			(void) hsearch(item, ENTER);
3984 		}
3985 	}
3986 
3987 	exit(0);
3988 }
3989 
3990 void
3991 dsw_ostat(int argc, char *argv[])
3992 {
3993 	dsw_ostat_t	args;
3994 	int	stat_flags;
3995 
3996 	if (argc != 2)
3997 		usage(gettext("Incorrect number of arguments"));
3998 
3999 	strncpy(args.overflow_vol, argv[1], DSW_NAMELEN);
4000 	args.overflow_vol[DSW_NAMELEN-1] = '\0';
4001 
4002 	args.status = spcs_s_ucreate();
4003 	if (do_ioctl(dsw_fd, DSWIOC_OSTAT2, &args) == -1)
4004 		dsw_error(gettext("Stat failed"), &args.status);
4005 	spcs_s_ufree(&args.status);
4006 
4007 	if ((args.hversion >= 1) && (args.hmagic == II_OMAGIC)) {
4008 		stat_flags = args.flags;
4009 		if (stat_flags & IIO_CNTR_INVLD)
4010 			(void) printf(gettext("Clean shutdown of volume "
4011 			"sets associated with overflow volume "
4012 			"did not occur.\n"
4013 			"Overflow counters will be inconsistent "
4014 			"until new point-in-time(s) are taken.\n"));
4015 	}
4016 	(void) printf(gettext("Total number of attached shadows: %d\n"),
4017 	    args.drefcnt);
4018 	(void) printf(gettext("Number of currently attached shadows: %d\n"),
4019 	    args.crefcnt);
4020 	(void) printf(gettext("Total number of chunks: %lld\n"), args.nchunks);
4021 	(void) printf(gettext("Number of chunks ever allocated: %lld\n"),
4022 	    args.used);
4023 	(void) printf(gettext("Number of used chunks: %lld\n"),
4024 		(args.nchunks - args.unused));
4025 	(void) printf(gettext("Number of unused chunks: %lld\n"), args.unused);
4026 	exit(0);
4027 }
4028 
4029 /*ARGSUSED*/
4030 void
4031 dsw_move_2_group(int argc, char *argv[])
4032 {
4033 	dsw_config_t parms;
4034 	dsw_movegrp_t movegrp;
4035 	grptag_t *gdata;
4036 	int waserr = 0;
4037 
4038 	/* handle move to NULL group, or group of all spaces or tabs */
4039 	strncpy(movegrp.new_group, group_name, DSW_NAMELEN);
4040 	if ((strlen(group_name) == 0) || (strcspn(group_name, " \t") == 0)) {
4041 		group_name = "-";
4042 		bzero(movegrp.new_group, DSW_NAMELEN);
4043 		gdata = NULL;
4044 	} else {
4045 		/* get the ctag for this group (if any) */
4046 		gdata = (grptag_t *)nsc_lookup(volhash, group_name);
4047 	}
4048 
4049 	movegrp.status = spcs_s_ucreate();
4050 
4051 	for (++argv; *argv; argv++) {
4052 		if (!find_shadow_config(*argv, &parms, NULL))
4053 			dsw_error(gettext("Volume is not in a Point-in-Time "
4054 					"Copy group"), NULL);
4055 
4056 		/* ensure the ctag matches the group */
4057 		if (gdata && *gdata->ctag) {
4058 			if (strncmp(parms.cluster_tag, gdata->ctag,
4059 			    DSW_NAMELEN) != 0) {
4060 				(void) fprintf(stderr, "%s: %s %s %s\n", cmdnam,
4061 				    gettext("unable to move set"), *argv,
4062 				    gettext("into new group - cluster "
4063 				    "resource mismatch"));
4064 				waserr = 1;
4065 				continue;
4066 			}
4067 		}
4068 
4069 		/* move the set in the kernel */
4070 		strncpy(movegrp.shadow_vol, parms.shadow_vol, DSW_NAMELEN);
4071 		if (do_ioctl(dsw_fd, DSWIOC_MOVEGRP, &movegrp) < 0)
4072 			dsw_error(gettext("Failed to move group in kernel"),
4073 			    NULL);
4074 
4075 		/* now update the config */
4076 		(void) sprintf(key, "ii.set%d.group", setnumber);
4077 		if (cfg_put_cstring(cfg, key, group_name,
4078 		    strlen(group_name)) < 0) {
4079 			perror("cfg_put_cstring");
4080 		}
4081 		(void) cfg_commit(cfg);
4082 	}
4083 	spcs_s_ufree(&movegrp.status);
4084 	cfg_close(cfg);
4085 	exit(waserr);
4086 }
4087 
4088 void
4089 dsw_list_groups()
4090 {
4091 	FILE *pfp;
4092 
4093 	if ((pfp = popen("/usr/bin/sort -u", "w")) == NULL) {
4094 		dsw_error(gettext("Can't open sort program"), NULL);
4095 	}
4096 
4097 	(void) fflush(stdout);
4098 	for (setnumber = 1; /*CSTYLED*/; setnumber++) {
4099 		(void) snprintf(key, sizeof (key), "ii.set%d.group", setnumber);
4100 		if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0)
4101 			break;
4102 
4103 		/* skip if shadow set is not in any group */
4104 		if (strcmp(buf, "") == 0)
4105 			continue;
4106 		(void) fprintf(pfp, "%s\n", buf);
4107 	}
4108 	(void) pclose(pfp);
4109 }
4110 
4111 void
4112 dsw_list_group_volumes()
4113 {
4114 	FILE *pfp;
4115 
4116 	if (find_group_members(group_name) < 1)
4117 		dsw_error(gettext("Group does not exist or has no members"),
4118 			NULL);
4119 
4120 	if ((pfp = popen("/usr/bin/sort -u", "w")) == NULL) {
4121 		dsw_error(gettext("Can't open sort program"), NULL);
4122 	}
4123 
4124 	(void) fflush(stdout);
4125 	for (; *group_volumes; group_volumes++)
4126 		(void) fprintf(pfp, "%s\n", *group_volumes);
4127 	(void) pclose(pfp);
4128 }
4129 
4130 static void
4131 load_ii_vols(CFGFILE *cfg)
4132 {
4133 	int set, entries;
4134 	char *mst, *shd, *buf, **entry;
4135 	char *ctag, *group;
4136 	mstcount_t *mdata;
4137 	shdvol_t *sdata;
4138 	grptag_t *gdata;
4139 	static int whinged = 0;
4140 
4141 	if (volhash) {
4142 		return;
4143 	}
4144 
4145 	volhash = nsc_create_hash();
4146 	cfg_rewind(cfg, CFG_SEC_CONF);
4147 	entries = cfg_get_section(cfg, &entry, "ii");
4148 	for (set = 1; set <= entries; set++) {
4149 		buf = entry[set - 1];
4150 
4151 		/* grab master volume name */
4152 		mst = strtok(buf, " ");
4153 		if (!mst) {
4154 			free(buf);
4155 			break;
4156 		}
4157 
4158 		/* grab shadow, group & cnode fields */
4159 		shd = strtok(NULL, " ");
4160 		(void) strtok(NULL, " ");	/* bitmap */
4161 		(void) strtok(NULL, " ");	/* mode */
4162 		(void) strtok(NULL, " ");	/* overflow */
4163 		ctag = strtok(NULL, " ");	/* cnode */
4164 		(void) strtok(NULL, " ");	/* options */
4165 		group = strtok(NULL, " ");	/* group */
4166 
4167 		/* Fix optional tags */
4168 		if (ctag)
4169 			ctag += strspn(ctag, "-");
4170 		if (group)
4171 			group += strspn(group, "-");
4172 
4173 		/* If cluster tags don't match, skip record */
4174 		if ((cfg_cluster_tag && strcmp(ctag, cfg_cluster_tag)) ||
4175 		    (!cfg_cluster_tag && strlen(ctag))) {
4176 			free(buf);
4177 			continue;
4178 		}
4179 
4180 		/* master volume, may be duplicates */
4181 		mdata = (mstcount_t *)nsc_lookup(volhash, mst);
4182 		if (mdata) {
4183 			++mdata->count;
4184 		} else {
4185 			mdata = (mstcount_t *)malloc(sizeof (mstcount_t));
4186 			mdata->count = 1;
4187 			(void) nsc_insert_node(volhash, mdata, mst);
4188 		}
4189 
4190 		/* grab shadow volume name */
4191 		sdata = (shdvol_t *)malloc(sizeof (shdvol_t));
4192 		strncpy(sdata->master, mst, DSW_NAMELEN);
4193 		(void) nsc_insert_node(volhash, sdata, shd);
4194 
4195 		/* No need to continue if no groups or ctags */
4196 		if (!group || !*group || !ctag || !*ctag) {
4197 			free(buf);
4198 			continue;
4199 		}
4200 
4201 		gdata = (grptag_t *)nsc_lookup(volhash, group);
4202 		if (gdata) {
4203 			/* group already exists - check ctag */
4204 			if (*ctag &&
4205 			    (strncmp(ctag, gdata->ctag, DSW_NAMELEN) != 0)) {
4206 				if (!whinged) {
4207 					printf(gettext("Warning: multiple "
4208 					    "cluster resource groups "
4209 					    "defined within a single "
4210 					    "I/O group\n"));
4211 					whinged = 1;
4212 				}
4213 			}
4214 		} else {
4215 			gdata = (grptag_t *)malloc(sizeof (grptag_t));
4216 			strncpy(gdata->ctag, ctag, DSW_NAMELEN);
4217 			(void) nsc_insert_node(volhash, gdata, group);
4218 		}
4219 
4220 		free(buf);
4221 	}
4222 
4223 	/* free up any leftovers */
4224 	while (set < entries)
4225 		free(entry[set++]);
4226 	if (entries)
4227 		free(entry);
4228 }
4229 
4230 static void
4231 unload_ii_vols()
4232 {
4233 	nsc_remove_all(volhash, free);
4234 	volhash = 0;
4235 }
4236 
4237 static int
4238 perform_autosv()
4239 {
4240 	static int result;
4241 	static int calculated = 0;
4242 	int rc;
4243 
4244 #ifdef DEBUG
4245 	if (getenv("II_SET_CLUSTER"))
4246 		return (1);
4247 #endif
4248 
4249 	if (calculated) {
4250 		return (result);
4251 	}
4252 
4253 	/*
4254 	 * we only perform auto-sv if we're in a sun cluster or if
4255 	 * we're on a standalone system.  I.e. we don't do auto-sv on Harry
4256 	 */
4257 	rc = check_cluster();
4258 
4259 	if (II_NOT_CLUSTER == rc) {
4260 		result = 1;
4261 	} else {
4262 		result = cfg_issuncluster();
4263 	}
4264 
4265 	calculated = 1;
4266 	return (result);
4267 }
4268 
4269 /*
4270  * Returns true if set has had the shadow volume exported.
4271  * Returns false if shadow volume is not exported, or set is suspended.
4272  */
4273 static int
4274 is_exported(char *set)
4275 {
4276 	dsw_stat_t args;
4277 	int rc;
4278 
4279 	strncpy(args.shadow_vol, set, DSW_NAMELEN);
4280 	args.shadow_vol[DSW_NAMELEN-1] = '\0';
4281 	args.status = spcs_s_ucreate();
4282 
4283 	rc = do_ioctl(dsw_fd, DSWIOC_STAT, &args);
4284 	spcs_s_ufree(&args.status);
4285 
4286 	if (-1 == rc) {
4287 		/* set must be suspended, or being disabled */
4288 		return (0);
4289 	}
4290 
4291 	return ((args.stat & DSW_SHDEXPORT) == DSW_SHDEXPORT);
4292 }
4293 
4294 static void
4295 conform_name(char **path)
4296 {
4297 	char *cfgname;
4298 	int rc = cfg_get_canonical_name(cfg, *path, &cfgname);
4299 
4300 	if (rc < 0) {
4301 		dsw_error(gettext("Unable to parse config file"), NULL);
4302 	}
4303 	if (rc) {
4304 		printf("  '%s'\n%s\n  '%s'\n", *path,
4305 		    gettext("is currently configured as"), cfgname);
4306 		check_action(gettext("Perform operation with indicated volume"
4307 		    " name?"));
4308 		*path = cfgname;
4309 		/*
4310 		 * NOTE: *path ought to be deallocated ('free(*path)') after
4311 		 * we're done with it, but since this routine is called just
4312 		 * before we exit, it doesn't really matter
4313 		 */
4314 	}
4315 }
4316 
4317 /*
4318  * verify_groupname(char *, int);
4319  *
4320  * Check the group name for the following rules:
4321  *	1. The name does not start with a '-'
4322  *	2. The name does not contain any space characters as defined by
4323  *	   isspace(3C).
4324  * If either of these rules are broken, error immediately. The check for a
4325  * leading dash can be skipped if the 'testDash' argument is false. This is to
4326  * allow for the '-g -L' functionality.
4327  *
4328  */
4329 static void
4330 verify_groupname(char *grp, int testDash)
4331 {
4332 	int i;
4333 
4334 	if (testDash && grp[0] == '-') {
4335 		errno = EINVAL;
4336 		dsw_error(gettext("group name cannot start with a '-'"), NULL);
4337 	}
4338 
4339 	for (i = 0; grp[i] != '\0'; i++) {
4340 		if (isspace(grp[i])) {
4341 			errno = EINVAL;
4342 			dsw_error(gettext("group name cannot contain a space"),
4343 			    NULL);
4344 		}
4345 	}
4346 }
4347 
4348 void
4349 check_iishadow(char *shadow_vol) {
4350 	int i;
4351 	int entries;
4352 	char **entry;
4353 	char *shost;
4354 	char *svol;
4355 	char *buf;
4356 	void *librdc;
4357 
4358 	/*
4359 	 * See if librdc is around
4360 	 * If not, we can just return
4361 	 */
4362 	if (librdc = dlopen(RDC_LIB, RTLD_LAZY | RTLD_GLOBAL))
4363 		self_check = (int (*)(char *)) dlsym(librdc, "self_check");
4364 	else {
4365 		return;
4366 	}
4367 
4368 	entry = NULL;
4369 	entries = cfg_get_section(cfg, &entry, "sndr");
4370 	for (i = 0; i < entries; i++) {
4371 		buf = entry[i];
4372 
4373 		(void) strtok(buf, " ");	/* phost */
4374 		(void) strtok(NULL, " ");	/* primary */
4375 		(void) strtok(NULL, " ");	/* pbitmap */
4376 		shost = strtok(NULL, " ");	/* shost */
4377 		svol = strtok(NULL, " ");	/* secondary */
4378 
4379 		if (self_check(shost) && (strcmp(shadow_vol, svol) == 0)) {
4380 			free(buf);
4381 			if (entries)
4382 				free(entry);
4383 			errno = EINVAL;
4384 			dsw_error(gettext(
4385 			    "shadow volume is in use as SNDR secondary volume"),
4386 			    NULL);
4387 		}
4388 		free(buf);
4389 	}
4390 
4391 	(void) dlclose(librdc);
4392 	if (entries)
4393 		free(entry);
4394 }
4395