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
62typedef struct mstcount_s {
63	int count;
64} mstcount_t;
65typedef struct shdvol_s {
66	char master[ DSW_NAMELEN ];
67} shdvol_t;
68typedef struct grptag_s {
69	char ctag[ DSW_NAMELEN ];
70} grptag_t;
71hash_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"
77static 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
89static char *cfg_cluster_tag = NULL;
90static CFGFILE *cfg = NULL;
91
92void 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
101unsigned long	bm_size;		/* size in bytes of bitmap */
102unsigned long	bm_actual;		/* original number of bits in bitmap */
103int	debug = 0;
104
105int	dsw_fd;
106
107#define	LD_II		0x00000001
108#define	LD_DSVOLS	0x00000002
109#define	LD_SVOLS	0x00000004
110#define	LD_SHADOWS	0x00000008
111
112static int reload_vols = 0;
113static int config_locked = 0;
114static int last_lock;
115
116/*
117 * names for do_copy() flags.
118 */
119
120enum	copy_update {Copy = 0, Update};
121enum	copy_direction {ToShadow = 0, ToMaster};
122enum	copy_wait {WaitForStart = 0, WaitForEnd};
123
124char	*cmdnam;
125
126unsigned char	*allocate_bitmap(char *);
127void		usage(char *);
128void		enable(char *, char *, char *, char *);
129int		disable(char *);
130void		bitmap_op(char *, int, int, int, int);
131void		print_status(dsw_config_t *, int);
132int		abort_copy(char *);
133int		reset(char *);
134int		overflow(char *);
135void		iiversion(void);
136int		wait_for_copy(char *);
137int		export(char *);
138void		list_volumes(void);
139void		dsw_error(char *, spcs_s_info_t *);
140void		InitEnv();
141static void	check_dg_is_local(char *dgname);
142static int	check_resource_group(char *volume);
143static int	check_diskgroup(char *path, char *result);
144static int	check_cluster();
145static void	unload_ii_vols();
146static void	load_ii_vols(CFGFILE *);
147static int	perform_autosv();
148static int	is_exported(char *);
149static void	conform_name(char **);
150static void	do_attach(dsw_config_t *);
151static int	ii_lock(CFGFILE *, int);
152static void	verify_groupname(char *grp, int testDash);
153
154void	dsw_list_clusters(char *);
155void	dsw_enable(int, char **);
156void	dsw_disable(int, char **);
157void	dsw_copy_to_shadow(int, char **);
158void	dsw_update_shadow(int, char **);
159void	dsw_copy_to_master(int, char **);
160void	dsw_update_master(int, char **);
161void	dsw_abort_copy(int, char **);
162void	dsw_display_status(int, char **);
163void	dsw_display_bitmap(int, char **);
164void	dsw_reset(int, char **);
165void	dsw_overflow(int, char **);
166void	dsw_version(int, char **);
167void	dsw_wait(int, char **);
168void	dsw_list_volumes(int, char **);
169void	dsw_list_group_volumes();
170void	dsw_export(int, char **);
171void	dsw_import(int, char **);
172void	dsw_join(int, char **);
173void	dsw_attach(int, char **);
174void	dsw_detach(int, char **);
175void	dsw_params(int, char **);
176void	dsw_olist(int, char **);
177void	dsw_ostat(int, char **);
178void	dsw_move_2_group(int, char **);
179void	dsw_list_groups();
180void	check_iishadow(char *);
181
182extern char *optarg;
183extern int optind, opterr, optopt;
184
185int	Aflg;
186int	Cflg;
187int	CLflg;
188int	Dflg;
189int	Eflg;
190int	Iflg;
191int	Jflg;
192int	Lflg;
193int	Oflg;
194int	Pflg;
195int	Qflg;
196int	Rflg;
197int	aflg;
198int	bflg;
199int	cflg;
200int	dflg;
201int	eflg;
202int	fflg;
203int	gflg;
204int	gLflg;
205int	hflg;
206int	iflg;
207int	lflg;
208int	mflg;
209int	nflg;
210int	pflg;
211int	uflg;
212int	vflg;
213int	wflg;
214
215int	errflg;
216#ifdef DEBUG
217const 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 */
221const char single_opts[] = "a:c:d:e:g:hilmnpu:vw:A:C:D:E:I:J:LO:PQ:R:";
222#endif
223const char group_opts[] = "ac:de:ilmnpu:wA:C:DELPR";
224const char *opt_list = single_opts;
225
226char	buf[CFG_MAX_BUF];
227char	key[CFG_MAX_KEY];
228char	last_overflow[DSW_NAMELEN];
229int	setnumber;
230char	*group_name;
231char	**group_volumes;
232enum copy_direction direction;
233char	*param_delay, *param_unit;
234char	*overflow_file;
235
236#ifdef lint
237int
238iiadm_lintmain(int argc, char *argv[])
239#else
240int
241main(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
670static int
671ii_lock(CFGFILE *cfg, int locktype)
672{
673	last_lock = locktype;
674	return (cfg_lock(cfg, locktype));
675}
676
677static int
678do_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
765static int
766get_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
798static int
799find_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}
812int
813find_any_cf_line(char *volume)
814{
815	return (find_next_cf_line(volume, 1));
816}
817
818static int
819find_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}
830int
831find_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 */
840char *
841get_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
873int
874find_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
908static int
909find_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
928int
929find_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
934int
935find_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
980void
981add_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
1009void
1010remove_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 */
1095int
1096check_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 */
1154static int
1155check_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
1201static void
1202check_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 */
1229static int
1230check_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 */
1268void
1269sigterm(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
1279volatile pid_t	dead_child;
1280int	dead_stat;
1281
1282/*ARGSUSED*/
1283void
1284sigchild(int sig)
1285{
1286	dead_child = wait(&dead_stat);
1287}
1288
1289/*
1290 * InitEnv(): initializes environment
1291 */
1292void
1293InitEnv()
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 */
1326void
1327dsw_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
1352void
1353free_bitmap(unsigned char *bitmap)
1354{
1355	free(bitmap);
1356}
1357
1358
1359int
1360get_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
1378unsigned char *
1379allocate_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 */
1444void
1445usage(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
1649static  char    yeschr[MAX_LINE_SIZE + 2];
1650static  char    nochr[MAX_LINE_SIZE + 2];
1651
1652static int
1653yes(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
1687static int
1688convert_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
1707void
1708check_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
1729enum	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
1739int
1740child_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
1777int
1778mounted(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
1816void
1817enable(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
2159int
2160reset(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
2302int
2303overflow(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
2331void
2332bitmap_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
2399static int
2400validate_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
2470int
2471do_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
2585int
2586do_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
2709void
2710print_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
2843int
2844abort_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
2859void
2860iiversion()
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
2882void
2883list_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
2967int
2968wait_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
3010int
3011export(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
3057int
3058detach(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
3084static void
3085can_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
3103static void
3104clean_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
3125int
3126dsw_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
3230int
3231dsw_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
3251void
3252dsw_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
3292void
3293dsw_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
3303void
3304dsw_disable(int argc, char *argv[])
3305{
3306	(void) dsw_group_or_single_disable(argc, argv);
3307	exit(0);
3308}
3309
3310
3311void
3312dsw_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
3332void
3333dsw_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
3353void
3354dsw_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
3377void
3378dsw_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
3401void
3402dsw_abort_copy(int argc, char *argv[])
3403{
3404	exit(dsw_group_or_single_op(argc, argv, abort_copy));
3405}
3406
3407
3408void
3409dsw_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
3460void
3461dsw_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*/
3484void
3485dsw_version(int argc, char *argv[])
3486{
3487	iiversion();
3488	exit(0);
3489}
3490
3491void
3492dsw_reset(int argc, char *argv[])
3493{
3494	exit(dsw_group_or_single_op(argc, argv, reset));
3495}
3496
3497void
3498dsw_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
3506void
3507dsw_wait(int argc, char *argv[])
3508{
3509	exit(dsw_group_or_single_op(argc, argv, wait_for_copy));
3510}
3511
3512/*ARGSUSED*/
3513void
3514dsw_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
3523void
3524dsw_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
3532void
3533dsw_detach(int argc, char *argv[])
3534{
3535	(void) dsw_group_or_single_op(argc, argv, detach);
3536	exit(0);
3537}
3538
3539void
3540import(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
3617void
3618dsw_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
3627void
3628join(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
3727int
3728params(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
3770static void
3771do_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
3804int
3805attach(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
3875void
3876dsw_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
3885void
3886dsw_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*/
3903void
3904dsw_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*/
3913void
3914dsw_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
3996void
3997dsw_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*/
4036void
4037dsw_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
4095void
4096dsw_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
4118void
4119dsw_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
4137static void
4138load_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
4238static void
4239unload_ii_vols()
4240{
4241	nsc_remove_all(volhash, free);
4242	volhash = 0;
4243}
4244
4245static int
4246perform_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 */
4281static int
4282is_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
4302static void
4303conform_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 */
4337static void
4338verify_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
4356void
4357check_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