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