xref: /titanic_50/usr/src/cmd/avs/dsw/iiadm.c (revision 506ea5b80cb420d5edeb6aff19fe035c0a283bb3)
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 2010 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 	(void) 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 			(void) 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 		(void) cfg_lock(cfg, last_lock);
748 	}
749 	if (unlocked) {
750 		/* reload vol hashes */
751 		if (reload_vols & LD_SVOLS)
752 			(void) cfg_load_svols(cfg);
753 		if (reload_vols & LD_DSVOLS)
754 			(void) cfg_load_dsvols(cfg);
755 		if (reload_vols & LD_SHADOWS)
756 			(void) 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, sizeof (buf)) < 0)
883 			break;
884 
885 		if (strcmp(group, buf))
886 			continue;
887 
888 		(void) snprintf(key, sizeof (key), "ii.set%d.shadow",
889 		    setnumber);
890 		if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0)
891 			break;
892 
893 		if (nmembers >= vector_len) {
894 			vector_len += 10;
895 			group_volumes = realloc(group_volumes, (1+vector_len) *
896 			    sizeof (char *));
897 		}
898 		group_volumes[nmembers] = strdup(buf);
899 		nmembers++;
900 	}
901 	if (group_volumes)
902 		group_volumes[nmembers] = NULL;	/* terminate list */
903 	return (nmembers);
904 }
905 
906 static int
907 find_next_matching_cf_line(
908 	char *volume, dsw_config_t *conf, dsw_ioctl_t *io, int next)
909 {
910 	dsw_config_t config;
911 
912 	if (!find_next_cf_line(volume, next)) {
913 		return (0);
914 	}
915 
916 	if (conf == NULL)
917 		conf = &config;
918 	(void) get_dsw_config(setnumber, conf);
919 	if (io) {
920 		(void) strlcpy(io->shadow_vol, conf->shadow_vol, DSW_NAMELEN);
921 	}
922 	return (1);
923 }
924 
925 int
926 find_matching_cf_line(char *volume, dsw_config_t *conf, dsw_ioctl_t *io)
927 {
928 	return (find_next_matching_cf_line(volume, conf, io, 1));
929 }
930 
931 int
932 find_shadow_config(char *volume, dsw_config_t *conf, dsw_ioctl_t *io)
933 {
934 	dsw_config_t *c, cf;
935 
936 	if (io) {
937 		bzero(io, sizeof (dsw_ioctl_t));
938 	}
939 	c = conf ? conf : &cf;
940 	setnumber = 1;
941 	/* perform action for each line of the stored config file */
942 	for ((void) snprintf(key, sizeof (key), "ii.set%d.shadow", setnumber);
943 	    cfg_get_cstring(cfg, key, c->shadow_vol, DSW_NAMELEN) >= 0;
944 	    (void) snprintf(key, sizeof (key), "ii.set%d.shadow",
945 	    ++setnumber)) {
946 		if (strncmp(volume, c->shadow_vol, DSW_NAMELEN) == 0) {
947 			(void) get_dsw_config(setnumber, c);
948 
949 			if (check_resource_group(c->bitmap_vol)) {
950 				setnumber = 0;
951 				continue;
952 			}
953 
954 			switch (check_cluster()) {
955 			case II_CLUSTER:
956 				if ((cfg_cluster_tag) &&
957 				    (strcmp(cfg_cluster_tag, c->cluster_tag)))
958 					continue;
959 				break;
960 			case II_CLUSTER_LCL:
961 				if (strlen(c->cluster_tag))
962 					continue;
963 				break;
964 			}
965 
966 			if (io) {
967 				(void) strlcpy(io->shadow_vol, c->shadow_vol,
968 				    DSW_NAMELEN);
969 			}
970 			return (1);
971 		}
972 	}
973 	return (0);
974 }
975 
976 void
977 add_cfg_entry(dsw_config_t *parms)
978 {
979 	/* insert the well-known fields first */
980 	(void) snprintf(buf, sizeof (buf), "%s %s %s %s",
981 	    parms->master_vol, parms->shadow_vol, parms->bitmap_vol,
982 	    (parms->flag & DSW_GOLDEN) ? "I" : "D");
983 
984 	if (cfg_put_cstring(cfg, "ii", buf, strlen(buf)) >=  0) {
985 		/* if we have a group name, add it */
986 		if (group_name) {
987 			if (find_any_cf_line(parms->shadow_vol)) {
988 				(void) sprintf(buf, "ii.set%d.group",
989 				    setnumber);
990 				if (cfg_put_cstring(cfg, buf,
991 				    group_name, strlen(group_name)) < 0)
992 					perror("cfg_put_cstring");
993 			}
994 			else
995 				perror("cfg_location");
996 		}
997 
998 		/* commit the record */
999 		(void) cfg_commit(cfg);
1000 	}
1001 	else
1002 		perror("cfg_put_string");
1003 }
1004 
1005 void
1006 remove_iiset(int setno, char *shadow, int shd_exp)
1007 {
1008 	mstcount_t *mdata;
1009 	shdvol_t *sdata;
1010 	char sn[CFG_MAX_BUF];
1011 
1012 	if (perform_autosv()) {
1013 		if (volhash) {
1014 			unload_ii_vols();
1015 		}
1016 		load_ii_vols(cfg);
1017 		if (cfg_load_dsvols(cfg) < 0 || cfg_load_svols(cfg) < 0) {
1018 			dsw_error(gettext("Unable to parse config file"), NULL);
1019 		}
1020 
1021 		sdata = (shdvol_t *)nsc_lookup(volhash, shadow);
1022 		if (sdata) {
1023 			/*
1024 			 * Handle the normal cases of disabling a set that is
1025 			 * not an imported shadow volume
1026 			 */
1027 			if (strcmp(sdata->master, II_IMPORTED_SHADOW)) {
1028 				/*
1029 				 * Handle multiple-shadows of single master
1030 				 */
1031 				mdata = (mstcount_t *)
1032 				    nsc_lookup(volhash, sdata->master);
1033 				if ((mdata) && (mdata->count == 1)) {
1034 					if (cfg_vol_disable(cfg, sdata->master,
1035 					    cfg_cluster_tag, "ii") < 0)
1036 						dsw_error(gettext(
1037 						    "SV disable of master "
1038 						    "failed"),
1039 						    NULL);
1040 				}
1041 			}
1042 
1043 			/*
1044 			 * Handle disk group name of different shadow
1045 			 */
1046 			if (shd_exp) {
1047 				/*
1048 				 * If shadow is exported, then do nothing
1049 				 */
1050 				/*EMPTY*/;
1051 			} else if (cfg_cluster_tag &&
1052 			    strcmp(cfg_cluster_tag, "") &&
1053 			    cfg_dgname(shadow, sn, sizeof (sn)) &&
1054 			    strlen(sn) &&
1055 			    strcmp(sn, cfg_cluster_tag)) {
1056 					/* reload disk group volumes */
1057 					cfg_resource(cfg, sn);
1058 					cfg_unload_dsvols();
1059 					cfg_unload_svols();
1060 					(void) cfg_load_dsvols(cfg);
1061 					(void) cfg_load_svols(cfg);
1062 					if (cfg_vol_disable(cfg, shadow, sn,
1063 					    "ii") < 0) {
1064 						dsw_error(gettext(
1065 						    "SV disable of shadow "
1066 						    "failed"),
1067 						    NULL);
1068 					}
1069 					cfg_resource(cfg, cfg_cluster_tag);
1070 			} else {
1071 				if (cfg_vol_disable(cfg, shadow,
1072 				    cfg_cluster_tag, "ii") < 0)
1073 					dsw_error(gettext(
1074 					    "SV disable of shadow failed"),
1075 					    NULL);
1076 			}
1077 		}
1078 		cfg_unload_svols();
1079 		cfg_unload_dsvols();
1080 		unload_ii_vols();
1081 		reload_vols &= ~(LD_SVOLS | LD_DSVOLS | LD_II);
1082 	}
1083 
1084 	(void) sprintf(key, "ii.set%d", setno);
1085 	if (cfg_put_cstring(cfg, key, NULL, 0) < 0) {
1086 		perror("cfg_put_cstring");
1087 	}
1088 	(void) cfg_commit(cfg);
1089 }
1090 
1091 /*
1092  * determine if we are running in a Sun Cluster Environment
1093  */
1094 int
1095 check_cluster()
1096 {
1097 	static int is_cluster = -1;
1098 	int rc;
1099 #ifdef DEBUG
1100 	char *cdebug = getenv("II_SET_CLUSTER");
1101 #endif
1102 
1103 	/*
1104 	 * If this routine was previously called, just return results
1105 	 */
1106 	if (is_cluster != -1)
1107 		return (is_cluster);
1108 
1109 	/*
1110 	 * See if Sun Cluster was installed on this node
1111 	 */
1112 #ifdef DEBUG
1113 	if (cdebug) rc = atoi(cdebug);
1114 	else
1115 #endif
1116 	rc = cfg_iscluster();
1117 	if (rc > 0) {
1118 		/*
1119 		 * Determine if user specified -C local
1120 		 */
1121 		if ((cfg_cluster_tag == NULL) ||
1122 		    (strcmp(cfg_cluster_tag, II_LOCAL_TAG))) {
1123 			/*
1124 			 * We're in a Sun Cluster, and no "-C local"
1125 			 */
1126 			is_cluster = II_CLUSTER;
1127 		} else {
1128 			/*
1129 			 * We're in a Sun Cluster, but "-C local" was specified
1130 			 */
1131 			is_cluster = II_CLUSTER_LCL;
1132 			cfg_cluster_tag = "";
1133 		}
1134 		return (is_cluster);
1135 	} else if (rc == 0) {
1136 		/*
1137 		 * Not in a Sun Cluster
1138 		 */
1139 		is_cluster = II_NOT_CLUSTER;
1140 		return (is_cluster);
1141 	} else {
1142 		dsw_error(gettext("unable to ascertain environment"), NULL);
1143 		/*NOTREACHED*/
1144 	}
1145 
1146 	/* gcc */
1147 	return (is_cluster);
1148 }
1149 
1150 /*
1151  * Determine if we need to set a cfg_resource based on this volume
1152  */
1153 static int
1154 check_resource_group(char *volume)
1155 {
1156 	char diskgroup[CFG_MAX_BUF];
1157 
1158 	/*
1159 	 * If we are in a cluster, attempt to derive a new resource group
1160 	 */
1161 
1162 #ifdef DEBUG
1163 	if (getenv("II_SET_CLUSTER") || (check_cluster() == II_CLUSTER)) {
1164 #else
1165 	if (check_cluster() == II_CLUSTER) {
1166 #endif
1167 		if (check_diskgroup(volume, diskgroup)) {
1168 			if (cfg_cluster_tag == NULL) {
1169 				cfg_cluster_tag = strdup(diskgroup);
1170 				if (cfg_cluster_tag == NULL)
1171 					dsw_error(gettext(
1172 					"Memory allocation failure"), NULL);
1173 				cfg_resource(cfg, cfg_cluster_tag);
1174 				return (1);
1175 			} else {
1176 				/*
1177 				 * Check dgname and cluster tag from -C are
1178 				 * the same.
1179 				 */
1180 				if (strcmp(diskgroup, cfg_cluster_tag) != 0) {
1181 					char error_buffer[128];
1182 					(void) snprintf(error_buffer,
1183 					    sizeof (error_buffer),
1184 					    gettext("-C (%s) does not match "
1185 					    "disk group name (%s) for %s"),
1186 					    cfg_cluster_tag, 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 		(void) 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 	(void) 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 	(void) sigset(SIGHUP, sigterm);
1300 	(void) sigset(SIGINT, sigterm);
1301 	(void) sigset(SIGQUIT, sigterm);
1302 	(void) sigset(SIGILL, sigterm);
1303 	(void) sigset(SIGEMT, sigterm);
1304 	(void) sigset(SIGABRT, sigterm);
1305 	(void) sigset(SIGFPE, sigterm);
1306 	(void) sigset(SIGBUS, sigterm);
1307 	(void) sigset(SIGSEGV, sigterm);
1308 	(void) sigset(SIGTERM, sigterm);
1309 	(void) sigset(SIGPWR, sigterm);
1310 	(void) sigset(SIGSTOP, sigterm);
1311 	(void) 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 	(void) 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 	(void) strlcpy(parms.shadow_vol, master_volume, DSW_NAMELEN);
1369 	parms.shd_bitmap = shd_bitmap;
1370 	parms.shd_size = size;
1371 	parms.copy_bitmap = copy_bitmap;
1372 	parms.copy_size = size;
1373 
1374 	return (do_ioctl(dsw_fd, DSWIOC_BITMAP, &parms));
1375 }
1376 
1377 unsigned char *
1378 allocate_bitmap(char *shadow_volume)
1379 {
1380 	unsigned char	*shd_bitmap;
1381 	unsigned char	*copy_bitmap;
1382 	unsigned char	*p;
1383 	unsigned char	*q;
1384 	int		i;
1385 	dsw_stat_t	args;
1386 	int		stat_flags;
1387 
1388 	(void) strlcpy(args.shadow_vol, shadow_volume, DSW_NAMELEN);
1389 
1390 	args.status = spcs_s_ucreate();
1391 	if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1)
1392 		dsw_error(gettext("Stat failed"), &args.status);
1393 
1394 	stat_flags = args.stat;
1395 	if (stat_flags & DSW_BMPOFFLINE)
1396 		return (NULL);
1397 
1398 	bm_size = args.size;
1399 	bm_size = (bm_size + DSW_SIZE-1) / DSW_SIZE;
1400 	bm_actual = bm_size;
1401 	bm_size = (bm_size + DSW_BITS-1) / DSW_BITS;
1402 	spcs_s_ufree(&args.status);
1403 
1404 	p = shd_bitmap = (unsigned char *) malloc(bm_size);
1405 	if (!shd_bitmap) {
1406 		perror(gettext("malloc bitmap"));
1407 		return (NULL);
1408 	}
1409 
1410 	q = copy_bitmap = (unsigned char *) malloc(bm_size);
1411 	if (!copy_bitmap) {
1412 		perror(gettext("malloc bitmap"));
1413 		free(shd_bitmap);
1414 		return (NULL);
1415 	}
1416 
1417 	(void) memset(shd_bitmap, 0, bm_size);
1418 	(void) memset(copy_bitmap, 0, bm_size);
1419 
1420 	if (get_bitmap(shadow_volume, shd_bitmap, copy_bitmap, bm_size) < 0) {
1421 		free(copy_bitmap);
1422 		free(shd_bitmap);
1423 		return (NULL);
1424 	}
1425 
1426 	/*
1427 	 * "or" the copy and shadow bitmaps together to return a composite
1428 	 * bitmap that contains the total set of differences between the
1429 	 * volumes.
1430 	 */
1431 	for (i = bm_size; i-- > 0; /*CSTYLED*/)
1432 		*p++ |= *q++;
1433 
1434 	free(copy_bitmap);
1435 
1436 	return (shd_bitmap);
1437 }
1438 
1439 /*
1440  * print usage message and exit.
1441  */
1442 void
1443 usage(char *why)
1444 {
1445 	if (why) {
1446 		(void) fprintf(stderr, "%s: %s\n", cmdnam, why);
1447 
1448 		(void) fprintf(stderr, "%s\n",
1449 		    gettext("\nBrief summary:"));
1450 		(void) fprintf(stderr, "%s\n",
1451 		    gettext("\t-e {ind|dep} master_vol shadow_vol "
1452 		    "bitmap_vol"));
1453 		(void) fprintf(stderr, "%s\n",
1454 		    gettext("\t-[cu {s|m}] volume_set"));
1455 		(void) fprintf(stderr, "%s\n",
1456 		    gettext("\t-i all"));
1457 		(void) fprintf(stderr, "%s\n",
1458 		    gettext("\t-[adDEilPRw] volume_set"));
1459 		(void) fprintf(stderr, "%s\n",
1460 		    gettext("\t-g group_name [options]"));
1461 		(void) fprintf(stderr, "%s\n",
1462 		    gettext("\t-C cluster_tag [options]"));
1463 		(void) fprintf(stderr, "%s\n",
1464 		    gettext("\t-[hilLv]"));
1465 		(void) fprintf(stderr, "%s\n",
1466 		    gettext("\t-[IJ] volume_set bitmap"));
1467 		(void) fprintf(stderr, "%s\n",
1468 		    gettext("\t-A overflow_vol volume_set"));
1469 		(void) fprintf(stderr, "%s\n",
1470 		    gettext("\t-[OQ] overflow_vol"));
1471 		(void) fprintf(stderr, "%s\n",
1472 		    gettext("\t-P {delay} {units} volume_set"));
1473 
1474 		/* assume we came here due to a user mistake */
1475 		exit(1);
1476 		/* NOTREACHED */
1477 	} else {
1478 
1479 		(void) fprintf(stdout, "%s\n",
1480 		    gettext("Point-in-Time Copy Administrator CLI options"));
1481 		(void) fprintf(stdout, "%s\n",
1482 		    gettext("Usage summary:"));
1483 		(void) fprintf(stdout, "%s\n",
1484 		    gettext("\t-e ind m s b\tenable independent master shadow "
1485 		    "bitmap"));
1486 		(void) fprintf(stdout, "%s\n",
1487 		    gettext("\t-e dep m s b\tenable dependent master shadow "
1488 		    "bitmap"));
1489 		if (check_cluster() == II_CLUSTER)
1490 			(void) fprintf(stdout, "%s\n",
1491 			    gettext("\t-ne ind m s b\tenable exportable master "
1492 			    "shadow bitmap"));
1493 		(void) fprintf(stdout, "%s\n",
1494 		    gettext("\t-d v\t\tdisable volume"));
1495 		(void) fprintf(stdout, "%s\n",
1496 		    gettext("\t-u s v\t\tupdate shadow volume"));
1497 		(void) fprintf(stdout, "%s\n",
1498 		    gettext("\t-u m v\t\tupdate master volume"));
1499 		(void) fprintf(stdout, "%s\n",
1500 		    gettext("\t-c s v\t\tcopy to shadow volume"));
1501 		(void) fprintf(stdout, "%s\n",
1502 		    gettext("\t-c m v\t\tcopy to master volume"));
1503 		(void) fprintf(stdout, "%s\n",
1504 		    gettext("\t-a v\t\tabort copy volume"));
1505 		(void) fprintf(stdout, "%s\n",
1506 		    gettext("\t-w v\t\twait volume"));
1507 		(void) fprintf(stdout, "%s\n",
1508 		    gettext("\t-i v\t\tdisplay volume status"));
1509 		(void) fprintf(stdout, "%s\n",
1510 		    gettext("\t-i all\t\tdisplay all volume status"));
1511 		(void) fprintf(stdout, "%s\n",
1512 		    gettext("\t-l\t\tlist all volumes"));
1513 		(void) fprintf(stdout, "%s\n",
1514 		    gettext("\t-R v\t\treset volume"));
1515 		(void) fprintf(stdout, "%s\n",
1516 		    gettext("\t-A o v\t\tattach overflow to volume"));
1517 		(void) fprintf(stdout, "%s\n",
1518 		    gettext("\t-D v\t\tdetach overflow from volume"));
1519 		(void) fprintf(stdout, "%s\n",
1520 		    gettext("\t-L\t\tlist all overflow volumes"));
1521 		(void) fprintf(stdout, "%s\n",
1522 		    gettext("\t-O o\t\tinitialize overflow"));
1523 		(void) fprintf(stdout, "%s\n",
1524 		    gettext("\t-Q o\t\tquery status of overflow"));
1525 		(void) fprintf(stdout, "%s\n",
1526 		    gettext("\t-E v\t\texport shadow volume"));
1527 		(void) fprintf(stdout, "%s\n",
1528 		    gettext("\t-I v b\t\timport volume bitmap"));
1529 		(void) fprintf(stdout, "%s\n",
1530 		    gettext("\t-J v b\t\tjoin volume bitmap"));
1531 		(void) fprintf(stdout, "%s\n",
1532 		    gettext("\t-P d u v\tset copy delay/units for volume"));
1533 		(void) fprintf(stdout, "%s\n",
1534 		    gettext("\t-P v\t\tget copy delay/units for volume"));
1535 		(void) fprintf(stdout, "%s\n",
1536 		    gettext("\t-C tag\t\tcluster resource tag"));
1537 #ifdef DEBUG
1538 		(void) fprintf(stdout, "%s\n",
1539 		    gettext("\t-b v\t\tdisplay bitmap volume"));
1540 		(void) fprintf(stdout, "%s\n",
1541 		    gettext("\t-f f\t\tuse private configuration file"));
1542 #endif
1543 		(void) fprintf(stdout, "%s\n",
1544 		    gettext("\t-v\t\tprint software versions"));
1545 		(void) fprintf(stdout, "%s\n",
1546 		    gettext("\t-n\t\tperform action without question"));
1547 		(void) fprintf(stdout, "%s\n",
1548 		    gettext("\t-p [-c|-u] {m|s}"
1549 		    "enable PID locking on copy or update"));
1550 		(void) fprintf(stdout, "%s\n",
1551 		    gettext("\t-p -w v\t\tdisable PID locking"));
1552 		(void) fprintf(stdout, "%s\n",
1553 		    gettext("\t-h\t\tiiadm usage summary"));
1554 		(void) fprintf(stdout, "%s\n",
1555 		    gettext("\nUsage summary for options that support "
1556 		    "grouping (-g g):"));
1557 		(void) fprintf(stdout, "%s\n",
1558 		    gettext("\t-g g -e ind m s b group enable independent "
1559 		    "master shadow bitmap"));
1560 		(void) fprintf(stdout, "%s\n",
1561 		    gettext("\t-g g -e dep m s b group enable dependent "
1562 		    "master shadow bitmap"));
1563 		(void) fprintf(stdout, "%s\n",
1564 		    gettext("\t-g g -d\t\tdisable group"));
1565 		(void) fprintf(stdout, "%s\n",
1566 		    gettext("\t-g g -u s\tupdate shadow for all volumes in "
1567 		    "group"));
1568 		(void) fprintf(stdout, "%s\n",
1569 		    gettext("\t-g g -u m\tupdate master for all volumes in "
1570 		    "group"));
1571 		(void) fprintf(stdout, "%s\n",
1572 		    gettext("\t-g g -c s\tcopy to shadow for all volumes in "
1573 		    "group"));
1574 		(void) fprintf(stdout, "%s\n",
1575 		    gettext("\t-g g -c m\tcopy to master for all volumes in "
1576 		    "group"));
1577 		(void) fprintf(stdout, "%s\n",
1578 		    gettext("\t-g g -a\t\tabort copy for all volumes in "
1579 		    "group"));
1580 		(void) fprintf(stdout, "%s\n",
1581 		    gettext("\t-g g -w\t\twait for all volumes in group"));
1582 		(void) fprintf(stdout, "%s\n",
1583 		    gettext("\t-g g -i\t\tdisplay status of all volumes in "
1584 		    "group"));
1585 		(void) fprintf(stdout, "%s\n",
1586 		    gettext("\t-g g -l\t\tlist all volumes in group"));
1587 		(void) fprintf(stdout, "%s\n",
1588 		    gettext("\t-g -L\t\tlist all groups"));
1589 		(void) fprintf(stdout, "%s\n",
1590 		    gettext("\t-g g -m v v\tmove one or more volumes into "
1591 		    "group"));
1592 		(void) fprintf(stdout, "%s\n",
1593 		    gettext("\t-g \"\" -m v\tremove volume from group"));
1594 		(void) fprintf(stdout, "%s\n",
1595 		    gettext("\t-g g -R\t\treset all volumes in group"));
1596 		(void) fprintf(stdout, "%s\n",
1597 		    gettext("\t-g g -A o\tattach overflow to all volumes in "
1598 		    "group"));
1599 		(void) fprintf(stdout, "%s\n",
1600 		    gettext("\t-g g -D\t\tdetach overflow from all volumes in "
1601 		    "group"));
1602 		(void) fprintf(stdout, "%s\n",
1603 		    gettext("\t-g g -E\t\texport shadow volume for all "
1604 		    "volumes in group"));
1605 		(void) fprintf(stdout, "%s\n",
1606 		    gettext("\t-g g -P d u\tset copy delay/units for all "
1607 		    "volumes in group"));
1608 		(void) fprintf(stdout, "%s\n",
1609 		    gettext("\t-g g -P\t\tget copy delay/units for all "
1610 		    "volumes in group"));
1611 		(void) fprintf(stdout, "%s\n",
1612 		    gettext("\nLegend summary:"));
1613 		(void) fprintf(stdout, "%s\n",
1614 		    gettext("\tind\t\tindependent volume set"));
1615 		(void) fprintf(stdout, "%s\n",
1616 		    gettext("\tdep\t\tdependent volume set"));
1617 		(void) fprintf(stdout, "%s\n",
1618 		    gettext("\tall\t\tall configured volumes"));
1619 		(void) fprintf(stdout, "%s\n",
1620 		    gettext("\tm\t\tmaster volume"));
1621 		(void) fprintf(stdout, "%s\n",
1622 		    gettext("\ts\t\tshadow volume"));
1623 		(void) fprintf(stdout, "%s\n",
1624 		    gettext("\tv\t\tshadow volume (reference name)"));
1625 		(void) fprintf(stdout, "%s\n",
1626 		    gettext("\to\t\toverflow volume"));
1627 		(void) fprintf(stdout, "%s\n",
1628 		    gettext("\tb\t\tbitmap volume"));
1629 #ifdef DEBUG
1630 		(void) fprintf(stdout, "%s\n",
1631 		    gettext("\tf\t\tconfiguration file name"));
1632 #endif
1633 		(void) fprintf(stdout, "%s\n",
1634 		    gettext("\td\t\tdelay tick interval"));
1635 		(void) fprintf(stdout, "%s\n",
1636 		    gettext("\tu\t\tunit size"));
1637 		(void) fprintf(stdout, "%s\n",
1638 		    gettext("\tg\t\tgroup name"));
1639 
1640 		/* assume we came here because user request help text */
1641 		exit(0);
1642 		/* NOTREACHED */
1643 	}
1644 
1645 }
1646 
1647 static  char    yeschr[MAX_LINE_SIZE + 2];
1648 static  char    nochr[MAX_LINE_SIZE + 2];
1649 
1650 static int
1651 yes(void)
1652 {
1653 	int	i, b;
1654 	char	ans[MAX_LINE_SIZE + 1];
1655 
1656 	for (i = 0; /*CSTYLED*/; i++) {
1657 		b = getchar();
1658 		if (b == '\n' || b == '\0' || b == EOF) {
1659 			if (i < MAX_LINE_SIZE)
1660 				ans[i] = 0;
1661 			break;
1662 		}
1663 		if (i < MAX_LINE_SIZE)
1664 			ans[i] = b;
1665 	}
1666 	if (i >= MAX_LINE_SIZE) {
1667 		i = MAX_LINE_SIZE;
1668 		ans[MAX_LINE_SIZE] = 0;
1669 	}
1670 	if ((i == 0) || (strncmp(yeschr, ans, i))) {
1671 		if (strncmp(nochr, ans, i) == 0)
1672 			return (0);
1673 		else if (strncmp(yeschr, ans, i) == 0)
1674 			return (1);
1675 		else {
1676 			(void) fprintf(stderr, "%s %s/%s\n",
1677 			    gettext("You have to respond with"),
1678 			    yeschr, nochr);
1679 			return (2);
1680 		}
1681 	}
1682 	return (1);
1683 }
1684 
1685 static int
1686 convert_int(char *str)
1687 {
1688 	int result, rc;
1689 	char *buf;
1690 
1691 	buf = (char *)calloc(strlen(str) + 256, sizeof (char));
1692 	rc = sscanf(str, "%d%s", &result, buf);
1693 
1694 	if (rc != 1) {
1695 		(void) sprintf(buf, gettext("'%s' is not a valid number"), str);
1696 		/* dsw_error calls exit which frees 'buf' */
1697 		errno = EINVAL;
1698 		dsw_error(buf, NULL);
1699 	}
1700 	free(buf);
1701 
1702 	return (result);
1703 }
1704 
1705 void
1706 check_action(char *will_happen)
1707 {
1708 	int answer;
1709 
1710 	if (nflg || !isatty(fileno(stdin)))
1711 		return;
1712 	(void) strncpy(yeschr, nl_langinfo(YESSTR), MAX_LINE_SIZE + 1);
1713 	(void) strncpy(nochr, nl_langinfo(NOSTR), MAX_LINE_SIZE + 1);
1714 
1715 	/*CONSTCOND*/
1716 	while (1) {
1717 		(void) printf("%s %s/%s ", will_happen, yeschr, nochr);
1718 		answer = yes();
1719 		if (answer == 1 || answer == 0)
1720 			break;
1721 	}
1722 	if (answer == 1)
1723 		return;
1724 	exit(1);
1725 }
1726 
1727 enum	child_event {Status, CopyStart};
1728 
1729 /*
1730  * Wait for child process to get to some state, where some state may be:
1731  *
1732  *	Status		Set up the shadow enough so that it responds
1733  *			to status requests.
1734  *	CopyStart	Start copy/update operations.
1735  */
1736 
1737 int
1738 child_wait(pid_t child, enum child_event event, char *volume)
1739 {
1740 	dsw_stat_t	args;
1741 	int rc;
1742 
1743 	(void) strlcpy(args.shadow_vol, volume, DSW_NAMELEN);
1744 
1745 	for (; dead_child != child; (void) sleep(1)) {
1746 
1747 		/* poll shadow group with a status ioctl() */
1748 		args.status = spcs_s_ucreate();
1749 		errno = 0;
1750 		rc = do_ioctl(dsw_fd, DSWIOC_STAT, &args);
1751 
1752 		spcs_s_ufree(&args.status);
1753 
1754 		if (event == Status) {
1755 			/* keep polling while we fail with DSW_ENOTFOUND */
1756 			if (rc != -1 || errno != DSW_ENOTFOUND)
1757 				return (0);
1758 		} else {
1759 			/* event == CopyStart */
1760 			if (rc == -1) {
1761 				return (1);	/* something wrong */
1762 			}
1763 			if (args.stat & DSW_COPYINGP)
1764 				return (0);	/* copying underway */
1765 		}
1766 	}
1767 	/* child died */
1768 	if (WIFEXITED(dead_stat))
1769 		return (WEXITSTATUS(dead_stat));
1770 	else
1771 		return (1);
1772 }
1773 
1774 int
1775 mounted(char *t)
1776 {
1777 	int	rdsk;
1778 	int	i;
1779 	FILE	*mntfp;
1780 	struct mnttab mntref;
1781 	struct mnttab mntent;
1782 	char	target[DSW_NAMELEN];
1783 	char	*s;
1784 
1785 	rdsk = i = 0;
1786 	for (s = target; i < DSW_NAMELEN && (*s = *t++); i++) {
1787 		if (*s == 'r' && rdsk == 0)
1788 			rdsk = 1;
1789 		else
1790 			s++;
1791 	}
1792 	*s = '\0';
1793 
1794 	mntref.mnt_special = target;
1795 	mntref.mnt_mountp = NULL;
1796 	mntref.mnt_fstype = NULL;
1797 	mntref.mnt_mntopts = NULL;
1798 	mntref.mnt_time = NULL;
1799 
1800 	if ((mntfp = fopen("/etc/mnttab", "r")) == NULL) {
1801 		dsw_error(gettext("Can not check volume against mount table"),
1802 		    NULL);
1803 	}
1804 	if (getmntany(mntfp, &mntent, &mntref) != -1) {
1805 		/* found something before EOF */
1806 		(void) fclose(mntfp);
1807 		return (1);
1808 	}
1809 	(void) fclose(mntfp);
1810 	return (0);
1811 }
1812 
1813 void
1814 enable(char *master_volume, char *shadow_volume,
1815 	char *bitmap_volume, char *copy_type)
1816 {
1817 	dsw_config_t parms;
1818 	dsw_ioctl_t temp;
1819 	char	*p;
1820 	int	rc;
1821 	pid_t	child;
1822 	spcs_s_info_t *sp_info;
1823 	struct stat mstat, sstat, bstat;
1824 	char	mst_dg[DSW_NAMELEN] = {0};
1825 	char	shd_dg[DSW_NAMELEN] = {0};
1826 	char	bmp_dg[DSW_NAMELEN] = {0};
1827 	int	mvol_enabled;
1828 	char	*altname;
1829 	grptag_t *gdata;
1830 
1831 	bzero(&parms, sizeof (dsw_config_t));
1832 
1833 	if (strcmp(copy_type, "independent") == 0 ||
1834 	    strcmp(copy_type, gettext("independent")) == 0)
1835 		parms.flag = DSW_GOLDEN;
1836 	else if (strcmp(copy_type, "dependent") == 0 ||
1837 	    strcmp(copy_type, gettext("dependent")) == 0)
1838 		parms.flag = 0;
1839 	else
1840 		dsw_error(gettext("don't understand shadow type"), NULL);
1841 
1842 	/* validate volume names */
1843 	if (perform_autosv()) {
1844 		if (cfg_load_svols(cfg) < 0 || cfg_load_dsvols(cfg) < 0 ||
1845 		    cfg_load_shadows(cfg) < 0) {
1846 			dsw_error(gettext("Unable to parse config file"), NULL);
1847 		}
1848 		load_ii_vols(cfg);
1849 		reload_vols = LD_SVOLS | LD_DSVOLS | LD_SHADOWS | LD_II;
1850 
1851 		/* see if it's been used before under a different name */
1852 		conform_name(&master_volume);
1853 		conform_name(&shadow_volume);
1854 		rc = cfg_get_canonical_name(cfg, bitmap_volume, &altname);
1855 		if (rc < 0) {
1856 			dsw_error(gettext("Unable to parse config file"), NULL);
1857 		}
1858 		if (rc) {
1859 			errno = EBUSY;
1860 			dsw_error(gettext("Bitmap in use"), NULL);
1861 		}
1862 	}
1863 
1864 	/*
1865 	 * If not local, determine disk group names for volumes in II set
1866 	 */
1867 	switch (check_cluster()) {
1868 	case II_CLUSTER:
1869 		/*
1870 		 * Check if none or all volumes are in a disk group
1871 		 */
1872 		rc = 0;
1873 		if (check_diskgroup(master_volume, mst_dg)) rc++;
1874 		if (check_diskgroup(shadow_volume, shd_dg)) rc++;
1875 		if (check_diskgroup(bitmap_volume, bmp_dg)) rc++;
1876 		if ((rc != 0) && (rc != 3))
1877 			dsw_error(gettext(
1878 			    "Not all Point-in-Time Copy volumes are "
1879 			    "in a disk group"), NULL);
1880 
1881 		/*
1882 		 * If volumes are not in a disk group, but are in a
1883 		 * cluster, then "-C <tag>", must be set
1884 		 */
1885 		if (rc == 0 && cfg_cluster_tag == NULL)
1886 			dsw_error(gettext(
1887 			    "Point-in-Time Copy volumes, that are not "
1888 			    "in a device group which has been "
1889 			    "registered with SunCluster, "
1890 			    "require usage of \"-C\""), NULL);
1891 
1892 		/*
1893 		 * the same disk group
1894 		 * If -n, plus mst_dg==bmp_dg, then allow E/I/J in SunCluster
1895 		 */
1896 		if ((strcmp(mst_dg, bmp_dg)) ||
1897 		    (strcmp(mst_dg, shd_dg) && (!nflg)))
1898 			dsw_error(gettext(
1899 			    "Volumes are not in same disk group"), NULL);
1900 
1901 		/*
1902 		 * Can never enable the same shadow twice, regardless of
1903 		 * exportable shadow device group movement
1904 		 */
1905 		if (find_shadow_line(shadow_volume))
1906 			dsw_error(gettext(
1907 			    "Shadow volume is already configured"), NULL);
1908 
1909 		/*
1910 		 * Groups cannot span multiple clusters
1911 		 */
1912 		if (group_name && perform_autosv()) {
1913 			gdata = (grptag_t *)nsc_lookup(volhash, group_name);
1914 			if (gdata &&
1915 			    strncmp(gdata->ctag, mst_dg, DSW_NAMELEN) != 0) {
1916 				errno = EINVAL;
1917 				dsw_error(gettext("Group contains sets not "
1918 				    "in the same cluster resource"), NULL);
1919 			}
1920 		}
1921 
1922 		/*
1923 		 * Check cluster tag and bitmap disk group
1924 		 * set latter if different
1925 		 */
1926 		if (check_resource_group(bitmap_volume)) {
1927 			/*
1928 			 * Unload and reload in the event cluster tag has
1929 			 * changed
1930 			 */
1931 			if (perform_autosv()) {
1932 				unload_ii_vols();
1933 				cfg_unload_shadows();
1934 				cfg_unload_dsvols();
1935 				cfg_unload_svols();
1936 				if (cfg_load_svols(cfg) < 0 ||
1937 				    cfg_load_dsvols(cfg) < 0 ||
1938 				    cfg_load_shadows(cfg) < 0) {
1939 					dsw_error(gettext(
1940 					    "Unable to parse config "
1941 					    "file"), NULL);
1942 				}
1943 				load_ii_vols(cfg);
1944 			}
1945 		}
1946 		/*
1947 		 * Copy cluster name into config
1948 		 */
1949 		(void) strncpy(parms.cluster_tag, cfg_cluster_tag, DSW_NAMELEN);
1950 		break;
1951 
1952 	case II_CLUSTER_LCL:
1953 		/* ensure that the -C local won't interfere with the set */
1954 		if (group_name && perform_autosv()) {
1955 			gdata = (grptag_t *)nsc_lookup(volhash, group_name);
1956 			if (gdata) {
1957 				if (strlen(gdata->ctag) != 0) {
1958 					errno = EINVAL;
1959 					dsw_error(gettext("Unable to put set "
1960 					    "into -C local and specified "
1961 					    "group"), NULL);
1962 				}
1963 			}
1964 		}
1965 		break;
1966 	}
1967 
1968 	/*
1969 	 * If we've got a group name, add it into the config
1970 	 */
1971 	if (group_name) {
1972 		(void) strncpy(parms.group_name, group_name, DSW_NAMELEN);
1973 	}
1974 
1975 	/*
1976 	 * Determine accessability of volumes
1977 	 */
1978 	if (stat(master_volume, &mstat) != 0)
1979 		dsw_error(gettext(
1980 		    "Unable to access master volume"), NULL);
1981 	if (!S_ISCHR(mstat.st_mode))
1982 		dsw_error(gettext(
1983 		    "Master volume is not a character device"), NULL);
1984 	/* check the shadow_vol hasn't be used as SNDR secondary vol */
1985 	check_iishadow(shadow_volume);
1986 	if (stat(shadow_volume, &sstat) != 0)
1987 		dsw_error(gettext(
1988 		    "Unable to access shadow volume"), NULL);
1989 	if (!S_ISCHR(sstat.st_mode))
1990 		dsw_error(gettext(
1991 		    "Shadow volume is not a character device"), NULL);
1992 	if (mounted(shadow_volume)) {
1993 		errno = EBUSY;
1994 		dsw_error(gettext(
1995 		    "Shadow volume is mounted, unmount it first"), NULL);
1996 	}
1997 	if (mstat.st_rdev == sstat.st_rdev) {
1998 		errno = EINVAL;
1999 		dsw_error(gettext(
2000 		    "Master and shadow are the same device"), NULL);
2001 	}
2002 	if (stat(bitmap_volume, &bstat) != 0) {
2003 		dsw_error(gettext("Unable to access bitmap"), NULL);
2004 	}
2005 	if (!S_ISCHR(bstat.st_mode))
2006 		dsw_error(gettext(
2007 		    "Bitmap volume is not a character device"), NULL);
2008 	if (S_ISCHR(bstat.st_mode)) {
2009 		if (mstat.st_rdev == bstat.st_rdev) {
2010 			errno = EINVAL;
2011 			dsw_error(gettext(
2012 			    "Master and bitmap are the same device"), NULL);
2013 		} else if (sstat.st_rdev == bstat.st_rdev) {
2014 			errno = EINVAL;
2015 			dsw_error(gettext(
2016 			    "Shadow and bitmap are the same device"), NULL);
2017 		}
2018 	}
2019 
2020 	(void) strncpy(parms.master_vol, master_volume, DSW_NAMELEN);
2021 	(void) strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
2022 	(void) strncpy(parms.bitmap_vol, bitmap_volume, DSW_NAMELEN);
2023 	errno = 0;
2024 	parms.status = spcs_s_ucreate();
2025 
2026 	/*
2027 	 * Check that none of the member volumes forms part of another
2028 	 * InstantImage group.
2029 	 *
2030 	 * -- this check has been removed; it is done in the kernel instead
2031 	 * -- PJW
2032 	 */
2033 
2034 	/*
2035 	 * Check against overflow volumes
2036 	 */
2037 	for (p = get_overflow_list(); *p != NULL; p += DSW_NAMELEN) {
2038 		if (strncmp(master_volume, p, DSW_NAMELEN) == 0)
2039 			dsw_error(gettext(
2040 			    "Master volume is already an overflow volume"),
2041 			    NULL);
2042 		else if (strncmp(shadow_volume, p, DSW_NAMELEN) == 0)
2043 			dsw_error(gettext(
2044 			    "Shadow volume is already an overflow volume"),
2045 			    NULL);
2046 		else if (strncmp(bitmap_volume, p, DSW_NAMELEN) == 0)
2047 			dsw_error(gettext(
2048 			    "Bitmap volume is already an overflow volume"),
2049 			    NULL);
2050 	}
2051 
2052 	/*
2053 	 * Make sure that the shadow volume is not already configured
2054 	 */
2055 	if (find_shadow_config(shadow_volume, NULL, &temp))
2056 		dsw_error(gettext(
2057 		    "Shadow volume is already configured"), NULL);
2058 	if (perform_autosv()) {
2059 		/*
2060 		 * parse the dsvol entries to see if we need to place
2061 		 * the master or shadow under SV control
2062 		 */
2063 		if (nsc_lookup(volhash, master_volume) == NULL) {
2064 			if (cfg_vol_enable(cfg, master_volume, cfg_cluster_tag,
2065 			    "ii") < 0) {
2066 				dsw_error(
2067 				    gettext("Cannot enable master volume"),
2068 				    NULL);
2069 			}
2070 			mvol_enabled = 1;
2071 		} else {
2072 			mvol_enabled = 0;
2073 		}
2074 		if (nsc_lookup(volhash, shadow_volume) == NULL) {
2075 			if (nflg) {
2076 				cfg_resource(cfg, shd_dg);
2077 				rc = cfg_vol_enable(cfg, shadow_volume,
2078 				    shd_dg, "ii");
2079 				cfg_resource(cfg, cfg_cluster_tag);
2080 			} else {
2081 				rc = cfg_vol_enable(cfg, shadow_volume,
2082 				    cfg_cluster_tag, "ii");
2083 			}
2084 			if (rc < 0) {
2085 				if (mvol_enabled) {
2086 					if (cfg_vol_disable(cfg,
2087 					    master_volume, cfg_cluster_tag,
2088 					    "ii") < 0)
2089 						dsw_error(gettext(
2090 						    "SV disable of master "
2091 						    "failed"),
2092 						    NULL);
2093 				}
2094 				dsw_error(
2095 				    gettext("Cannot enable shadow volume"),
2096 				    NULL);
2097 			}
2098 		}
2099 		unload_ii_vols();
2100 		cfg_unload_shadows();
2101 		cfg_unload_dsvols();
2102 		cfg_unload_svols();
2103 		reload_vols = 0;
2104 	}
2105 
2106 	add_cfg_entry(&parms);
2107 	cfg_unlock(cfg);
2108 	config_locked = 0;
2109 
2110 	(void) sigset(SIGCHLD, sigchild);
2111 	switch (child = fork()) {
2112 
2113 	case (pid_t)-1:
2114 		dsw_error(gettext("Unable to fork"), NULL);
2115 		break;
2116 
2117 	case 0:
2118 		rc = do_ioctl(dsw_fd, DSWIOC_ENABLE, &parms);
2119 		if (rc == -1 && errno != DSW_EABORTED && errno != DSW_EIO) {
2120 			/*
2121 			 * Failed to enable shadow group, log problem and remove
2122 			 * the shadow group from the config file.
2123 			 */
2124 			spcs_log("ii", &parms.status,
2125 			    gettext("Enable failed %s %s %s (%s)"),
2126 			    master_volume, shadow_volume, bitmap_volume,
2127 			    parms.flag & DSW_GOLDEN ?
2128 			    "independent" : "dependent");
2129 
2130 			if (!ii_lock(cfg, CFG_WRLOCK) ||
2131 			    !find_shadow_config(shadow_volume, NULL, &temp)) {
2132 				dsw_error(gettext(
2133 				    "Enable failed, can't tidy up cfg"),
2134 				    &parms.status);
2135 			}
2136 			config_locked = 1;
2137 			remove_iiset(setnumber, shadow_volume, 0);
2138 			dsw_error(gettext("Enable failed"), &parms.status);
2139 		}
2140 
2141 		if (rc == -1)
2142 			sp_info = &parms.status;
2143 		else
2144 			sp_info = NULL;
2145 		spcs_log("ii", sp_info, gettext("Enabled %s %s %s (%s)"),
2146 		    master_volume, shadow_volume, bitmap_volume,
2147 		    parms.flag & DSW_GOLDEN ? "independent" : "dependent");
2148 		spcs_s_ufree(&parms.status);
2149 		break;
2150 
2151 	default:
2152 		exit(child_wait(child, Status, shadow_volume));
2153 		break;
2154 	}
2155 }
2156 
2157 int
2158 reset(char *volume)
2159 {
2160 	dsw_ioctl_t args;
2161 	dsw_config_t parms;
2162 	int	rc;
2163 	int	wait_loc;
2164 	pid_t	child = (pid_t)0;
2165 	enum copy_wait wait_action;
2166 	spcs_s_info_t *stat;
2167 	dsw_stat_t prev_stat;
2168 	int stat_flags;
2169 	static int unlocked = 0;
2170 	int	do_enable = 0;
2171 	char	key[CFG_MAX_KEY];
2172 	char	optval[CFG_MAX_BUF];
2173 	unsigned int flags;
2174 
2175 	wait_action = WaitForStart;
2176 
2177 	if (unlocked && !ii_lock(cfg, CFG_RDLOCK)) {
2178 		dsw_error(gettext("Unable to set locking on the configuration"),
2179 		    NULL);
2180 	}
2181 	config_locked = 1;
2182 	if (!find_shadow_config(volume, &parms, &args))
2183 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2184 		    "group"), NULL);
2185 
2186 	cfg_unlock(cfg);
2187 	config_locked = 0;
2188 	unlocked = 1;
2189 
2190 	spcs_log("ii", NULL, gettext("Start reset %s"), volume);
2191 	(void) strlcpy(prev_stat.shadow_vol, volume, DSW_NAMELEN);
2192 	prev_stat.status = spcs_s_ucreate();
2193 	if (do_ioctl(dsw_fd, DSWIOC_STAT, &prev_stat) == -1) {
2194 		/* set is suspended, so we do the enable processing instead */
2195 		do_enable = 1;
2196 
2197 		/* first check to see whether the set was offline */
2198 		(void) snprintf(key, CFG_MAX_KEY, "ii.set%d.options",
2199 		    setnumber);
2200 		if (!ii_lock(cfg, CFG_RDLOCK)) {
2201 			dsw_error(gettext("Unable to set locking on the "
2202 			    "configuration"), NULL);
2203 		}
2204 		config_locked = 1;
2205 		unlocked = 0;
2206 		if (cfg_get_single_option(cfg, CFG_SEC_CONF, key,
2207 		    NSKERN_II_BMP_OPTION, optval, CFG_MAX_BUF) < 0) {
2208 			dsw_error(gettext("unable to read config file"), NULL);
2209 		}
2210 		cfg_unlock(cfg);
2211 		config_locked = 0;
2212 		unlocked = 1;
2213 		(void) sscanf(optval, "%x", &flags);
2214 		if ((flags & DSW_OFFLINE) == 0) {
2215 			/* set wasn't offline - don't reset */
2216 			dsw_error(gettext("Set not offline, will not reset"),
2217 			    NULL);
2218 		}
2219 		parms.status = spcs_s_ucreate();
2220 		stat = &parms.status;
2221 		stat_flags = DSW_BMPOFFLINE;
2222 	} else {
2223 		args.status = spcs_s_ucreate();
2224 		stat = &args.status;
2225 		stat_flags = prev_stat.stat;
2226 	}
2227 	spcs_s_ufree(&prev_stat.status);
2228 
2229 	if (wait_action == WaitForStart)
2230 		(void) sigset(SIGCHLD, sigchild);
2231 
2232 	switch (child = fork()) {
2233 
2234 	case (pid_t)-1:
2235 		dsw_error(gettext("Unable to fork"), NULL);
2236 		break;
2237 
2238 	case 0:
2239 		if (do_enable) {
2240 			rc = do_ioctl(dsw_fd, DSWIOC_ENABLE, &parms);
2241 		} else {
2242 			rc = do_ioctl(dsw_fd, DSWIOC_RESET, &args);
2243 		}
2244 		if (rc == -1 && errno != DSW_EABORTED && errno != DSW_EIO) {
2245 			spcs_log("ii", stat, gettext("Fail reset %s"), volume);
2246 			dsw_error(gettext("Reset shadow failed"), stat);
2247 		}
2248 		/* last_overflow is set during find_shadow_config */
2249 		if (strlen(last_overflow) > 0 &&
2250 		    (stat_flags & (DSW_SHDOFFLINE | DSW_BMPOFFLINE)) != 0) {
2251 			/* reattach it */
2252 			(void) strncpy(parms.bitmap_vol, last_overflow,
2253 			    DSW_NAMELEN);
2254 			do_attach(&parms);
2255 		}
2256 		spcs_log("ii", stat, gettext("Finish reset %s"), volume);
2257 		spcs_s_ufree(stat);
2258 
2259 		exit(0);
2260 		break;
2261 	default:
2262 		if (wait_action == WaitForStart) {
2263 			rc = child_wait(child, CopyStart, args.shadow_vol);
2264 		} else { /* wait_action == WaitForEnd */
2265 			wait_loc = 0;
2266 			(void) wait(&wait_loc);
2267 			if (WIFEXITED(wait_loc) && (WEXITSTATUS(wait_loc) == 0))
2268 				rc = 0;
2269 			else
2270 				rc = -1;
2271 		}
2272 		break;
2273 	}
2274 	/* if successful, remove flags entry from options field */
2275 	if (rc >= 0) {
2276 		if (!ii_lock(cfg, CFG_WRLOCK)) {
2277 			dsw_error(gettext("Unable to set locking on the "
2278 			    "configuration"), NULL);
2279 		}
2280 		config_locked = 1;
2281 		if (!find_shadow_config(volume, &parms, &args)) {
2282 			dsw_error(gettext("Volume is not in a Point-in-Time "
2283 			    "Copy group"), NULL);
2284 		}
2285 		(void) snprintf(key, CFG_MAX_KEY, "ii.set%d.options",
2286 		    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 		(void) 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 	(void) 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 	(void) 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 			(void) 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 		(void) strlcpy(stat_s.shadow_vol, parms.shadow_vol,
2529 		    DSW_NAMELEN);
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 ? gettext("update") : gettext("copy"),
2550 		    vol_list[i],
2551 		    direction == ToMaster ?  gettext("from shadow") :
2552 		    gettext("to shadow"));
2553 	}
2554 	if (group_name == NULL || *group_name == NULL) {
2555 		sp = acopy_args->shadow_vol;
2556 		for (i = 0; i < n_vols; i++, sp += DSW_NAMELEN)
2557 			(void) strncpy(sp, vol_list[i], DSW_NAMELEN);
2558 	} else {
2559 		(void) strncpy(acopy_args->shadow_vol, group_name, DSW_NAMELEN);
2560 		acopy_args->flags |= CV_IS_GROUP;
2561 	}
2562 	rc = do_ioctl(dsw_fd, DSWIOC_ACOPY, acopy_args);
2563 	if (rc == -1) {
2564 		i = acopy_args->count;
2565 		if (i < 0 || i >= n_vols) {
2566 			spcs_log("ii", NULL, gettext("Atomic update failed"));
2567 			(void) sprintf(buf, gettext("Update failed"));
2568 		} else {
2569 			spcs_log("ii", NULL,
2570 			    gettext("Atomic update of %s failed"),
2571 			    vol_list[acopy_args->count]);
2572 			(void) sprintf(buf, gettext("Update of %s failed"),
2573 			    vol_list[acopy_args->count]);
2574 		}
2575 		dsw_error(buf, &(acopy_args->status));
2576 	}
2577 	return (rc);
2578 }
2579 
2580 int
2581 do_copy(char **vol_list, enum copy_update update_mode,
2582 		enum copy_direction direction, enum copy_wait wait_action)
2583 {
2584 	dsw_ioctl_t copy_args;
2585 	dsw_config_t parms;
2586 	dsw_stat_t	stat_s;
2587 	int	rc;
2588 	int	wait_loc;
2589 	char	*t;
2590 	char	*volume;
2591 	pid_t	child = (pid_t)0;
2592 	char	*ppid;
2593 
2594 	if (vol_list[0] && vol_list[1])
2595 		return (do_acopy(vol_list, update_mode, direction));
2596 
2597 	volume = vol_list[0];
2598 	if (!find_shadow_config(volume, &parms, &copy_args))
2599 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2600 		    "group"), NULL);
2601 
2602 	cfg_unlock(cfg);
2603 	config_locked = 0;
2604 	copy_args.flags = 0;
2605 
2606 	if (update_mode == Update)
2607 		copy_args.flags |= CV_BMP_ONLY;
2608 	if (direction == ToMaster) {
2609 		copy_args.flags |= CV_SHD2MST;
2610 		t = parms.master_vol;
2611 	} else {
2612 		t = parms.shadow_vol;
2613 	}
2614 	if (pflg) {
2615 		copy_args.flags |= CV_LOCK_PID;
2616 #ifdef DEBUG
2617 		ppid = getenv("IIADM_PPID");
2618 		if (ppid) {
2619 			copy_args.pid = atoi(ppid);
2620 			(void) fprintf(stderr, "(using %s for ppid)\n", ppid);
2621 		} else {
2622 			copy_args.pid = getppid();
2623 		}
2624 #else
2625 		copy_args.pid = getppid();
2626 #endif
2627 	}
2628 
2629 	if (mounted(t)) {
2630 		errno = EBUSY;
2631 		dsw_error(gettext("Target of copy/update is mounted, "
2632 		    "unmount it first"), NULL);
2633 	}
2634 
2635 	(void) strlcpy(stat_s.shadow_vol, copy_args.shadow_vol, DSW_NAMELEN);
2636 	stat_s.status = spcs_s_ucreate();
2637 	rc = do_ioctl(dsw_fd, DSWIOC_STAT, &stat_s);
2638 	spcs_s_ufree(&stat_s.status);
2639 	if (rc == -1)
2640 		dsw_error(gettext("Shadow group suspended"), NULL);
2641 
2642 	if (stat_s.stat & DSW_COPYINGP) {
2643 		(void) fprintf(stderr, "%s: %s\n", cmdnam,
2644 		    gettext("Copy already in progress"));
2645 		exit(1);
2646 	}
2647 
2648 	copy_args.status = spcs_s_ucreate();
2649 	spcs_log("ii", NULL, gettext("Start %s %s %s"),
2650 	    update_mode == Update ? gettext("update") : gettext("copy"),
2651 	    volume,
2652 	    direction == ToMaster ?  gettext("from shadow") :
2653 	    gettext("to shadow"));
2654 
2655 	if (wait_action == WaitForStart)
2656 		(void) sigset(SIGCHLD, sigchild);
2657 	switch (child = fork()) {
2658 
2659 	case (pid_t)-1:
2660 		dsw_error(gettext("Unable to fork"),
2661 		    NULL);
2662 		break;
2663 
2664 	case 0:
2665 		rc = do_ioctl(dsw_fd, DSWIOC_COPY, &copy_args);
2666 		if (rc == -1) {
2667 			spcs_log("ii", &copy_args.status,
2668 			    gettext("Fail %s %s %s"),
2669 			    update_mode == Update ?
2670 			    gettext("update") : gettext("copy"),
2671 			    volume,
2672 			    direction == ToMaster ?
2673 			    gettext("from shadow") : gettext("to shadow"));
2674 			dsw_error(gettext("Copy failed"), &copy_args.status);
2675 		}
2676 		spcs_s_ufree(&copy_args.status);
2677 		spcs_log("ii", NULL, gettext("Finish %s %s %s"),
2678 		    update_mode == Update ? gettext("update") : gettext("copy"),
2679 		    volume,
2680 		    direction == ToMaster ?  gettext("from shadow") :
2681 		    gettext("to shadow"));
2682 
2683 		exit(0);
2684 		break;
2685 	default:
2686 		if (wait_action == WaitForStart) {
2687 			rc = child_wait(child, CopyStart, copy_args.shadow_vol);
2688 		} else { /* wait_action == WaitForEnd */
2689 			wait_loc = 0;
2690 			(void) wait(&wait_loc);
2691 			if (WIFEXITED(wait_loc) && (WEXITSTATUS(wait_loc) == 0))
2692 				rc = 0;
2693 			else
2694 				rc = 1;
2695 		}
2696 		break;
2697 	}
2698 	return (rc);
2699 }
2700 
2701 void
2702 print_status(dsw_config_t *conf, int in_config)
2703 {
2704 	dsw_stat_t args;
2705 	int	stat_flags;
2706 	static int need_sep = 0;
2707 	time_t tmp_time;
2708 
2709 	if (need_sep++ > 0)
2710 		(void) printf("--------------------------------------"
2711 		    "----------------------------------------\n");
2712 	(void) strlcpy(args.shadow_vol, conf->shadow_vol, DSW_NAMELEN);
2713 	if (in_config) {
2714 		(void) printf("%s: %s\n",
2715 		    conf->master_vol, gettext("(master volume)"));
2716 		(void) printf("%s: %s\n",
2717 		    conf->shadow_vol, gettext("(shadow volume)"));
2718 		(void) printf("%s: %s\n",
2719 		    conf->bitmap_vol, gettext("(bitmap volume)"));
2720 	}
2721 
2722 	/*
2723 	 * Do special checking on the status of this volume in a Sun Cluster
2724 	 */
2725 	if (check_cluster() == II_CLUSTER) {
2726 		char dgname[CFG_MAX_BUF], *other_node;
2727 
2728 		if (cfg_dgname(conf->bitmap_vol, dgname, sizeof (dgname))) {
2729 			if (strlen(dgname)) {
2730 				int rc = cfg_dgname_islocal(dgname,
2731 				    &other_node);
2732 
2733 				if (rc < 0) {
2734 					(void) printf(gettext(
2735 					    "Suspended on this node, "
2736 					    "not active elsewhere\n"));
2737 					return;
2738 				} else if (rc == 0) {
2739 					(void) printf(gettext(
2740 					    "Suspended on this node, "
2741 					    "active on %s\n"), other_node);
2742 					return;
2743 				}
2744 			}
2745 		}
2746 	}
2747 
2748 	args.status = spcs_s_ucreate();
2749 	if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) {
2750 
2751 		/* Handle Not found or not in config */
2752 		if (errno != DSW_ENOTFOUND || !in_config)
2753 			dsw_error(gettext("Stat failed"), &args.status);
2754 
2755 		/* Just suspend */
2756 		(void) printf(gettext("Suspended.\n"));
2757 		return;
2758 	}
2759 
2760 	if (args.overflow_vol[0] != '\0')
2761 		(void) printf("%s: %s\n", args.overflow_vol,
2762 		    gettext("(overflow volume)"));
2763 
2764 	if (conf->group_name[0] != '\0')
2765 		(void) printf(gettext("Group name: %s\n"),
2766 		    conf->group_name);
2767 
2768 	if (conf->cluster_tag[0] != '\0')
2769 		(void) printf(gettext("Cluster tag: %s\n"),
2770 		    conf->cluster_tag);
2771 
2772 	stat_flags = args.stat;
2773 	spcs_s_ufree(&args.status);
2774 	if (stat_flags & DSW_GOLDEN)
2775 		(void) printf(gettext("Independent copy"));
2776 	else
2777 		(void) printf(gettext("Dependent copy"));
2778 
2779 	if (stat_flags & DSW_TREEMAP)
2780 		(void) printf(gettext(", compacted shadow space"));
2781 
2782 	if (stat_flags & DSW_COPYINGP)
2783 		(void) printf(gettext(", copy in progress"));
2784 	else if (stat_flags & DSW_COPYING)
2785 		(void) printf(gettext(", copy not active"));
2786 
2787 	if (stat_flags & DSW_COPYINGM)
2788 		(void) printf(gettext(", copying master to shadow"));
2789 
2790 	if (stat_flags & DSW_COPYINGS)
2791 		(void) printf(gettext(", copying shadow to master"));
2792 
2793 	if (stat_flags & DSW_COPYINGX)
2794 		(void) printf(gettext(", abort of copy requested"));
2795 
2796 	if (stat_flags & DSW_MSTOFFLINE)
2797 		(void) printf(gettext(", master volume offline"));
2798 
2799 	if (stat_flags & DSW_SHDOFFLINE)
2800 		(void) printf(gettext(", shadow volume offline"));
2801 
2802 	if (stat_flags & DSW_BMPOFFLINE)
2803 		(void) printf(gettext(", bitmap volume offline"));
2804 
2805 	if (stat_flags & DSW_OVROFFLINE)
2806 		(void) printf(gettext(", overflow volume offline"));
2807 
2808 	if (stat_flags & DSW_SHDEXPORT)
2809 		(void) printf(gettext(", shadow volume exported"));
2810 
2811 	if (stat_flags & DSW_SHDIMPORT)
2812 		(void) printf(gettext(", shadow volume imported"));
2813 
2814 	if (stat_flags & DSW_OVERFLOW)
2815 		(void) printf(gettext(", out of space"));
2816 
2817 	if (stat_flags & DSW_VOVERFLOW)
2818 		(void) printf(gettext(", spilled into overflow volume"));
2819 	(void) printf("\n");
2820 
2821 	tmp_time = args.mtime;
2822 	if (tmp_time != 0)
2823 		(void) printf("%s %s", gettext("Latest modified time:"),
2824 		    ctime(&tmp_time));
2825 	else
2826 		(void) printf("%s\n", gettext("Latest modified time: unknown"));
2827 
2828 	(void) printf("%s %8llu\n", gettext("Volume size:"), args.size);
2829 	if (args.shdsize != 0) {
2830 		(void) printf("%s %lld %s %lld\n",
2831 		    gettext("Shadow chunks total:"), args.shdsize,
2832 		    gettext("Shadow chunks used:"), args.shdused);
2833 	}
2834 	bitmap_op(args.shadow_vol, 0, 1, 0, 0);
2835 }
2836 
2837 int
2838 abort_copy(char *volume)
2839 {
2840 	dsw_ioctl_t args;
2841 
2842 	if (!find_shadow_config(volume, NULL, &args))
2843 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2844 		    "group"), NULL);
2845 	args.status = spcs_s_ucreate();
2846 	if (do_ioctl(dsw_fd, DSWIOC_ABORT, &args)  == -1)
2847 		dsw_error(gettext("Abort failed"), &args.status);
2848 	spcs_log("ii", NULL, gettext("Abort %s"), args.shadow_vol);
2849 	spcs_s_ufree(&args.status);
2850 	return (0);
2851 }
2852 
2853 void
2854 iiversion()
2855 {
2856 	dsw_version_t args;
2857 
2858 	args.status = spcs_s_ucreate();
2859 	if (do_ioctl(dsw_fd, DSWIOC_VERSION, &args)  == -1)
2860 		dsw_error(gettext("Version failed"), &args.status);
2861 	spcs_s_ufree(&args.status);
2862 #ifdef DEBUG
2863 	(void) printf(gettext("Point in Time Copy version %d.%d.%d.%d\n"),
2864 	    args.major, args.minor, args.micro, args.baseline);
2865 #else
2866 	if (args.micro) {
2867 		(void) printf(gettext("Point in Time Copy version %d.%d.%d\n"),
2868 		    args.major, args.minor, args.micro);
2869 	} else {
2870 		(void) printf(gettext("Point in Time Copy version %d.%d\n"),
2871 		    args.major, args.minor);
2872 	}
2873 #endif
2874 }
2875 
2876 void
2877 list_volumes()
2878 {
2879 	dsw_list_t args;
2880 	int i, set, found;
2881 	dsw_config_t *lp;
2882 	ENTRY item, *ip;
2883 	dsw_config_t parms;
2884 
2885 	if ((i = do_ioctl(dsw_fd, DSWIOC_LISTLEN, &args)) == -1)
2886 		dsw_error("DSWIOC_LISTLEN", NULL);
2887 
2888 	args.status = spcs_s_ucreate();
2889 	args.list_used = 0;
2890 	args.list_size = i + 4;
2891 	lp = args.list = (dsw_config_t *)
2892 	    malloc(args.list_size * sizeof (dsw_config_t));
2893 
2894 	if (args.list == NULL)
2895 		dsw_error(gettext("Failed to allocate memory"), NULL);
2896 	if (do_ioctl(dsw_fd, DSWIOC_LIST, &args)  == -1)
2897 		dsw_error(gettext("List failed"), &args.status);
2898 	spcs_s_ufree(&args.status);
2899 
2900 	/* make a hashtable */
2901 	if (args.list_used > 0) {
2902 		if (hcreate(args.list_used) == 0) {
2903 			dsw_error(gettext("Failed to allocate memory"), NULL);
2904 			/*NOTREACHED*/
2905 		}
2906 	}
2907 
2908 	/* populate the hashtable */
2909 	for (i = 0; i < args.list_used; i++, lp++) {
2910 		item.key = lp->shadow_vol;
2911 		item.data = (char *)lp;
2912 		if (hsearch(item, ENTER) == NULL) {
2913 			dsw_error(gettext("Failed to allocate memory"), NULL);
2914 			/*NOTREACHED*/
2915 		}
2916 	}
2917 
2918 	/* perform action for each line of the stored config file */
2919 	for (set = 1; get_dsw_config(set, &parms) == 0; set++) {
2920 
2921 		/* Are there any II sets configured on this node? */
2922 		if (args.list_used > 0) {
2923 			item.key = parms.shadow_vol;
2924 
2925 			/* Is this volume configured on this node? */
2926 			if (ip = hsearch(item, FIND)) {
2927 
2928 				/* Handle Imported Shadows */
2929 				/* LINTED alignment of cast ok */
2930 				lp = (dsw_config_t *)ip->data;
2931 				if (strcmp(parms.master_vol,
2932 				    II_IMPORTED_SHADOW))
2933 					found = !(lp->flag & DSW_SHDIMPORT);
2934 				else
2935 					found = (lp->flag & DSW_SHDIMPORT);
2936 			}
2937 			else
2938 				found = FALSE;
2939 		}
2940 		else
2941 			found = FALSE;
2942 
2943 		if ((cfg_cluster_tag) &&
2944 		    strcmp(cfg_cluster_tag, parms.cluster_tag))
2945 			continue;
2946 
2947 		if ((group_name) && strcmp(group_name, parms.group_name))
2948 			continue;
2949 
2950 		(void) printf("%s %.*s %.*s %.*s%s\n",
2951 		    (parms.flag & DSW_GOLDEN) ? "ind" : "dep",
2952 		    DSW_NAMELEN, parms.master_vol,
2953 		    DSW_NAMELEN, parms.shadow_vol,
2954 		    DSW_NAMELEN, parms.bitmap_vol,
2955 		    found ? "" : gettext(" (suspended)"));
2956 	}
2957 	hdestroy();
2958 	free(args.list);
2959 }
2960 
2961 int
2962 wait_for_copy(char *volume)
2963 {
2964 	dsw_ioctl_t parms;
2965 	int rc;
2966 	static int unlocked = 0;
2967 	char *ppid;
2968 
2969 	if (unlocked && !ii_lock(cfg, CFG_RDLOCK)) {
2970 		dsw_error(gettext("Unable to set locking on the configuration"),
2971 		    NULL);
2972 	}
2973 	config_locked = 1;
2974 	if (!find_shadow_config(volume, NULL, &parms))
2975 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2976 		    "group"), NULL);
2977 	cfg_unlock(cfg);
2978 	config_locked = 0;
2979 	unlocked = 1;
2980 
2981 	parms.status = spcs_s_ucreate();
2982 	if (pflg) {
2983 #ifdef DEBUG
2984 		ppid = getenv("IIADM_PPID");
2985 		if (ppid) {
2986 			parms.pid = atoi(ppid);
2987 			(void) fprintf(stderr, "(using %s for ppid)\n", ppid);
2988 		} else {
2989 			parms.pid = (nflg) ? -1 : getppid();
2990 		}
2991 #else
2992 		parms.pid = (nflg) ? -1 : getppid();
2993 #endif
2994 		parms.flags |= CV_LOCK_PID;
2995 	}
2996 
2997 	rc = do_ioctl(dsw_fd, DSWIOC_WAIT, &parms);
2998 	if (rc == -1)
2999 		dsw_error(gettext("Wait failed"), &parms.status);
3000 	spcs_s_ufree(&parms.status);
3001 	return (0);
3002 }
3003 
3004 int
3005 export(char *volume)
3006 {
3007 	dsw_ioctl_t parms;
3008 	dsw_config_t conf;
3009 	char *old_ctag, dgname[DSW_NAMELEN];
3010 	int rc;
3011 
3012 	if (!find_shadow_config(volume, &conf, &parms))
3013 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3014 		    "group"), NULL);
3015 	if (mounted(volume))
3016 		dsw_error(gettext("Can't export a mounted volume"), NULL);
3017 
3018 	/* If this is an exportable shadow in the cluster, change ctag */
3019 	if (strlen(conf.cluster_tag) &&
3020 	    (cfg_dgname(volume, dgname, sizeof (dgname)))) {
3021 		old_ctag = cfg_cluster_tag;
3022 		cfg_resource(cfg, cfg_cluster_tag = strdup(dgname));
3023 	} else	old_ctag = NULL;
3024 
3025 	if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) {
3026 		dsw_error(gettext("Unable to parse config file"), NULL);
3027 	}
3028 	reload_vols = LD_DSVOLS | LD_SHADOWS;
3029 	conform_name(&volume);
3030 
3031 	spcs_log("ii", NULL, gettext("Export %s"), volume);
3032 	parms.status = spcs_s_ucreate();
3033 	rc = do_ioctl(dsw_fd, DSWIOC_EXPORT, &parms);
3034 	if (rc == -1)
3035 		dsw_error(gettext("Export failed"), &parms.status);
3036 	if (perform_autosv()) {
3037 		if (cfg_vol_disable(cfg, volume, cfg_cluster_tag, "ii") < 0) {
3038 			dsw_error(gettext("SV-disable failed"), NULL);
3039 		}
3040 		(void) cfg_commit(cfg);
3041 	}
3042 
3043 	/* restore old cluster tag, if changed */
3044 	if (old_ctag != NULL)
3045 		cfg_resource(cfg, cfg_cluster_tag = old_ctag);
3046 
3047 	spcs_s_ufree(&parms.status);
3048 	return (0);
3049 }
3050 
3051 int
3052 detach(char *volume)
3053 {
3054 	dsw_ioctl_t parms;
3055 	int rc;
3056 
3057 	if (!find_shadow_config(volume, NULL, &parms))
3058 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3059 		    "group"), NULL);
3060 	parms.status = spcs_s_ucreate();
3061 	rc = do_ioctl(dsw_fd, DSWIOC_ODETACH, &parms);
3062 	if (rc == 0) {
3063 		/* remove overflow from cfg line */
3064 		(void) sprintf(key, "ii.set%d.overflow", setnumber);
3065 		if (cfg_put_cstring(cfg, key, "-", 1) < 0) {
3066 				perror("cfg_put_cstring");
3067 		}
3068 		(void) cfg_commit(cfg);
3069 	} else {
3070 		spcs_log("ii", NULL, gettext("Detach of overflow %s failed"),
3071 		    parms.shadow_vol);
3072 		dsw_error(gettext("Failed to detach overflow volume"),
3073 		    &parms.status);
3074 	}
3075 	return (rc);
3076 }
3077 
3078 static void
3079 can_disable(char *vol)
3080 {
3081 	dsw_stat_t args;
3082 
3083 	if (mounted(vol)) {
3084 		(void) strlcpy(args.shadow_vol, vol, DSW_NAMELEN);
3085 		args.status = spcs_s_ucreate();
3086 		if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) != -1 &&
3087 		    (args.stat & DSW_GOLDEN) == 0) {
3088 			errno = EBUSY;
3089 			dsw_error(gettext("Shadow Volume is currently mounted "
3090 			    "and dependent on the master volume"), NULL);
3091 		}
3092 		spcs_s_ufree(&args.status);
3093 	}
3094 }
3095 
3096 static void
3097 clean_up_after_failed_disable(dsw_ioctl_t *parms)
3098 {
3099 	char **p;
3100 	dsw_stat_t args;
3101 
3102 	for (p = group_volumes; *p; p++) {
3103 		(void) strlcpy(args.shadow_vol, *p, DSW_NAMELEN);
3104 		args.status = spcs_s_ucreate();
3105 		if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) {
3106 			/* set was successfully disabled */
3107 			if (find_shadow_config(*p, NULL, NULL))
3108 				remove_iiset(setnumber, *p, 0);
3109 		}
3110 		spcs_s_ufree(&args.status);
3111 	}
3112 
3113 	dsw_error(gettext("Some sets in the group failed to disable"),
3114 	    &parms->status);
3115 }
3116 
3117 int
3118 dsw_group_or_single_disable(int argc, char *argv[])
3119 {
3120 	int rc = 0;
3121 	char **p;
3122 	dsw_ioctl_t parms;
3123 	int flags = 0;
3124 	dsw_config_t conf;
3125 	int shd_exported = 0;
3126 
3127 	if (argc != 2)
3128 		usage(gettext("Incorrect number of arguments"));
3129 
3130 	if (group_name) {
3131 		if (find_group_members(group_name) < 1)
3132 			dsw_error(gettext("Group does not exist or "
3133 			    "has no members"), NULL);
3134 		for (p = group_volumes; *p; p++) {
3135 			can_disable(*p);
3136 		}
3137 
3138 		(void) strncpy(parms.shadow_vol, group_name, DSW_NAMELEN);
3139 		if (*group_name)
3140 			flags = CV_IS_GROUP;
3141 	} else {
3142 		if (!find_shadow_config(argv[1], &conf, &parms)) {
3143 			dsw_error(gettext("Volume is not in a Point-in-Time "
3144 			    "Copy group"), NULL);
3145 		}
3146 
3147 		can_disable(argv[1]);
3148 		flags = 0;
3149 	}
3150 
3151 	if (group_name && !*group_name) {
3152 		/* user typed iiadm -g "" -d */
3153 		for (p = group_volumes; *p; p++) {
3154 			parms.status = spcs_s_ucreate();
3155 			parms.flags = flags;
3156 			(void) strncpy(parms.shadow_vol, *p, DSW_NAMELEN);
3157 			rc = do_ioctl(dsw_fd, DSWIOC_DISABLE, &parms);
3158 			if (rc == -1 && errno != DSW_ENOTFOUND)
3159 				dsw_error(gettext("Disable failed"),
3160 				    &parms.status);
3161 			if (!find_shadow_config(*p, NULL, NULL))
3162 				dsw_error(gettext("Volume is not in a Point-in"
3163 				    "-Time Copy group"), &parms.status);
3164 			remove_iiset(setnumber, *p, 0);
3165 			spcs_s_ufree(&parms.status);
3166 			spcs_log("ii", NULL, gettext("Disabled %s"),
3167 			    parms.shadow_vol);
3168 		}
3169 	} else {
3170 		if (is_exported(conf.shadow_vol)) {
3171 			shd_exported = 1;
3172 		}
3173 		if ((strcmp(conf.master_vol, II_IMPORTED_SHADOW) == 0) &&
3174 		    is_exported(conf.shadow_vol)) {
3175 			dsw_error(gettext(
3176 			"Imported shadow not disabled"), NULL);
3177 		}
3178 
3179 		parms.status = spcs_s_ucreate();
3180 		parms.flags = flags;
3181 		rc = do_ioctl(dsw_fd, DSWIOC_DISABLE, &parms);
3182 		if (rc == -1 && errno != DSW_ENOTFOUND) {
3183 			if (errno == DSW_EDISABLE) {
3184 				/*
3185 				 * one or more sets within the group
3186 				 * couldn't disable
3187 				 */
3188 				clean_up_after_failed_disable(&parms);
3189 			} else {
3190 				dsw_error(gettext("Disable failed"),
3191 				    &parms.status);
3192 			}
3193 		}
3194 		spcs_log("ii", NULL, gettext("Disabled %s"), parms.shadow_vol);
3195 	}
3196 
3197 
3198 	if (group_name && *group_name) {
3199 		for (p = group_volumes; *p; p++) {
3200 			if (!find_shadow_config(*p, NULL, NULL)) {
3201 				/* argh! */
3202 				(void) fprintf(stderr,
3203 				    gettext("Volume '%s' is not "
3204 				    "in a Point-in-Time Copy group"), *p);
3205 			} else {
3206 				remove_iiset(setnumber, *p, 0);
3207 			}
3208 		}
3209 	} else if (!group_name) {
3210 		if (!find_shadow_config(argv[1], NULL, NULL)) {
3211 			/* argh! */
3212 			dsw_error(gettext("Volume is not in a Point-in-Time "
3213 			    "Copy group"), NULL);
3214 		}
3215 
3216 		remove_iiset(setnumber, argv[1], shd_exported);
3217 	}
3218 
3219 	return (0);
3220 }
3221 
3222 int
3223 dsw_group_or_single_op(int argc, char *argv[], int (*op)(char *))
3224 {
3225 	int rc = 0;
3226 
3227 	if (argc != 2)
3228 		usage(gettext("Incorrect number of arguments"));
3229 
3230 	if (group_name) {
3231 		if (find_group_members(group_name) < 1)
3232 			dsw_error(gettext("Group does not exist or "
3233 			    "has no members"), NULL);
3234 		for (; *group_volumes; group_volumes++)
3235 			rc |= (*op)(*group_volumes);
3236 	} else {
3237 		rc = (*op)(argv[1]);
3238 	}
3239 	return (rc);
3240 }
3241 
3242 void
3243 dsw_list_clusters(char *cluster)
3244 {
3245 	dsw_aioctl_t *acopy_args;
3246 	int rc, i, count;
3247 	char *ptr;
3248 
3249 	if ((count = do_ioctl(dsw_fd, DSWIOC_LISTLEN, NULL)) < 0)
3250 		dsw_error("DSWIOC_LISTLEN", NULL);
3251 
3252 	acopy_args = malloc(sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
3253 	if (acopy_args == NULL)
3254 		dsw_error(gettext("Can't get memory for list enquiry"), NULL);
3255 
3256 	bzero(acopy_args, sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
3257 	acopy_args->count = count;
3258 	acopy_args->flags = 0;
3259 	acopy_args->status = spcs_s_ucreate();
3260 	if (cluster)
3261 		(void) strncpy(acopy_args->shadow_vol, cluster, DSW_NAMELEN);
3262 
3263 	rc = do_ioctl(dsw_fd, DSWIOC_CLIST, acopy_args);
3264 	if (rc == -1)
3265 		dsw_error(gettext("Cluster list access failure"),
3266 		    &acopy_args->status);
3267 
3268 	acopy_args->shadow_vol[DSW_NAMELEN*acopy_args->count] = NULL;
3269 
3270 	if (cluster) {
3271 		(void) printf(gettext("Sets in cluster resource group %s:\n"),
3272 		    cluster);
3273 	} else {
3274 		(void) printf(
3275 		    gettext("Currently configured resource groups\n"));
3276 	}
3277 	for (i = 0, ptr = acopy_args->shadow_vol; *ptr &&
3278 	    i < acopy_args->count; i++, ptr += DSW_NAMELEN) {
3279 		(void) printf("  %-64.64s\n", ptr);
3280 	}
3281 }
3282 
3283 void
3284 dsw_enable(int argc, char *argv[])
3285 {
3286 	if (argc != 5)
3287 		usage(gettext("Incorrect number of arguments"));
3288 
3289 	enable(argv[1], argv[2], argv[3], argv[4]);
3290 	exit(0);
3291 }
3292 
3293 
3294 void
3295 dsw_disable(int argc, char *argv[])
3296 {
3297 	(void) dsw_group_or_single_disable(argc, argv);
3298 	exit(0);
3299 }
3300 
3301 
3302 void
3303 dsw_copy_to_shadow(int argc, char *argv[])
3304 {
3305 	char	**volume_list;
3306 
3307 	if (argc != 2)
3308 		usage(gettext("Incorrect number of arguments"));
3309 	if (group_name == NULL)
3310 		volume_list = ++argv;
3311 	else {
3312 		if (find_group_members(group_name) < 1)
3313 			dsw_error(gettext("Group does not exist or "
3314 			    "has no members"), NULL);
3315 		volume_list = group_volumes;
3316 	}
3317 
3318 	exit(do_copy(volume_list, Copy, ToShadow, WaitForStart));
3319 }
3320 
3321 
3322 void
3323 dsw_update_shadow(int argc, char *argv[])
3324 {
3325 	char	**volume_list;
3326 
3327 	if (argc != 2)
3328 		usage(gettext("Incorrect number of arguments"));
3329 	if (group_name == NULL)
3330 		volume_list = ++argv;
3331 	else {
3332 		if (find_group_members(group_name) < 1)
3333 			dsw_error(gettext("Group does not exist or "
3334 			    "has no members"), NULL);
3335 		volume_list = group_volumes;
3336 	}
3337 
3338 	exit(do_copy(volume_list, Update, ToShadow, WaitForStart));
3339 }
3340 
3341 
3342 void
3343 dsw_copy_to_master(int argc, char *argv[])
3344 {
3345 	char	**volume_list;
3346 
3347 	if (argc != 2)
3348 		usage(gettext("Incorrect number of arguments"));
3349 	if (group_name == NULL) {
3350 		volume_list = ++argv;
3351 		check_action(gettext("Overwrite master with shadow volume?"));
3352 	} else {
3353 		check_action(gettext("Overwrite every"
3354 		    " master in this group with its shadow volume?"));
3355 		if (find_group_members(group_name) < 1)
3356 			dsw_error(gettext("Group does not exist or "
3357 			    "has no members"), NULL);
3358 		volume_list = group_volumes;
3359 	}
3360 
3361 	exit(do_copy(volume_list, Copy, ToMaster, WaitForStart));
3362 }
3363 
3364 
3365 void
3366 dsw_update_master(int argc, char *argv[])
3367 {
3368 	char	**volume_list;
3369 
3370 	if (argc != 2)
3371 		usage(gettext("Incorrect number of arguments"));
3372 	if (group_name == NULL) {
3373 		volume_list = ++argv;
3374 		check_action(gettext("Overwrite master with shadow volume?"));
3375 	} else {
3376 		check_action(gettext("Overwrite every"
3377 		    " master in this group with its shadow volume?"));
3378 		if (find_group_members(group_name) < 1)
3379 			dsw_error(gettext("Group does not exist or "
3380 			    "has no members"), NULL);
3381 		volume_list = group_volumes;
3382 	}
3383 
3384 	exit(do_copy(volume_list, Update, ToMaster, WaitForStart));
3385 }
3386 
3387 
3388 void
3389 dsw_abort_copy(int argc, char *argv[])
3390 {
3391 	exit(dsw_group_or_single_op(argc, argv, abort_copy));
3392 }
3393 
3394 
3395 void
3396 dsw_display_status(int argc, char *argv[])
3397 {
3398 	dsw_config_t parms;
3399 	int	in_config;
3400 
3401 	if (argc != 2 && argc != 1)
3402 		usage(gettext("Incorrect number of arguments"));
3403 
3404 	/* "iiadm -i" and "iiadm -i all" are equivalent */
3405 	if (argc == 2 && strcmp("all", argv[1]) != 0) {
3406 		in_config = find_shadow_config(argv[1], &parms, NULL);
3407 		if (!in_config) {
3408 			(void) printf(gettext(
3409 			    "Volume is not in configuration file\n"), NULL);
3410 			(void) fflush(stdout);
3411 			(void) strlcpy(parms.shadow_vol, argv[1], DSW_NAMELEN);
3412 		}
3413 		print_status(&parms, in_config);
3414 	} else if (group_name) {
3415 		if (find_group_members(group_name) < 1)
3416 			dsw_error(gettext("Group does not exist or "
3417 			    "has no members"), NULL);
3418 		for (; *group_volumes; group_volumes++) {
3419 			in_config = find_shadow_config(*group_volumes,
3420 			    &parms, NULL);
3421 			if (in_config)
3422 				print_status(&parms, in_config);
3423 		}
3424 	} else {
3425 		/* perform action for each line of the stored config file */
3426 		for (setnumber = 1;
3427 		    !get_dsw_config(setnumber, &parms); setnumber++) {
3428 			switch (check_cluster()) {
3429 			case II_CLUSTER:
3430 				if ((cfg_cluster_tag) &&
3431 				    (strcmp(cfg_cluster_tag,
3432 				    parms.cluster_tag)))
3433 					continue;
3434 				break;
3435 			case II_CLUSTER_LCL:
3436 				if (strlen(parms.cluster_tag))
3437 					continue;
3438 				break;
3439 			}
3440 			print_status(&parms, 1);
3441 		}
3442 	}
3443 	exit(0);
3444 }
3445 
3446 void
3447 dsw_display_bitmap(int argc, char *argv[])
3448 {
3449 	dsw_config_t parms;
3450 	int	in_config;
3451 
3452 	if (argc != 2)
3453 		usage(gettext("Incorrect number of arguments"));
3454 
3455 	in_config = find_shadow_config(argv[1], &parms, NULL);
3456 	if (!in_config) {
3457 		(void) printf(gettext(
3458 		    "Volume is not in configuration file\n"), NULL);
3459 		(void) fflush(stdout);
3460 		(void) strlcpy(parms.master_vol, argv[1], DSW_NAMELEN);
3461 	}
3462 
3463 	bitmap_op(parms.shadow_vol, 1, 0, 0, 0);
3464 	exit(0);
3465 }
3466 
3467 
3468 /*ARGSUSED*/
3469 void
3470 dsw_version(int argc, char *argv[])
3471 {
3472 	iiversion();
3473 	exit(0);
3474 }
3475 
3476 void
3477 dsw_reset(int argc, char *argv[])
3478 {
3479 	exit(dsw_group_or_single_op(argc, argv, reset));
3480 }
3481 
3482 void
3483 dsw_overflow(int argc, char *argv[])
3484 {
3485 	if (argc != 2)
3486 		usage(gettext("Incorrect number of arguments"));
3487 
3488 	exit(overflow(argv[1]));
3489 }
3490 
3491 void
3492 dsw_wait(int argc, char *argv[])
3493 {
3494 	exit(dsw_group_or_single_op(argc, argv, wait_for_copy));
3495 }
3496 
3497 /*ARGSUSED*/
3498 void
3499 dsw_list_volumes(int argc, char *argv[])
3500 {
3501 	if (argc != 1)
3502 		usage(gettext("Incorrect number of arguments"));
3503 
3504 	list_volumes();
3505 	exit(0);
3506 }
3507 
3508 void
3509 dsw_export(int argc, char *argv[])
3510 {
3511 	if (argc != 2)
3512 		usage(gettext("Incorrect number of arguments"));
3513 
3514 	exit(dsw_group_or_single_op(argc, argv, export));
3515 }
3516 
3517 void
3518 dsw_detach(int argc, char *argv[])
3519 {
3520 	(void) dsw_group_or_single_op(argc, argv, detach);
3521 	exit(0);
3522 }
3523 
3524 void
3525 import(char *shadow_volume, char *bitmap_volume)
3526 {
3527 	dsw_config_t parms = {0};
3528 	int rc = 0;
3529 	char	shd_dg[DSW_NAMELEN];
3530 	char	bmp_dg[DSW_NAMELEN];
3531 
3532 	/*
3533 	 * If importing a shadow volume and the shadow volume is already
3534 	 * configured, we only support this if we are in a Sun Cluster
3535 	 * and the current user specified a cluster tag of -C local
3536 	 */
3537 	if (find_shadow_config(shadow_volume, &parms, NULL)) {
3538 		dsw_error(gettext("Can't import volume on same node"), NULL);
3539 	}
3540 
3541 	switch (check_cluster()) {
3542 	case II_CLUSTER:
3543 	case II_CLUSTER_LCL:
3544 		(void) check_resource_group(shadow_volume);
3545 		if (cfg_cluster_tag) { /* check all volumes are in same dg */
3546 			if (cfg_dgname(shadow_volume, shd_dg, DSW_NAMELEN)
3547 			    == NULL)
3548 				dsw_error(gettext("Shadow volume not in a"
3549 				    " disk group"), NULL);
3550 			if (cfg_dgname(bitmap_volume, bmp_dg, DSW_NAMELEN)
3551 			    == NULL)
3552 				dsw_error(gettext("Bitmap volume not in a"
3553 				    " disk group"), NULL);
3554 			if (strcmp(bmp_dg, shd_dg) != 0)
3555 				dsw_error(gettext("Bitmap volume not in"
3556 				    " same disk group as shadow set members"),
3557 				    NULL);
3558 		}
3559 		break;
3560 	case II_NOT_CLUSTER:
3561 		/* do nothing */
3562 		break;
3563 	default:
3564 		dsw_error(gettext(
3565 		    "Unexpected return from check_cluster()"), NULL);
3566 	}
3567 
3568 	/* Local configuration volumes */
3569 	if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) {
3570 		dsw_error(gettext("Unable to parse config file"), NULL);
3571 	}
3572 
3573 	reload_vols = LD_DSVOLS | LD_SHADOWS;
3574 	conform_name(&shadow_volume);
3575 	(void) strcpy(parms.master_vol, II_IMPORTED_SHADOW);
3576 	(void) strlcpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
3577 	(void) strlcpy(parms.bitmap_vol, bitmap_volume, DSW_NAMELEN);
3578 	parms.flag = DSW_GOLDEN;
3579 
3580 	spcs_log("ii", NULL, gettext("Import %s %s"),
3581 	    parms.shadow_vol, parms.bitmap_vol);
3582 	parms.status = spcs_s_ucreate();
3583 	rc = do_ioctl(dsw_fd, DSWIOC_IMPORT, &parms);
3584 	if (rc == -1) {
3585 		spcs_log("ii", NULL, gettext("Import failed %s %s"),
3586 		    parms.shadow_vol, parms.bitmap_vol);
3587 		dsw_error(gettext("Import failed"), &parms.status);
3588 	}
3589 	if (perform_autosv()) {
3590 		if (cfg_vol_enable(cfg, shadow_volume, cfg_cluster_tag, "ii")
3591 		    < 0) {
3592 			dsw_error(gettext("SV-enable failed"), NULL);
3593 		}
3594 		/* cfg_commit is called by add_cfg_entry below */
3595 	}
3596 	spcs_s_ufree(&parms.status);
3597 	add_cfg_entry(&parms);
3598 }
3599 
3600 void
3601 dsw_import(int argc, char *argv[])
3602 {
3603 	if (argc != 3)
3604 		usage(gettext("Incorrect number of arguments"));
3605 	import(argv[1], argv[2]);
3606 
3607 	exit(0);
3608 }
3609 
3610 void
3611 join(char *shadow_volume, char *bitmap_file)
3612 {
3613 	dsw_ioctl_t shd;
3614 	dsw_config_t conf;
3615 	dsw_bitmap_t parms;
3616 	int rc = 0;
3617 	int size;
3618 	FILE *bmpfp;
3619 	uchar_t *shd_bitmap = 0;
3620 	ii_header_t header;
3621 	char dgname[DSW_NAMELEN];
3622 
3623 	if (!find_shadow_config(shadow_volume, &conf, &shd))
3624 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3625 		    "group"), NULL);
3626 
3627 	/* If this is an exportable shadow in the cluster, change ctag */
3628 	if (strlen(conf.cluster_tag) &&
3629 	    (cfg_dgname(shadow_volume, dgname, sizeof (dgname))))
3630 		cfg_resource(cfg, cfg_cluster_tag = strdup(dgname));
3631 
3632 	if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) {
3633 		dsw_error(gettext("Unable to parse config file"), NULL);
3634 	}
3635 	reload_vols = LD_DSVOLS | LD_SHADOWS;
3636 	conform_name(&shadow_volume);
3637 
3638 	if ((bmpfp = fopen(bitmap_file, "r")) == NULL) {
3639 		perror(bitmap_file);
3640 		(void) fprintf(stderr,
3641 		    gettext("Can't open imported bitmap volume\n"));
3642 		exit(1);
3643 	}
3644 
3645 	if (fread(&header, sizeof (header), 1, bmpfp) != 1) {
3646 		(void) fprintf(stderr,
3647 		    gettext("Can't read imported bitmap volume\n"));
3648 		exit(1);
3649 	}
3650 
3651 	/* See if this is a bitmap header */
3652 	switch (header.ii_magic) {
3653 	case DSW_DIRTY:		/* A copy of a enable bitmap volume */
3654 	case DSW_CLEAN:
3655 		check_action(gettext("Use the never imported bitmap?"));
3656 		break;
3657 	case DSW_INVALID:	/* A valid diskable secondary bitmap */
3658 		break;
3659 	default:
3660 		(void) fprintf(stderr,
3661 		    gettext("Secondary bitmap is not a valid bitmap volume\n"));
3662 		exit(1);
3663 	}
3664 
3665 	size = FBA_SIZE(header.ii_copyfba - header.ii_shdfba);
3666 	if ((shd_bitmap = malloc(size)) == NULL) {
3667 		perror("malloc");
3668 		exit(1);
3669 	}
3670 
3671 	if (fseek(bmpfp, FBA_SIZE(header.ii_shdfba), SEEK_SET)) {
3672 		perror("fseek");
3673 		exit(1);
3674 	}
3675 
3676 	if (fread(shd_bitmap, 1, size, bmpfp) != size) {
3677 		(void) fprintf(stderr,
3678 		    gettext("Can't read imported bitmap volume\n"));
3679 		exit(1);
3680 	}
3681 
3682 	(void) fclose(bmpfp);
3683 
3684 	(void) strlcpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
3685 	parms.shd_bitmap = shd_bitmap;
3686 	parms.shd_size = size;
3687 	parms.copy_bitmap = NULL;
3688 	parms.copy_size = 0;
3689 
3690 	spcs_log("ii", NULL, gettext("Join %s %s"),
3691 	    parms.shadow_vol, bitmap_file);
3692 	parms.status = spcs_s_ucreate();
3693 	rc = do_ioctl(dsw_fd, DSWIOC_JOIN, &parms);
3694 	if (rc == -1) {
3695 		spcs_log("ii", NULL, gettext("Join failed %s %s"),
3696 		    parms.shadow_vol, bitmap_file);
3697 		dsw_error(gettext("Join failed"), &parms.status);
3698 	}
3699 	if (perform_autosv()) {
3700 		rc = cfg_vol_enable(cfg, shadow_volume, cfg_cluster_tag, "ii");
3701 		if (rc < 0) {
3702 			dsw_error(gettext("SV-enable failed"), NULL);
3703 		}
3704 		(void) cfg_commit(cfg);
3705 	}
3706 	spcs_s_ufree(&parms.status);
3707 }
3708 
3709 int
3710 params(char *shadow_volume)
3711 {
3712 	char *delay = param_delay;
3713 	char *unit = param_unit;
3714 	dsw_copyp_t parms;
3715 	int rc = 0;
3716 	int get = 0;
3717 	int new_delay;
3718 	int new_unit;
3719 
3720 	(void) strlcpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
3721 	if (delay == NULL || unit == NULL) {
3722 		get = 1;
3723 		parms.copy_delay = -1;
3724 		parms.copy_unit = -1;
3725 	} else {
3726 		new_delay = parms.copy_delay = convert_int(delay);
3727 		new_unit = parms.copy_unit = convert_int(unit);
3728 	}
3729 
3730 	parms.status = spcs_s_ucreate();
3731 	rc = do_ioctl(dsw_fd, DSWIOC_COPYP, &parms);
3732 	if (rc == -1) {
3733 		(void) fprintf(stderr,
3734 		    gettext("Parameter ranges are delay(%d - %d), "
3735 		    "units(%d - %d)\n"), MIN_THROTTLE_DELAY, MAX_THROTTLE_DELAY,
3736 		    MIN_THROTTLE_UNIT, MAX_THROTTLE_UNIT);
3737 		dsw_error(gettext("Set Copy Parameters failed"), &parms.status);
3738 	}
3739 	if (!get)
3740 		spcs_log("ii", NULL, gettext("Changed copy parameters %s from "
3741 		    "%d %d to %d %d"), parms.shadow_vol, parms.copy_delay,
3742 		    parms.copy_unit, new_delay, new_unit);
3743 	else
3744 		(void) printf(gettext("volume: %s\ncopy delay: %d\ncopy unit:"
3745 		    " %d\n"), parms.shadow_vol, parms.copy_delay,
3746 		    parms.copy_unit);
3747 	spcs_s_ufree(&parms.status);
3748 	return (0);
3749 }
3750 
3751 static void
3752 do_attach(dsw_config_t *parms)
3753 {
3754 	dsw_config_t io;
3755 	int rc;
3756 	int check = 0;
3757 
3758 	spcs_log("ii", NULL, gettext("Attach %s %s"),
3759 	    parms->shadow_vol, parms->bitmap_vol);
3760 	parms->status = spcs_s_ucreate();
3761 	rc = do_ioctl(dsw_fd, DSWIOC_OATTACH, parms);
3762 	if (rc == -1) {
3763 		check = 1;
3764 		/* if overflow() fails, it calls dsw_error to exit */
3765 		(void) overflow(parms->bitmap_vol);
3766 	}
3767 	spcs_s_ufree(&parms->status);
3768 	if (check == 1) {
3769 		if (!find_shadow_config(parms->shadow_vol, &io, NULL))
3770 			dsw_error(
3771 			    gettext("Volume is not in a Point-in-Time Copy "
3772 			    "group"), NULL);
3773 		(void) strlcpy(io.bitmap_vol, parms->bitmap_vol, DSW_NAMELEN);
3774 		io.status = spcs_s_ucreate();
3775 		if (do_ioctl(dsw_fd, DSWIOC_OATTACH, &io) == -1) {
3776 			spcs_log("ii", NULL, gettext("Attach failed %s %s"),
3777 			    io.shadow_vol, parms->bitmap_vol);
3778 			dsw_error(gettext("Attach failed"), &io.status);
3779 		}
3780 		spcs_s_ufree(&io.status);
3781 	}
3782 }
3783 
3784 int
3785 attach(char *shadow_volume)
3786 {
3787 	dsw_config_t parms;
3788 	dsw_stat_t args;
3789 	char	shd_dg[DSW_NAMELEN];
3790 	char	ovr_dg[DSW_NAMELEN];
3791 
3792 	switch (check_cluster()) {
3793 	case II_CLUSTER:
3794 	case II_CLUSTER_LCL:
3795 		(void) check_resource_group(shadow_volume);
3796 		if (cfg_cluster_tag) { /* check all volumes are in same dg */
3797 			if (cfg_dgname(shadow_volume, shd_dg, DSW_NAMELEN)
3798 			    == NULL)
3799 				dsw_error(gettext("Shadow volume not in a"
3800 				    " disk group"), NULL);
3801 			if (cfg_dgname(overflow_file, ovr_dg, DSW_NAMELEN)
3802 			    == NULL)
3803 				dsw_error(gettext("Overflow volume not in a"
3804 				    " disk group"), NULL);
3805 			if (strcmp(ovr_dg, shd_dg) != 0)
3806 				dsw_error(gettext("Overflow volume not in"
3807 				    " same disk group as shadow set members"),
3808 				    NULL);
3809 		}
3810 		break;
3811 	case II_NOT_CLUSTER:
3812 		/* do nothing */
3813 		break;
3814 	default:
3815 		dsw_error(gettext(
3816 		    "Unexpected return from check_cluster()"), NULL);
3817 	}
3818 
3819 	/* assure that the overflow_file is not an II volume */
3820 	if (find_any_cf_line(overflow_file))
3821 		dsw_error(gettext(
3822 		    "Overflow volume is already in a Point-in-Time Copy "
3823 		    "group"), NULL);
3824 
3825 	/* use find_shadow_config() to find setnumber */
3826 	if (!find_shadow_config(shadow_volume, &parms, NULL))
3827 		dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3828 		    "group"), NULL);
3829 
3830 	/* can only attach an overflow volume to dependent, compact shadow */
3831 	(void) strlcpy(args.shadow_vol, shadow_volume, DSW_NAMELEN);
3832 
3833 	args.status = spcs_s_ucreate();
3834 	if ((do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) ||
3835 	    !(args.stat & DSW_TREEMAP))
3836 		dsw_error(gettext("Not a compact dependent shadow"), NULL);
3837 
3838 	/* bitmap_vol is overloaded */
3839 	(void) strlcpy(parms.bitmap_vol, overflow_file, DSW_NAMELEN);
3840 
3841 	do_attach(&parms);
3842 
3843 	/* add overflow to cfg line */
3844 	(void) sprintf(key, "ii.set%d.overflow", setnumber);
3845 	if (cfg_put_cstring(cfg, key, overflow_file,
3846 	    strlen(overflow_file)) < 0) {
3847 		perror("cfg_put_cstring");
3848 	}
3849 	(void) cfg_commit(cfg);
3850 	return (0);
3851 }
3852 
3853 void
3854 dsw_join(int argc, char *argv[])
3855 {
3856 	if (argc != 3)
3857 		usage(gettext("Incorrect number of arguments"));
3858 
3859 	join(argv[1], argv[2]);
3860 	exit(0);
3861 }
3862 
3863 void
3864 dsw_params(int argc, char *argv[])
3865 {
3866 	if (argc != 4 && argc != 2 && argc != 0)
3867 		usage(gettext("Incorrect number of arguments"));
3868 
3869 	if ((argc == 4) || (argc == 2)) {
3870 		param_delay = argv[1];
3871 		param_unit = argv[2];
3872 		if (argc == 4) {
3873 			argv[1] = argv[3];
3874 			argv[2] = NULL;
3875 		}
3876 	}
3877 	exit(dsw_group_or_single_op(2, argv, params));
3878 }
3879 
3880 /*ARGSUSED*/
3881 void
3882 dsw_attach(int argc, char *argv[])
3883 {
3884 	overflow_file = argv[1];
3885 	argv[1] = argv[2];
3886 	(void) dsw_group_or_single_op(2, argv, attach);
3887 	exit(0);
3888 }
3889 
3890 /*ARGSUSED*/
3891 void
3892 dsw_olist(int argc, char *argv[])
3893 {
3894 	char	*sp, *overflow_list, **vol;
3895 	int	count, i;
3896 	ENTRY	item, *found;
3897 	char	key[ CFG_MAX_KEY ], buf[ CFG_MAX_BUF ];
3898 
3899 	overflow_list = get_overflow_list();
3900 
3901 	/* count entries */
3902 	count = 0;
3903 	for (sp = overflow_list; *sp; sp += DSW_NAMELEN) {
3904 		++count;
3905 	}
3906 
3907 	/* create hash (adding room for suspended overflow volumes) */
3908 	if (hcreate(count + 1024) == 0) {
3909 		dsw_error(gettext("Out of memory creating lookup table"), NULL);
3910 		/*NOTREACHED*/
3911 	}
3912 
3913 	if (count > 0) {
3914 		/* create memory to store copy of list */
3915 		vol = (char **)calloc(count, sizeof (char *));
3916 		if (!vol) {
3917 			dsw_error(
3918 			    gettext("Out of memory creating lookup table"),
3919 			    NULL);
3920 			/*NOTREACHED*/
3921 		}
3922 
3923 		/* fill hash */
3924 		for (i = 0, sp = overflow_list; *sp; sp += DSW_NAMELEN, i++) {
3925 
3926 			/* make copy of string */
3927 			vol[ i ] = (char *)malloc(DSW_NAMELEN + 1);
3928 			(void) strlcpy(vol[ i ], sp, DSW_NAMELEN);
3929 
3930 			item.key = vol[ i ];
3931 			item.data = (char *)0;
3932 			(void) hsearch(item, ENTER);
3933 		}
3934 	}
3935 
3936 	/* loop through config file entries */
3937 	i = 0;
3938 	cfg_rewind(cfg, CFG_SEC_CONF);
3939 
3940 	/*CONSTCOND*/
3941 	while (1) {
3942 		++i;
3943 		(void) snprintf(key, CFG_MAX_KEY, "ii.set%d.overflow", i);
3944 		if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
3945 			break;
3946 		}
3947 
3948 		/* has this set got an overflow volume? */
3949 		if (!*buf) {
3950 			continue;
3951 		}
3952 
3953 		/* look up overflow in hash */
3954 		item.key = buf;
3955 		if (count > 0 && (found = hsearch(item, FIND)) != NULL) {
3956 			if (0 == (int)found->data) {
3957 				(void) printf("%s\n", buf);
3958 				found->data = (char *)1;
3959 				(void) hsearch(*found, ENTER);
3960 			}
3961 		} else {
3962 			/* must be part of a suspended set */
3963 			(void) printf("%s (attached to suspended set)\n", buf);
3964 			item.key = buf;
3965 			item.data = (char *)1;
3966 			(void) hsearch(item, ENTER);
3967 		}
3968 	}
3969 
3970 	exit(0);
3971 }
3972 
3973 void
3974 dsw_ostat(int argc, char *argv[])
3975 {
3976 	dsw_ostat_t	args;
3977 	int	stat_flags;
3978 
3979 	if (argc != 2)
3980 		usage(gettext("Incorrect number of arguments"));
3981 
3982 	(void) strlcpy(args.overflow_vol, argv[1], DSW_NAMELEN);
3983 
3984 	args.status = spcs_s_ucreate();
3985 	if (do_ioctl(dsw_fd, DSWIOC_OSTAT2, &args) == -1)
3986 		dsw_error(gettext("Stat failed"), &args.status);
3987 	spcs_s_ufree(&args.status);
3988 
3989 	if ((args.hversion >= 1) && (args.hmagic == II_OMAGIC)) {
3990 		stat_flags = args.flags;
3991 		if (stat_flags & IIO_CNTR_INVLD)
3992 			(void) printf(gettext("Clean shutdown of volume "
3993 			"sets associated with overflow volume "
3994 			"did not occur.\n"
3995 			"Overflow counters will be inconsistent "
3996 			"until new point-in-time(s) are taken.\n"));
3997 	}
3998 	(void) printf(gettext("Total number of attached shadows: %d\n"),
3999 	    args.drefcnt);
4000 	(void) printf(gettext("Number of currently attached shadows: %d\n"),
4001 	    args.crefcnt);
4002 	(void) printf(gettext("Total number of chunks: %lld\n"), args.nchunks);
4003 	(void) printf(gettext("Number of chunks ever allocated: %lld\n"),
4004 	    args.used);
4005 	(void) printf(gettext("Number of used chunks: %lld\n"),
4006 	    (args.nchunks - args.unused));
4007 	(void) printf(gettext("Number of unused chunks: %lld\n"), args.unused);
4008 	exit(0);
4009 }
4010 
4011 /*ARGSUSED*/
4012 void
4013 dsw_move_2_group(int argc, char *argv[])
4014 {
4015 	dsw_config_t parms;
4016 	dsw_movegrp_t movegrp;
4017 	grptag_t *gdata;
4018 	int waserr = 0;
4019 
4020 	/* handle move to NULL group, or group of all spaces or tabs */
4021 	(void) strncpy(movegrp.new_group, group_name, DSW_NAMELEN);
4022 	if ((strlen(group_name) == 0) || (strcspn(group_name, " \t") == 0)) {
4023 		group_name = "-";
4024 		bzero(movegrp.new_group, DSW_NAMELEN);
4025 		gdata = NULL;
4026 	} else {
4027 		/* get the ctag for this group (if any) */
4028 		gdata = (grptag_t *)nsc_lookup(volhash, group_name);
4029 	}
4030 
4031 	movegrp.status = spcs_s_ucreate();
4032 
4033 	for (++argv; *argv; argv++) {
4034 		if (!find_shadow_config(*argv, &parms, NULL))
4035 			dsw_error(gettext("Volume is not in a Point-in-Time "
4036 			    "Copy group"), NULL);
4037 
4038 		/* ensure the ctag matches the group */
4039 		if (gdata && *gdata->ctag) {
4040 			if (strncmp(parms.cluster_tag, gdata->ctag,
4041 			    DSW_NAMELEN) != 0) {
4042 				(void) fprintf(stderr, "%s: %s %s %s\n", cmdnam,
4043 				    gettext("unable to move set"), *argv,
4044 				    gettext("into new group - cluster "
4045 				    "resource mismatch"));
4046 				waserr = 1;
4047 				continue;
4048 			}
4049 		}
4050 
4051 		/* move the set in the kernel */
4052 		(void) strncpy(movegrp.shadow_vol, parms.shadow_vol,
4053 		    DSW_NAMELEN);
4054 		if (do_ioctl(dsw_fd, DSWIOC_MOVEGRP, &movegrp) < 0)
4055 			dsw_error(gettext("Failed to move group in kernel"),
4056 			    NULL);
4057 
4058 		/* now update the config */
4059 		(void) sprintf(key, "ii.set%d.group", setnumber);
4060 		if (cfg_put_cstring(cfg, key, group_name,
4061 		    strlen(group_name)) < 0) {
4062 			perror("cfg_put_cstring");
4063 		}
4064 		(void) cfg_commit(cfg);
4065 	}
4066 	spcs_s_ufree(&movegrp.status);
4067 	cfg_close(cfg);
4068 	exit(waserr);
4069 }
4070 
4071 void
4072 dsw_list_groups()
4073 {
4074 	FILE *pfp;
4075 
4076 	if ((pfp = popen("/usr/bin/sort -u", "w")) == NULL) {
4077 		dsw_error(gettext("Can't open sort program"), NULL);
4078 	}
4079 
4080 	(void) fflush(stdout);
4081 	for (setnumber = 1; /*CSTYLED*/; setnumber++) {
4082 		(void) snprintf(key, sizeof (key), "ii.set%d.group", setnumber);
4083 		if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0)
4084 			break;
4085 
4086 		/* skip if shadow set is not in any group */
4087 		if (strcmp(buf, "") == 0)
4088 			continue;
4089 		(void) fprintf(pfp, "%s\n", buf);
4090 	}
4091 	(void) pclose(pfp);
4092 }
4093 
4094 void
4095 dsw_list_group_volumes()
4096 {
4097 	FILE *pfp;
4098 
4099 	if (find_group_members(group_name) < 1)
4100 		dsw_error(gettext("Group does not exist or has no members"),
4101 		    NULL);
4102 
4103 	if ((pfp = popen("/usr/bin/sort -u", "w")) == NULL) {
4104 		dsw_error(gettext("Can't open sort program"), NULL);
4105 	}
4106 
4107 	(void) fflush(stdout);
4108 	for (; *group_volumes; group_volumes++)
4109 		(void) fprintf(pfp, "%s\n", *group_volumes);
4110 	(void) pclose(pfp);
4111 }
4112 
4113 static void
4114 load_ii_vols(CFGFILE *cfg)
4115 {
4116 	int set, entries;
4117 	char *mst, *shd, *buf, **entry;
4118 	char *ctag, *group;
4119 	mstcount_t *mdata;
4120 	shdvol_t *sdata;
4121 	grptag_t *gdata;
4122 	static int whinged = 0;
4123 
4124 	if (volhash) {
4125 		return;
4126 	}
4127 
4128 	volhash = nsc_create_hash();
4129 	cfg_rewind(cfg, CFG_SEC_CONF);
4130 	entries = cfg_get_section(cfg, &entry, "ii");
4131 	for (set = 1; set <= entries; set++) {
4132 		buf = entry[set - 1];
4133 
4134 		/* grab master volume name */
4135 		mst = strtok(buf, " ");
4136 		if (!mst) {
4137 			free(buf);
4138 			break;
4139 		}
4140 
4141 		/* grab shadow, group & cnode fields */
4142 		shd = strtok(NULL, " ");
4143 		(void) strtok(NULL, " ");	/* bitmap */
4144 		(void) strtok(NULL, " ");	/* mode */
4145 		(void) strtok(NULL, " ");	/* overflow */
4146 		ctag = strtok(NULL, " ");	/* cnode */
4147 		(void) strtok(NULL, " ");	/* options */
4148 		group = strtok(NULL, " ");	/* group */
4149 
4150 		/* Fix optional tags */
4151 		if (ctag)
4152 			ctag += strspn(ctag, "-");
4153 		if (group)
4154 			group += strspn(group, "-");
4155 
4156 		/* If cluster tags don't match, skip record */
4157 		if ((cfg_cluster_tag && strcmp(ctag, cfg_cluster_tag)) ||
4158 		    (!cfg_cluster_tag && strlen(ctag))) {
4159 			free(buf);
4160 			continue;
4161 		}
4162 
4163 		/* master volume, may be duplicates */
4164 		mdata = (mstcount_t *)nsc_lookup(volhash, mst);
4165 		if (mdata) {
4166 			++mdata->count;
4167 		} else {
4168 			mdata = (mstcount_t *)malloc(sizeof (mstcount_t));
4169 			mdata->count = 1;
4170 			(void) nsc_insert_node(volhash, mdata, mst);
4171 		}
4172 
4173 		/* grab shadow volume name */
4174 		sdata = (shdvol_t *)malloc(sizeof (shdvol_t));
4175 		(void) strncpy(sdata->master, mst, DSW_NAMELEN);
4176 		(void) nsc_insert_node(volhash, sdata, shd);
4177 
4178 		/* No need to continue if no groups or ctags */
4179 		if (!group || !*group || !ctag || !*ctag) {
4180 			free(buf);
4181 			continue;
4182 		}
4183 
4184 		gdata = (grptag_t *)nsc_lookup(volhash, group);
4185 		if (gdata) {
4186 			/* group already exists - check ctag */
4187 			if (*ctag &&
4188 			    (strncmp(ctag, gdata->ctag, DSW_NAMELEN) != 0)) {
4189 				if (!whinged) {
4190 					(void) printf(gettext(
4191 					    "Warning: multiple "
4192 					    "cluster resource groups "
4193 					    "defined within a single "
4194 					    "I/O group\n"));
4195 					whinged = 1;
4196 				}
4197 			}
4198 		} else {
4199 			gdata = (grptag_t *)malloc(sizeof (grptag_t));
4200 			(void) strncpy(gdata->ctag, ctag, DSW_NAMELEN);
4201 			(void) nsc_insert_node(volhash, gdata, group);
4202 		}
4203 
4204 		free(buf);
4205 	}
4206 
4207 	/* free up any leftovers */
4208 	while (set < entries)
4209 		free(entry[set++]);
4210 	if (entries)
4211 		free(entry);
4212 }
4213 
4214 static void
4215 unload_ii_vols()
4216 {
4217 	nsc_remove_all(volhash, free);
4218 	volhash = 0;
4219 }
4220 
4221 static int
4222 perform_autosv()
4223 {
4224 	static int result;
4225 	static int calculated = 0;
4226 	int rc;
4227 
4228 #ifdef DEBUG
4229 	if (getenv("II_SET_CLUSTER"))
4230 		return (1);
4231 #endif
4232 
4233 	if (calculated) {
4234 		return (result);
4235 	}
4236 
4237 	/*
4238 	 * we only perform auto-sv if we're in a sun cluster or if
4239 	 * we're on a standalone system.  I.e. we don't do auto-sv on Harry
4240 	 */
4241 	rc = check_cluster();
4242 
4243 	if (II_NOT_CLUSTER == rc) {
4244 		result = 1;
4245 	} else {
4246 		result = cfg_issuncluster();
4247 	}
4248 
4249 	calculated = 1;
4250 	return (result);
4251 }
4252 
4253 /*
4254  * Returns true if set has had the shadow volume exported.
4255  * Returns false if shadow volume is not exported, or set is suspended.
4256  */
4257 static int
4258 is_exported(char *set)
4259 {
4260 	dsw_stat_t args;
4261 	int rc;
4262 
4263 	(void) strlcpy(args.shadow_vol, set, DSW_NAMELEN);
4264 	args.status = spcs_s_ucreate();
4265 
4266 	rc = do_ioctl(dsw_fd, DSWIOC_STAT, &args);
4267 	spcs_s_ufree(&args.status);
4268 
4269 	if (-1 == rc) {
4270 		/* set must be suspended, or being disabled */
4271 		return (0);
4272 	}
4273 
4274 	return ((args.stat & DSW_SHDEXPORT) == DSW_SHDEXPORT);
4275 }
4276 
4277 static void
4278 conform_name(char **path)
4279 {
4280 	char *cfgname;
4281 	int rc = cfg_get_canonical_name(cfg, *path, &cfgname);
4282 
4283 	if (rc < 0) {
4284 		dsw_error(gettext("Unable to parse config file"), NULL);
4285 	}
4286 	if (rc) {
4287 		(void) printf("  '%s'\n%s\n  '%s'\n", *path,
4288 		    gettext("is currently configured as"), cfgname);
4289 		check_action(gettext("Perform operation with indicated volume"
4290 		    " name?"));
4291 		*path = cfgname;
4292 		/*
4293 		 * NOTE: *path ought to be deallocated ('free(*path)') after
4294 		 * we're done with it, but since this routine is called just
4295 		 * before we exit, it doesn't really matter
4296 		 */
4297 	}
4298 }
4299 
4300 /*
4301  * verify_groupname(char *, int);
4302  *
4303  * Check the group name for the following rules:
4304  *	1. The name does not start with a '-'
4305  *	2. The name does not contain any space characters as defined by
4306  *	   isspace(3C).
4307  * If either of these rules are broken, error immediately. The check for a
4308  * leading dash can be skipped if the 'testDash' argument is false. This is to
4309  * allow for the '-g -L' functionality.
4310  *
4311  */
4312 static void
4313 verify_groupname(char *grp, int testDash)
4314 {
4315 	int i;
4316 
4317 	if (testDash && grp[0] == '-') {
4318 		errno = EINVAL;
4319 		dsw_error(gettext("group name cannot start with a '-'"), NULL);
4320 	}
4321 
4322 	for (i = 0; grp[i] != '\0'; i++) {
4323 		if (isspace(grp[i])) {
4324 			errno = EINVAL;
4325 			dsw_error(gettext("group name cannot contain a space"),
4326 			    NULL);
4327 		}
4328 	}
4329 }
4330 
4331 void
4332 check_iishadow(char *shadow_vol) {
4333 	int i;
4334 	int entries;
4335 	char **entry;
4336 	char *shost;
4337 	char *svol;
4338 	char *buf;
4339 	void *librdc;
4340 
4341 	/*
4342 	 * See if librdc is around
4343 	 * If not, we can just return
4344 	 */
4345 	if (librdc = dlopen(RDC_LIB, RTLD_LAZY | RTLD_GLOBAL))
4346 		self_check = (int (*)(char *)) dlsym(librdc, "self_check");
4347 	else {
4348 		return;
4349 	}
4350 
4351 	entry = NULL;
4352 	entries = cfg_get_section(cfg, &entry, "sndr");
4353 	for (i = 0; i < entries; i++) {
4354 		buf = entry[i];
4355 
4356 		(void) strtok(buf, " ");	/* phost */
4357 		(void) strtok(NULL, " ");	/* primary */
4358 		(void) strtok(NULL, " ");	/* pbitmap */
4359 		shost = strtok(NULL, " ");	/* shost */
4360 		svol = strtok(NULL, " ");	/* secondary */
4361 
4362 		if (self_check(shost) && (strcmp(shadow_vol, svol) == 0)) {
4363 			free(buf);
4364 			if (entries)
4365 				free(entry);
4366 			errno = EINVAL;
4367 			dsw_error(gettext(
4368 			    "shadow volume is in use as SNDR secondary volume"),
4369 			    NULL);
4370 		}
4371 		free(buf);
4372 	}
4373 
4374 	(void) dlclose(librdc);
4375 	if (entries)
4376 		free(entry);
4377 }
4378