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.
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.
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]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/mnttab.h>
51 #include <sys/nsctl/cfg.h>
52 #include <sys/nsctl/nsc_hash.h>
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 */
60 #include <sys/nskernd.h>
62 typedef struct mstcount_s
{
65 typedef struct shdvol_s
{
66 char master
[ DSW_NAMELEN
];
68 typedef struct grptag_s
{
69 char ctag
[ DSW_NAMELEN
];
71 hash_node_t
**volhash
= NULL
;
73 #define DSW_TEXT_DOMAIN "II"
76 #define RDC_LIB "/usr/lib/librdc.so.1"
77 static int (*self_check
)(char *);
80 * Support for the special cluster tag "local" to be used with -C in a
81 * cluster for local volumes.
83 #define II_LOCAL_TAG "local"
85 #define II_NOT_CLUSTER 1
87 #define II_CLUSTER_LCL 3
89 static char *cfg_cluster_tag
= NULL
;
90 static CFGFILE
*cfg
= NULL
;
92 void sigterm(int sig
);
94 #define SD_BIT_CLR(bmap, bit) (bmap &= ~(1 << bit))
95 #define SD_BIT_ISSET(bmap, bit) ((bmap & (1 << bit)) != 0)
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 */
101 unsigned long bm_size
; /* size in bytes of bitmap */
102 unsigned long bm_actual
; /* original number of bits in bitmap */
107 #define LD_II 0x00000001
108 #define LD_DSVOLS 0x00000002
109 #define LD_SVOLS 0x00000004
110 #define LD_SHADOWS 0x00000008
112 static int reload_vols
= 0;
113 static int config_locked
= 0;
114 static int last_lock
;
117 * names for do_copy() flags.
120 enum copy_update
{Copy
= 0, Update
};
121 enum copy_direction
{ToShadow
= 0, ToMaster
};
122 enum copy_wait
{WaitForStart
= 0, WaitForEnd
};
126 unsigned char *allocate_bitmap(char *);
128 void enable(char *, char *, char *, char *);
130 void bitmap_op(char *, int, int, int, int);
131 void print_status(dsw_config_t
*, int);
132 int abort_copy(char *);
134 int overflow(char *);
135 void iiversion(void);
136 int wait_for_copy(char *);
138 void list_volumes(void);
139 void dsw_error(char *, spcs_s_info_t
*);
141 static void check_dg_is_local(char *dgname
);
142 static int check_resource_group(char *volume
);
143 static int check_diskgroup(char *path
, char *result
);
144 static int check_cluster();
145 static void unload_ii_vols();
146 static void load_ii_vols(CFGFILE
*);
147 static int perform_autosv();
148 static int is_exported(char *);
149 static void conform_name(char **);
150 static void do_attach(dsw_config_t
*);
151 static int ii_lock(CFGFILE
*, int);
152 static void verify_groupname(char *grp
, int testDash
);
154 void dsw_list_clusters(char *);
155 void dsw_enable(int, char **);
156 void dsw_disable(int, char **);
157 void dsw_copy_to_shadow(int, char **);
158 void dsw_update_shadow(int, char **);
159 void dsw_copy_to_master(int, char **);
160 void dsw_update_master(int, char **);
161 void dsw_abort_copy(int, char **);
162 void dsw_display_status(int, char **);
163 void dsw_display_bitmap(int, char **);
164 void dsw_reset(int, char **);
165 void dsw_overflow(int, char **);
166 void dsw_version(int, char **);
167 void dsw_wait(int, char **);
168 void dsw_list_volumes(int, char **);
169 void dsw_list_group_volumes();
170 void dsw_export(int, char **);
171 void dsw_import(int, char **);
172 void dsw_join(int, char **);
173 void dsw_attach(int, char **);
174 void dsw_detach(int, char **);
175 void dsw_params(int, char **);
176 void dsw_olist(int, char **);
177 void dsw_ostat(int, char **);
178 void dsw_move_2_group(int, char **);
179 void dsw_list_groups();
180 void check_iishadow(char *);
183 extern int optind
, opterr
, optopt
;
217 const char single_opts
[] =
218 "a:b:c:d:e:f:g:hilmnpu:vw:A:C:D:E:I:J:LO:PQ:R:";
220 /* no b or f flags */
221 const char single_opts
[] = "a:c:d:e:g:hilmnpu:vw:A:C:D:E:I:J:LO:PQ:R:";
223 const char group_opts
[] = "ac:de:ilmnpu:wA:C:DELPR";
224 const char *opt_list
= single_opts
;
226 char buf
[CFG_MAX_BUF
];
227 char key
[CFG_MAX_KEY
];
228 char last_overflow
[DSW_NAMELEN
];
231 char **group_volumes
;
232 enum copy_direction direction
;
233 char *param_delay
, *param_unit
;
238 iiadm_lintmain(int argc
, char *argv
[])
241 main(int argc
, char *argv
[])
251 (void) memset(av
, 0, sizeof (av
));
253 while ((c
= getopt(argc
, argv
, opt_list
)) != EOF
)
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
;
267 "must specify m or s with -c"));
282 if (strcmp(optarg
, "ind") == 0)
283 av
[4] = "independent";
284 else if (strcmp(optarg
, "dep") == 0)
289 "must specify ind or dep with -e"));
295 opt_list
= group_opts
;
297 if (group_name
&& *group_name
== '-') {
298 gLflg
= (strcmp("-L", group_name
) == 0);
302 verify_groupname(group_name
, !gLflg
);
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
;
320 "must specify m or s with -u"));
327 av
[0] = "display_status";
332 av
[0] = "list_config";
338 av
[0] = "move_to_group";
350 av
[0] = "display_bitmap";
357 av
[0] = "abort_copy";
383 cfg_cluster_tag
= optarg
;
384 if (cfg_cluster_tag
&& *cfg_cluster_tag
== '-') {
385 CLflg
= (strcmp("-L", cfg_cluster_tag
) == 0);
441 /* If -g group -L, force error */
442 if (group_name
) actions
++;
463 usage(gettext("unrecognized argument"));
467 usage(gettext("must specify an action flag"));
469 /* default behavior is to list configuration */
470 lflg
++; av
[0] = "list_config"; ac
= 1;
475 usage(gettext("too many action flags"));
479 if (gflg
&& (Iflg
|| Jflg
|| Oflg
|| Qflg
))
480 usage(gettext("can't use a group with this option"));
482 usage(gettext("must use a group with this option"));
485 * Open configuration file.
487 if ((cfg
= cfg_open(NULL
)) == NULL
) {
488 perror("unable to access configuration");
493 * Set write locking (CFG_WRLOCK) for:
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
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");
513 * If we are in a cluster, set or derive a valid disk group
515 switch (check_cluster()) {
518 * If in a Sun Cluster, can't Import an II shadow
519 * Must be done as -C local
523 "-I (import) only allowed as -C local"), NULL
);
527 * If a cluster tag was specified or derived, set it
530 dsw_list_clusters(argv
[optind
]);
534 cfg_resource(cfg
, cfg_cluster_tag
);
538 if (cfg_cluster_tag
!= NULL
)
540 "-C is valid only in a Sun Cluster"), NULL
);
544 "Unexpected return from check_cluster()"), NULL
);
547 /* preload the ii config */
549 reload_vols
|= LD_II
;
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
++];
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
];
568 if (direction
== ToMaster
)
569 dsw_update_master(ac
, av
);
571 dsw_update_shadow(ac
, av
);
574 av
[1] = argv
[optind
];
578 dsw_display_status(ac
, av
);
580 dsw_display_bitmap(ac
, av
);
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
];
588 if (direction
== ToMaster
)
589 dsw_copy_to_master(ac
, av
);
591 dsw_copy_to_shadow(ac
, av
);
593 dsw_abort_copy(ac
, av
);
597 if (argc
- optind
!= 1)
598 usage(gettext("must specify 2 volumes with -I"));
599 av
[2] = argv
[optind
++];
604 if (argc
- optind
!= 0)
605 usage(gettext("must specify overflow volume " \
606 "when using groups with -A"));
609 if (argc
- optind
!= 1)
610 usage(gettext("specify 2 volumes with -A"));
612 av
[2] = argv
[optind
++];
618 if (argc
- optind
!= 1)
619 usage(gettext("must specify 2 volumes with -J"));
620 av
[2] = argv
[optind
++];
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;
634 "must specify delay, unit and shadow with -P"));
637 dsw_overflow(ac
, av
);
645 if ((gflg
) && (!group_name
))
646 dsw_list_group_volumes();
648 dsw_list_volumes(ac
, av
);
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
];
661 dsw_move_2_group(ac
, av
);
671 ii_lock(CFGFILE
*cfg
, int locktype
)
673 last_lock
= locktype
;
674 return (cfg_lock(cfg
, locktype
));
678 do_ioctl(int fd
, int cmd
, void *arg
)
692 case DSWIOC_SHUTDOWN
:
704 case DSWIOC_SBITSSET
:
705 case DSWIOC_CBITSSET
:
708 case DSWIOC_CHANGETAG
:
721 case DSWIOC_OLISTLEN
:
727 (void) fprintf(stderr
,
728 "cfg locking needs to be set for %08x\n", cmd
);
734 /* unload vol hashes */
735 if (reload_vols
& LD_II
)
737 if (reload_vols
& LD_SHADOWS
)
738 cfg_unload_shadows();
739 if (reload_vols
& LD_DSVOLS
)
741 if (reload_vols
& LD_SVOLS
)
744 rc
= ioctl(fd
, cmd
, arg
);
746 if (config_locked
&& unlocked
) {
747 (void) cfg_lock(cfg
, last_lock
);
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
)
766 get_dsw_config(int setno
, dsw_config_t
*parms
)
768 char buf
[CFG_MAX_BUF
];
769 char key
[CFG_MAX_KEY
];
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)
776 (void) snprintf(key
, sizeof (key
), "ii.set%d.shadow", setno
);
777 (void) cfg_get_cstring(cfg
, key
, parms
->shadow_vol
, DSW_NAMELEN
);
779 (void) snprintf(key
, sizeof (key
), "ii.set%d.bitmap", setno
);
780 (void) cfg_get_cstring(cfg
, key
, parms
->bitmap_vol
, DSW_NAMELEN
);
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
;
787 (void) snprintf(key
, sizeof (key
), "ii.set%d.overflow", setno
);
788 (void) cfg_get_cstring(cfg
, key
, last_overflow
, DSW_NAMELEN
);
790 (void) snprintf(key
, sizeof (key
), "ii.set%d.group", setno
);
791 (void) cfg_get_cstring(cfg
, key
, parms
->group_name
, DSW_NAMELEN
);
793 (void) snprintf(key
, sizeof (key
), "ii.set%d.cnode", setno
);
794 (void) cfg_get_cstring(cfg
, key
, parms
->cluster_tag
, DSW_NAMELEN
);
799 find_next_cf_line(char *volume
, int next
)
801 dsw_config_t cf_line
;
803 for (setnumber
= next
; get_dsw_config(setnumber
, &cf_line
) == 0;
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)
813 find_any_cf_line(char *volume
)
815 return (find_next_cf_line(volume
, 1));
819 find_next_shadow_line(char *volume
, int next
)
821 dsw_config_t cf_line
;
823 for (setnumber
= next
; get_dsw_config(setnumber
, &cf_line
) == 0;
825 if (strncmp(volume
, cf_line
.shadow_vol
, DSW_NAMELEN
) == 0)
831 find_shadow_line(char *volume
)
833 return (find_next_shadow_line(volume
, 1));
837 * this function is designed to be called once, subsequent calls won't
838 * free memory allocated by earlier invocations.
843 dsw_aioctl_t
*acopy_args
;
846 num
= do_ioctl(dsw_fd
, DSWIOC_OLISTLEN
, NULL
);
848 dsw_error(gettext("Can't get overflow list length"), NULL
);
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
);
854 acopy_args
->count
= num
;
855 acopy_args
->flags
= 0;
856 acopy_args
->status
= spcs_s_ucreate();
858 rc
= do_ioctl(dsw_fd
, DSWIOC_OLIST
, acopy_args
);
860 dsw_error(gettext("Overflow list access failure"),
861 &acopy_args
->status
);
863 acopy_args
->shadow_vol
[DSW_NAMELEN
*acopy_args
->count
] = NULL
;
865 return (acopy_args
->shadow_vol
);
869 * this function is designed to be called once, subsequent calls won't
870 * free memory allocated by earlier invocations.
874 find_group_members(char *group
)
879 group_volumes
= NULL
;
880 for (setnumber
= 1; /*CSTYLED*/; setnumber
++) {
881 (void) snprintf(key
, sizeof (key
), "ii.set%d.group", setnumber
);
882 if (cfg_get_cstring(cfg
, key
, buf
, sizeof (buf
)) < 0)
885 if (strcmp(group
, buf
))
888 (void) snprintf(key
, sizeof (key
), "ii.set%d.shadow",
890 if (cfg_get_cstring(cfg
, key
, buf
, sizeof (buf
)) < 0)
893 if (nmembers
>= vector_len
) {
895 group_volumes
= realloc(group_volumes
, (1+vector_len
) *
898 group_volumes
[nmembers
] = strdup(buf
);
902 group_volumes
[nmembers
] = NULL
; /* terminate list */
907 find_next_matching_cf_line(
908 char *volume
, dsw_config_t
*conf
, dsw_ioctl_t
*io
, int next
)
912 if (!find_next_cf_line(volume
, next
)) {
918 (void) get_dsw_config(setnumber
, conf
);
920 (void) strlcpy(io
->shadow_vol
, conf
->shadow_vol
, DSW_NAMELEN
);
926 find_matching_cf_line(char *volume
, dsw_config_t
*conf
, dsw_ioctl_t
*io
)
928 return (find_next_matching_cf_line(volume
, conf
, io
, 1));
932 find_shadow_config(char *volume
, dsw_config_t
*conf
, dsw_ioctl_t
*io
)
937 bzero(io
, sizeof (dsw_ioctl_t
));
939 c
= conf
? conf
: &cf
;
941 /* perform action for each line of the stored config file */
942 for ((void) snprintf(key
, sizeof (key
), "ii.set%d.shadow", setnumber
);
943 cfg_get_cstring(cfg
, key
, c
->shadow_vol
, DSW_NAMELEN
) >= 0;
944 (void) snprintf(key
, sizeof (key
), "ii.set%d.shadow",
946 if (strncmp(volume
, c
->shadow_vol
, DSW_NAMELEN
) == 0) {
947 (void) get_dsw_config(setnumber
, c
);
949 if (check_resource_group(c
->bitmap_vol
)) {
954 switch (check_cluster()) {
956 if ((cfg_cluster_tag
) &&
957 (strcmp(cfg_cluster_tag
, c
->cluster_tag
)))
961 if (strlen(c
->cluster_tag
))
967 (void) strlcpy(io
->shadow_vol
, c
->shadow_vol
,
977 add_cfg_entry(dsw_config_t
*parms
)
979 /* insert the well-known fields first */
980 (void) snprintf(buf
, sizeof (buf
), "%s %s %s %s",
981 parms
->master_vol
, parms
->shadow_vol
, parms
->bitmap_vol
,
982 (parms
->flag
& DSW_GOLDEN
) ? "I" : "D");
984 if (cfg_put_cstring(cfg
, "ii", buf
, strlen(buf
)) >= 0) {
985 /* if we have a group name, add it */
987 if (find_any_cf_line(parms
->shadow_vol
)) {
988 (void) sprintf(buf
, "ii.set%d.group",
990 if (cfg_put_cstring(cfg
, buf
,
991 group_name
, strlen(group_name
)) < 0)
992 perror("cfg_put_cstring");
995 perror("cfg_location");
998 /* commit the record */
999 (void) cfg_commit(cfg
);
1002 perror("cfg_put_string");
1006 remove_iiset(int setno
, char *shadow
, int shd_exp
)
1010 char sn
[CFG_MAX_BUF
];
1012 if (perform_autosv()) {
1017 if (cfg_load_dsvols(cfg
) < 0 || cfg_load_svols(cfg
) < 0) {
1018 dsw_error(gettext("Unable to parse config file"), NULL
);
1021 sdata
= (shdvol_t
*)nsc_lookup(volhash
, shadow
);
1024 * Handle the normal cases of disabling a set that is
1025 * not an imported shadow volume
1027 if (strcmp(sdata
->master
, II_IMPORTED_SHADOW
)) {
1029 * Handle multiple-shadows of single master
1031 mdata
= (mstcount_t
*)
1032 nsc_lookup(volhash
, sdata
->master
);
1033 if ((mdata
) && (mdata
->count
== 1)) {
1034 if (cfg_vol_disable(cfg
, sdata
->master
,
1035 cfg_cluster_tag
, "ii") < 0)
1037 "SV disable of master "
1044 * Handle disk group name of different shadow
1048 * If shadow is exported, then do nothing
1051 } else if (cfg_cluster_tag
&&
1052 strcmp(cfg_cluster_tag
, "") &&
1053 cfg_dgname(shadow
, sn
, sizeof (sn
)) &&
1055 strcmp(sn
, cfg_cluster_tag
)) {
1056 /* reload disk group volumes */
1057 cfg_resource(cfg
, sn
);
1058 cfg_unload_dsvols();
1060 (void) cfg_load_dsvols(cfg
);
1061 (void) cfg_load_svols(cfg
);
1062 if (cfg_vol_disable(cfg
, shadow
, sn
,
1065 "SV disable of shadow "
1069 cfg_resource(cfg
, cfg_cluster_tag
);
1071 if (cfg_vol_disable(cfg
, shadow
,
1072 cfg_cluster_tag
, "ii") < 0)
1074 "SV disable of shadow failed"),
1079 cfg_unload_dsvols();
1081 reload_vols
&= ~(LD_SVOLS
| LD_DSVOLS
| LD_II
);
1084 (void) sprintf(key
, "ii.set%d", setno
);
1085 if (cfg_put_cstring(cfg
, key
, NULL
, 0) < 0) {
1086 perror("cfg_put_cstring");
1088 (void) cfg_commit(cfg
);
1092 * determine if we are running in a Sun Cluster Environment
1097 static int is_cluster
= -1;
1100 char *cdebug
= getenv("II_SET_CLUSTER");
1104 * If this routine was previously called, just return results
1106 if (is_cluster
!= -1)
1107 return (is_cluster
);
1110 * See if Sun Cluster was installed on this node
1113 if (cdebug
) rc
= atoi(cdebug
);
1116 rc
= cfg_iscluster();
1119 * Determine if user specified -C local
1121 if ((cfg_cluster_tag
== NULL
) ||
1122 (strcmp(cfg_cluster_tag
, II_LOCAL_TAG
))) {
1124 * We're in a Sun Cluster, and no "-C local"
1126 is_cluster
= II_CLUSTER
;
1129 * We're in a Sun Cluster, but "-C local" was specified
1131 is_cluster
= II_CLUSTER_LCL
;
1132 cfg_cluster_tag
= "";
1134 return (is_cluster
);
1135 } else if (rc
== 0) {
1137 * Not in a Sun Cluster
1139 is_cluster
= II_NOT_CLUSTER
;
1140 return (is_cluster
);
1142 dsw_error(gettext("unable to ascertain environment"), NULL
);
1147 return (is_cluster
);
1151 * Determine if we need to set a cfg_resource based on this volume
1154 check_resource_group(char *volume
)
1156 char diskgroup
[CFG_MAX_BUF
];
1159 * If we are in a cluster, attempt to derive a new resource group
1163 if (getenv("II_SET_CLUSTER") || (check_cluster() == II_CLUSTER
)) {
1165 if (check_cluster() == II_CLUSTER
) {
1167 if (check_diskgroup(volume
, diskgroup
)) {
1168 if (cfg_cluster_tag
== NULL
) {
1169 cfg_cluster_tag
= strdup(diskgroup
);
1170 if (cfg_cluster_tag
== NULL
)
1172 "Memory allocation failure"), NULL
);
1173 cfg_resource(cfg
, cfg_cluster_tag
);
1177 * Check dgname and cluster tag from -C are
1180 if (strcmp(diskgroup
, cfg_cluster_tag
) != 0) {
1181 char error_buffer
[128];
1182 (void) snprintf(error_buffer
,
1183 sizeof (error_buffer
),
1184 gettext("-C (%s) does not match "
1185 "disk group name (%s) for %s"),
1186 cfg_cluster_tag
, diskgroup
, volume
);
1187 spcs_log("ii", NULL
, error_buffer
);
1188 dsw_error(error_buffer
, NULL
);
1191 } else if (cfg_cluster_tag
== NULL
)
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
);
1202 check_dg_is_local(char *dgname
)
1204 char error_buffer
[128];
1209 * check where this disk service is mastered
1211 rc
= cfg_dgname_islocal(dgname
, &othernode
);
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
,
1221 dsw_error(error_buffer
, NULL
);
1226 * Carry out cluster based checks for a specified volume, or just
1230 check_diskgroup(char *path
, char *result
)
1232 char dgname
[CFG_MAX_BUF
];
1233 char error_buffer
[128];
1236 char *override
= getenv("II_CLUSTER_TAG");
1238 (void) strcpy(result
, override
);
1243 * Check on path name, a returned NULL dgname is valid
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
);
1250 if (strcmp(dgname
, "") == 0)
1254 * See if disk group is local to this node
1256 check_dg_is_local(dgname
);
1259 * Copy dgname into result
1261 (void) strcpy(result
, dgname
);
1266 * sigterm (): traps specified signal , usually termination one
1271 spcs_log("ii", NULL
, gettext("%s received signal %d"), cmdnam
, sig
);
1276 * sigchild; reap child and collect status.
1279 volatile pid_t dead_child
;
1286 dead_child
= wait(&dead_stat
);
1290 * InitEnv(): initializes environment
1295 (void) setlocale(LC_ALL
, "");
1296 (void) textdomain(DSW_TEXT_DOMAIN
);
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
);
1314 dsw_fd
= open(DSWDEV
, O_RDONLY
);
1324 * print an error message, followed by decoded errno then exit.
1327 dsw_error(char *str
, spcs_s_info_t
*status
)
1331 (void) fprintf(stderr
, "%s: %s:\n", cmdnam
, str
);
1332 if (status
== NULL
) {
1334 if (ESRCH
== errno
) {
1335 sp
= "Set/volume not found";
1337 sp
= strerror(errno
);
1339 (void) fprintf(stderr
, "%s\n", sp
? sp
: "");
1341 spcs_s_report(*status
, stderr
);
1342 spcs_s_ufree(status
);
1353 free_bitmap(unsigned char *bitmap
)
1360 get_bitmap(master_volume
, shd_bitmap
, copy_bitmap
, size
)
1361 char *master_volume
;
1362 unsigned char *shd_bitmap
;
1363 unsigned char *copy_bitmap
;
1368 (void) strlcpy(parms
.shadow_vol
, master_volume
, DSW_NAMELEN
);
1369 parms
.shd_bitmap
= shd_bitmap
;
1370 parms
.shd_size
= size
;
1371 parms
.copy_bitmap
= copy_bitmap
;
1372 parms
.copy_size
= size
;
1374 return (do_ioctl(dsw_fd
, DSWIOC_BITMAP
, &parms
));
1378 allocate_bitmap(char *shadow_volume
)
1380 unsigned char *shd_bitmap
;
1381 unsigned char *copy_bitmap
;
1388 (void) strlcpy(args
.shadow_vol
, shadow_volume
, DSW_NAMELEN
);
1390 args
.status
= spcs_s_ucreate();
1391 if (do_ioctl(dsw_fd
, DSWIOC_STAT
, &args
) == -1)
1392 dsw_error(gettext("Stat failed"), &args
.status
);
1394 stat_flags
= args
.stat
;
1395 if (stat_flags
& DSW_BMPOFFLINE
)
1398 bm_size
= args
.size
;
1399 bm_size
= (bm_size
+ DSW_SIZE
-1) / DSW_SIZE
;
1400 bm_actual
= bm_size
;
1401 bm_size
= (bm_size
+ DSW_BITS
-1) / DSW_BITS
;
1402 spcs_s_ufree(&args
.status
);
1404 p
= shd_bitmap
= (unsigned char *) malloc(bm_size
);
1406 perror(gettext("malloc bitmap"));
1410 q
= copy_bitmap
= (unsigned char *) malloc(bm_size
);
1412 perror(gettext("malloc bitmap"));
1417 (void) memset(shd_bitmap
, 0, bm_size
);
1418 (void) memset(copy_bitmap
, 0, bm_size
);
1420 if (get_bitmap(shadow_volume
, shd_bitmap
, copy_bitmap
, bm_size
) < 0) {
1427 * "or" the copy and shadow bitmaps together to return a composite
1428 * bitmap that contains the total set of differences between the
1431 for (i
= bm_size
; i
-- > 0; /*CSTYLED*/)
1436 return (shd_bitmap
);
1440 * print usage message and exit.
1446 (void) fprintf(stderr
, "%s: %s\n", cmdnam
, why
);
1448 (void) fprintf(stderr
, "%s\n",
1449 gettext("\nBrief summary:"));
1450 (void) fprintf(stderr
, "%s\n",
1451 gettext("\t-e {ind|dep} master_vol shadow_vol "
1453 (void) fprintf(stderr
, "%s\n",
1454 gettext("\t-[cu {s|m}] volume_set"));
1455 (void) fprintf(stderr
, "%s\n",
1456 gettext("\t-i all"));
1457 (void) fprintf(stderr
, "%s\n",
1458 gettext("\t-[adDEilPRw] volume_set"));
1459 (void) fprintf(stderr
, "%s\n",
1460 gettext("\t-g group_name [options]"));
1461 (void) fprintf(stderr
, "%s\n",
1462 gettext("\t-C cluster_tag [options]"));
1463 (void) fprintf(stderr
, "%s\n",
1464 gettext("\t-[hilLv]"));
1465 (void) fprintf(stderr
, "%s\n",
1466 gettext("\t-[IJ] volume_set bitmap"));
1467 (void) fprintf(stderr
, "%s\n",
1468 gettext("\t-A overflow_vol volume_set"));
1469 (void) fprintf(stderr
, "%s\n",
1470 gettext("\t-[OQ] overflow_vol"));
1471 (void) fprintf(stderr
, "%s\n",
1472 gettext("\t-P {delay} {units} volume_set"));
1474 /* assume we came here due to a user mistake */
1479 (void) fprintf(stdout
, "%s\n",
1480 gettext("Point-in-Time Copy Administrator CLI options"));
1481 (void) fprintf(stdout
, "%s\n",
1482 gettext("Usage summary:"));
1483 (void) fprintf(stdout
, "%s\n",
1484 gettext("\t-e ind m s b\tenable independent master shadow "
1486 (void) fprintf(stdout
, "%s\n",
1487 gettext("\t-e dep m s b\tenable dependent master shadow "
1489 if (check_cluster() == II_CLUSTER
)
1490 (void) fprintf(stdout
, "%s\n",
1491 gettext("\t-ne ind m s b\tenable exportable master "
1493 (void) fprintf(stdout
, "%s\n",
1494 gettext("\t-d v\t\tdisable volume"));
1495 (void) fprintf(stdout
, "%s\n",
1496 gettext("\t-u s v\t\tupdate shadow volume"));
1497 (void) fprintf(stdout
, "%s\n",
1498 gettext("\t-u m v\t\tupdate master volume"));
1499 (void) fprintf(stdout
, "%s\n",
1500 gettext("\t-c s v\t\tcopy to shadow volume"));
1501 (void) fprintf(stdout
, "%s\n",
1502 gettext("\t-c m v\t\tcopy to master volume"));
1503 (void) fprintf(stdout
, "%s\n",
1504 gettext("\t-a v\t\tabort copy volume"));
1505 (void) fprintf(stdout
, "%s\n",
1506 gettext("\t-w v\t\twait volume"));
1507 (void) fprintf(stdout
, "%s\n",
1508 gettext("\t-i v\t\tdisplay volume status"));
1509 (void) fprintf(stdout
, "%s\n",
1510 gettext("\t-i all\t\tdisplay all volume status"));
1511 (void) fprintf(stdout
, "%s\n",
1512 gettext("\t-l\t\tlist all volumes"));
1513 (void) fprintf(stdout
, "%s\n",
1514 gettext("\t-R v\t\treset volume"));
1515 (void) fprintf(stdout
, "%s\n",
1516 gettext("\t-A o v\t\tattach overflow to volume"));
1517 (void) fprintf(stdout
, "%s\n",
1518 gettext("\t-D v\t\tdetach overflow from volume"));
1519 (void) fprintf(stdout
, "%s\n",
1520 gettext("\t-L\t\tlist all overflow volumes"));
1521 (void) fprintf(stdout
, "%s\n",
1522 gettext("\t-O o\t\tinitialize overflow"));
1523 (void) fprintf(stdout
, "%s\n",
1524 gettext("\t-Q o\t\tquery status of overflow"));
1525 (void) fprintf(stdout
, "%s\n",
1526 gettext("\t-E v\t\texport shadow volume"));
1527 (void) fprintf(stdout
, "%s\n",
1528 gettext("\t-I v b\t\timport volume bitmap"));
1529 (void) fprintf(stdout
, "%s\n",
1530 gettext("\t-J v b\t\tjoin volume bitmap"));
1531 (void) fprintf(stdout
, "%s\n",
1532 gettext("\t-P d u v\tset copy delay/units for volume"));
1533 (void) fprintf(stdout
, "%s\n",
1534 gettext("\t-P v\t\tget copy delay/units for volume"));
1535 (void) fprintf(stdout
, "%s\n",
1536 gettext("\t-C tag\t\tcluster resource tag"));
1538 (void) fprintf(stdout
, "%s\n",
1539 gettext("\t-b v\t\tdisplay bitmap volume"));
1540 (void) fprintf(stdout
, "%s\n",
1541 gettext("\t-f f\t\tuse private configuration file"));
1543 (void) fprintf(stdout
, "%s\n",
1544 gettext("\t-v\t\tprint software versions"));
1545 (void) fprintf(stdout
, "%s\n",
1546 gettext("\t-n\t\tperform action without question"));
1547 (void) fprintf(stdout
, "%s\n",
1548 gettext("\t-p [-c|-u] {m|s}"
1549 "enable PID locking on copy or update"));
1550 (void) fprintf(stdout
, "%s\n",
1551 gettext("\t-p -w v\t\tdisable PID locking"));
1552 (void) fprintf(stdout
, "%s\n",
1553 gettext("\t-h\t\tiiadm usage summary"));
1554 (void) fprintf(stdout
, "%s\n",
1555 gettext("\nUsage summary for options that support "
1556 "grouping (-g g):"));
1557 (void) fprintf(stdout
, "%s\n",
1558 gettext("\t-g g -e ind m s b group enable independent "
1559 "master shadow bitmap"));
1560 (void) fprintf(stdout
, "%s\n",
1561 gettext("\t-g g -e dep m s b group enable dependent "
1562 "master shadow bitmap"));
1563 (void) fprintf(stdout
, "%s\n",
1564 gettext("\t-g g -d\t\tdisable group"));
1565 (void) fprintf(stdout
, "%s\n",
1566 gettext("\t-g g -u s\tupdate shadow for all volumes in "
1568 (void) fprintf(stdout
, "%s\n",
1569 gettext("\t-g g -u m\tupdate master for all volumes in "
1571 (void) fprintf(stdout
, "%s\n",
1572 gettext("\t-g g -c s\tcopy to shadow for all volumes in "
1574 (void) fprintf(stdout
, "%s\n",
1575 gettext("\t-g g -c m\tcopy to master for all volumes in "
1577 (void) fprintf(stdout
, "%s\n",
1578 gettext("\t-g g -a\t\tabort copy for all volumes in "
1580 (void) fprintf(stdout
, "%s\n",
1581 gettext("\t-g g -w\t\twait for all volumes in group"));
1582 (void) fprintf(stdout
, "%s\n",
1583 gettext("\t-g g -i\t\tdisplay status of all volumes in "
1585 (void) fprintf(stdout
, "%s\n",
1586 gettext("\t-g g -l\t\tlist all volumes in group"));
1587 (void) fprintf(stdout
, "%s\n",
1588 gettext("\t-g -L\t\tlist all groups"));
1589 (void) fprintf(stdout
, "%s\n",
1590 gettext("\t-g g -m v v\tmove one or more volumes into "
1592 (void) fprintf(stdout
, "%s\n",
1593 gettext("\t-g \"\" -m v\tremove volume from group"));
1594 (void) fprintf(stdout
, "%s\n",
1595 gettext("\t-g g -R\t\treset all volumes in group"));
1596 (void) fprintf(stdout
, "%s\n",
1597 gettext("\t-g g -A o\tattach overflow to all volumes in "
1599 (void) fprintf(stdout
, "%s\n",
1600 gettext("\t-g g -D\t\tdetach overflow from all volumes in "
1602 (void) fprintf(stdout
, "%s\n",
1603 gettext("\t-g g -E\t\texport shadow volume for all "
1604 "volumes in group"));
1605 (void) fprintf(stdout
, "%s\n",
1606 gettext("\t-g g -P d u\tset copy delay/units for all "
1607 "volumes in group"));
1608 (void) fprintf(stdout
, "%s\n",
1609 gettext("\t-g g -P\t\tget copy delay/units for all "
1610 "volumes in group"));
1611 (void) fprintf(stdout
, "%s\n",
1612 gettext("\nLegend summary:"));
1613 (void) fprintf(stdout
, "%s\n",
1614 gettext("\tind\t\tindependent volume set"));
1615 (void) fprintf(stdout
, "%s\n",
1616 gettext("\tdep\t\tdependent volume set"));
1617 (void) fprintf(stdout
, "%s\n",
1618 gettext("\tall\t\tall configured volumes"));
1619 (void) fprintf(stdout
, "%s\n",
1620 gettext("\tm\t\tmaster volume"));
1621 (void) fprintf(stdout
, "%s\n",
1622 gettext("\ts\t\tshadow volume"));
1623 (void) fprintf(stdout
, "%s\n",
1624 gettext("\tv\t\tshadow volume (reference name)"));
1625 (void) fprintf(stdout
, "%s\n",
1626 gettext("\to\t\toverflow volume"));
1627 (void) fprintf(stdout
, "%s\n",
1628 gettext("\tb\t\tbitmap volume"));
1630 (void) fprintf(stdout
, "%s\n",
1631 gettext("\tf\t\tconfiguration file name"));
1633 (void) fprintf(stdout
, "%s\n",
1634 gettext("\td\t\tdelay tick interval"));
1635 (void) fprintf(stdout
, "%s\n",
1636 gettext("\tu\t\tunit size"));
1637 (void) fprintf(stdout
, "%s\n",
1638 gettext("\tg\t\tgroup name"));
1640 /* assume we came here because user request help text */
1647 static char yeschr
[MAX_LINE_SIZE
+ 2];
1648 static char nochr
[MAX_LINE_SIZE
+ 2];
1654 char ans
[MAX_LINE_SIZE
+ 1];
1656 for (i
= 0; /*CSTYLED*/; i
++) {
1658 if (b
== '\n' || b
== '\0' || b
== EOF
) {
1659 if (i
< MAX_LINE_SIZE
)
1663 if (i
< MAX_LINE_SIZE
)
1666 if (i
>= MAX_LINE_SIZE
) {
1668 ans
[MAX_LINE_SIZE
] = 0;
1670 if ((i
== 0) || (strncmp(yeschr
, ans
, i
))) {
1671 if (strncmp(nochr
, ans
, i
) == 0)
1673 else if (strncmp(yeschr
, ans
, i
) == 0)
1676 (void) fprintf(stderr
, "%s %s/%s\n",
1677 gettext("You have to respond with"),
1686 convert_int(char *str
)
1691 buf
= (char *)calloc(strlen(str
) + 256, sizeof (char));
1692 rc
= sscanf(str
, "%d%s", &result
, buf
);
1695 (void) sprintf(buf
, gettext("'%s' is not a valid number"), str
);
1696 /* dsw_error calls exit which frees 'buf' */
1698 dsw_error(buf
, NULL
);
1706 check_action(char *will_happen
)
1710 if (nflg
|| !isatty(fileno(stdin
)))
1712 (void) strncpy(yeschr
, nl_langinfo(YESSTR
), MAX_LINE_SIZE
+ 1);
1713 (void) strncpy(nochr
, nl_langinfo(NOSTR
), MAX_LINE_SIZE
+ 1);
1717 (void) printf("%s %s/%s ", will_happen
, yeschr
, nochr
);
1719 if (answer
== 1 || answer
== 0)
1727 enum child_event
{Status
, CopyStart
};
1730 * Wait for child process to get to some state, where some state may be:
1732 * Status Set up the shadow enough so that it responds
1733 * to status requests.
1734 * CopyStart Start copy/update operations.
1738 child_wait(pid_t child
, enum child_event event
, char *volume
)
1743 (void) strlcpy(args
.shadow_vol
, volume
, DSW_NAMELEN
);
1745 for (; dead_child
!= child
; (void) sleep(1)) {
1747 /* poll shadow group with a status ioctl() */
1748 args
.status
= spcs_s_ucreate();
1750 rc
= do_ioctl(dsw_fd
, DSWIOC_STAT
, &args
);
1752 spcs_s_ufree(&args
.status
);
1754 if (event
== Status
) {
1755 /* keep polling while we fail with DSW_ENOTFOUND */
1756 if (rc
!= -1 || errno
!= DSW_ENOTFOUND
)
1759 /* event == CopyStart */
1761 return (1); /* something wrong */
1763 if (args
.stat
& DSW_COPYINGP
)
1764 return (0); /* copying underway */
1768 if (WIFEXITED(dead_stat
))
1769 return (WEXITSTATUS(dead_stat
));
1780 struct mnttab mntref
;
1781 struct mnttab mntent
;
1782 char target
[DSW_NAMELEN
];
1786 for (s
= target
; i
< DSW_NAMELEN
&& (*s
= *t
++); i
++) {
1787 if (*s
== 'r' && rdsk
== 0)
1794 mntref
.mnt_special
= target
;
1795 mntref
.mnt_mountp
= NULL
;
1796 mntref
.mnt_fstype
= NULL
;
1797 mntref
.mnt_mntopts
= NULL
;
1798 mntref
.mnt_time
= NULL
;
1800 if ((mntfp
= fopen("/etc/mnttab", "r")) == NULL
) {
1801 dsw_error(gettext("Can not check volume against mount table"),
1804 if (getmntany(mntfp
, &mntent
, &mntref
) != -1) {
1805 /* found something before EOF */
1806 (void) fclose(mntfp
);
1809 (void) fclose(mntfp
);
1814 enable(char *master_volume
, char *shadow_volume
,
1815 char *bitmap_volume
, char *copy_type
)
1822 spcs_s_info_t
*sp_info
;
1823 struct stat mstat
, sstat
, bstat
;
1824 char mst_dg
[DSW_NAMELEN
] = {0};
1825 char shd_dg
[DSW_NAMELEN
] = {0};
1826 char bmp_dg
[DSW_NAMELEN
] = {0};
1831 bzero(&parms
, sizeof (dsw_config_t
));
1833 if (strcmp(copy_type
, "independent") == 0 ||
1834 strcmp(copy_type
, gettext("independent")) == 0)
1835 parms
.flag
= DSW_GOLDEN
;
1836 else if (strcmp(copy_type
, "dependent") == 0 ||
1837 strcmp(copy_type
, gettext("dependent")) == 0)
1840 dsw_error(gettext("don't understand shadow type"), NULL
);
1842 /* validate volume names */
1843 if (perform_autosv()) {
1844 if (cfg_load_svols(cfg
) < 0 || cfg_load_dsvols(cfg
) < 0 ||
1845 cfg_load_shadows(cfg
) < 0) {
1846 dsw_error(gettext("Unable to parse config file"), NULL
);
1849 reload_vols
= LD_SVOLS
| LD_DSVOLS
| LD_SHADOWS
| LD_II
;
1851 /* see if it's been used before under a different name */
1852 conform_name(&master_volume
);
1853 conform_name(&shadow_volume
);
1854 rc
= cfg_get_canonical_name(cfg
, bitmap_volume
, &altname
);
1856 dsw_error(gettext("Unable to parse config file"), NULL
);
1860 dsw_error(gettext("Bitmap in use"), NULL
);
1865 * If not local, determine disk group names for volumes in II set
1867 switch (check_cluster()) {
1870 * Check if none or all volumes are in a disk group
1873 if (check_diskgroup(master_volume
, mst_dg
)) rc
++;
1874 if (check_diskgroup(shadow_volume
, shd_dg
)) rc
++;
1875 if (check_diskgroup(bitmap_volume
, bmp_dg
)) rc
++;
1876 if ((rc
!= 0) && (rc
!= 3))
1878 "Not all Point-in-Time Copy volumes are "
1879 "in a disk group"), NULL
);
1882 * If volumes are not in a disk group, but are in a
1883 * cluster, then "-C <tag>", must be set
1885 if (rc
== 0 && cfg_cluster_tag
== NULL
)
1887 "Point-in-Time Copy volumes, that are not "
1888 "in a device group which has been "
1889 "registered with SunCluster, "
1890 "require usage of \"-C\""), NULL
);
1893 * the same disk group
1894 * If -n, plus mst_dg==bmp_dg, then allow E/I/J in SunCluster
1896 if ((strcmp(mst_dg
, bmp_dg
)) ||
1897 (strcmp(mst_dg
, shd_dg
) && (!nflg
)))
1899 "Volumes are not in same disk group"), NULL
);
1902 * Can never enable the same shadow twice, regardless of
1903 * exportable shadow device group movement
1905 if (find_shadow_line(shadow_volume
))
1907 "Shadow volume is already configured"), NULL
);
1910 * Groups cannot span multiple clusters
1912 if (group_name
&& perform_autosv()) {
1913 gdata
= (grptag_t
*)nsc_lookup(volhash
, group_name
);
1915 strncmp(gdata
->ctag
, mst_dg
, DSW_NAMELEN
) != 0) {
1917 dsw_error(gettext("Group contains sets not "
1918 "in the same cluster resource"), NULL
);
1923 * Check cluster tag and bitmap disk group
1924 * set latter if different
1926 if (check_resource_group(bitmap_volume
)) {
1928 * Unload and reload in the event cluster tag has
1931 if (perform_autosv()) {
1933 cfg_unload_shadows();
1934 cfg_unload_dsvols();
1936 if (cfg_load_svols(cfg
) < 0 ||
1937 cfg_load_dsvols(cfg
) < 0 ||
1938 cfg_load_shadows(cfg
) < 0) {
1940 "Unable to parse config "
1947 * Copy cluster name into config
1949 (void) strncpy(parms
.cluster_tag
, cfg_cluster_tag
, DSW_NAMELEN
);
1952 case II_CLUSTER_LCL
:
1953 /* ensure that the -C local won't interfere with the set */
1954 if (group_name
&& perform_autosv()) {
1955 gdata
= (grptag_t
*)nsc_lookup(volhash
, group_name
);
1957 if (strlen(gdata
->ctag
) != 0) {
1959 dsw_error(gettext("Unable to put set "
1960 "into -C local and specified "
1969 * If we've got a group name, add it into the config
1972 (void) strncpy(parms
.group_name
, group_name
, DSW_NAMELEN
);
1976 * Determine accessability of volumes
1978 if (stat(master_volume
, &mstat
) != 0)
1980 "Unable to access master volume"), NULL
);
1981 if (!S_ISCHR(mstat
.st_mode
))
1983 "Master volume is not a character device"), NULL
);
1984 /* check the shadow_vol hasn't be used as SNDR secondary vol */
1985 check_iishadow(shadow_volume
);
1986 if (stat(shadow_volume
, &sstat
) != 0)
1988 "Unable to access shadow volume"), NULL
);
1989 if (!S_ISCHR(sstat
.st_mode
))
1991 "Shadow volume is not a character device"), NULL
);
1992 if (mounted(shadow_volume
)) {
1995 "Shadow volume is mounted, unmount it first"), NULL
);
1997 if (mstat
.st_rdev
== sstat
.st_rdev
) {
2000 "Master and shadow are the same device"), NULL
);
2002 if (stat(bitmap_volume
, &bstat
) != 0) {
2003 dsw_error(gettext("Unable to access bitmap"), NULL
);
2005 if (!S_ISCHR(bstat
.st_mode
))
2007 "Bitmap volume is not a character device"), NULL
);
2008 if (S_ISCHR(bstat
.st_mode
)) {
2009 if (mstat
.st_rdev
== bstat
.st_rdev
) {
2012 "Master and bitmap are the same device"), NULL
);
2013 } else if (sstat
.st_rdev
== bstat
.st_rdev
) {
2016 "Shadow and bitmap are the same device"), NULL
);
2020 (void) strncpy(parms
.master_vol
, master_volume
, DSW_NAMELEN
);
2021 (void) strncpy(parms
.shadow_vol
, shadow_volume
, DSW_NAMELEN
);
2022 (void) strncpy(parms
.bitmap_vol
, bitmap_volume
, DSW_NAMELEN
);
2024 parms
.status
= spcs_s_ucreate();
2027 * Check that none of the member volumes forms part of another
2028 * InstantImage group.
2030 * -- this check has been removed; it is done in the kernel instead
2035 * Check against overflow volumes
2037 for (p
= get_overflow_list(); *p
!= NULL
; p
+= DSW_NAMELEN
) {
2038 if (strncmp(master_volume
, p
, DSW_NAMELEN
) == 0)
2040 "Master volume is already an overflow volume"),
2042 else if (strncmp(shadow_volume
, p
, DSW_NAMELEN
) == 0)
2044 "Shadow volume is already an overflow volume"),
2046 else if (strncmp(bitmap_volume
, p
, DSW_NAMELEN
) == 0)
2048 "Bitmap volume is already an overflow volume"),
2053 * Make sure that the shadow volume is not already configured
2055 if (find_shadow_config(shadow_volume
, NULL
, &temp
))
2057 "Shadow volume is already configured"), NULL
);
2058 if (perform_autosv()) {
2060 * parse the dsvol entries to see if we need to place
2061 * the master or shadow under SV control
2063 if (nsc_lookup(volhash
, master_volume
) == NULL
) {
2064 if (cfg_vol_enable(cfg
, master_volume
, cfg_cluster_tag
,
2067 gettext("Cannot enable master volume"),
2074 if (nsc_lookup(volhash
, shadow_volume
) == NULL
) {
2076 cfg_resource(cfg
, shd_dg
);
2077 rc
= cfg_vol_enable(cfg
, shadow_volume
,
2079 cfg_resource(cfg
, cfg_cluster_tag
);
2081 rc
= cfg_vol_enable(cfg
, shadow_volume
,
2082 cfg_cluster_tag
, "ii");
2086 if (cfg_vol_disable(cfg
,
2087 master_volume
, cfg_cluster_tag
,
2090 "SV disable of master "
2095 gettext("Cannot enable shadow volume"),
2100 cfg_unload_shadows();
2101 cfg_unload_dsvols();
2106 add_cfg_entry(&parms
);
2110 (void) sigset(SIGCHLD
, sigchild
);
2111 switch (child
= fork()) {
2114 dsw_error(gettext("Unable to fork"), NULL
);
2118 rc
= do_ioctl(dsw_fd
, DSWIOC_ENABLE
, &parms
);
2119 if (rc
== -1 && errno
!= DSW_EABORTED
&& errno
!= DSW_EIO
) {
2121 * Failed to enable shadow group, log problem and remove
2122 * the shadow group from the config file.
2124 spcs_log("ii", &parms
.status
,
2125 gettext("Enable failed %s %s %s (%s)"),
2126 master_volume
, shadow_volume
, bitmap_volume
,
2127 parms
.flag
& DSW_GOLDEN
?
2128 "independent" : "dependent");
2130 if (!ii_lock(cfg
, CFG_WRLOCK
) ||
2131 !find_shadow_config(shadow_volume
, NULL
, &temp
)) {
2133 "Enable failed, can't tidy up cfg"),
2137 remove_iiset(setnumber
, shadow_volume
, 0);
2138 dsw_error(gettext("Enable failed"), &parms
.status
);
2142 sp_info
= &parms
.status
;
2145 spcs_log("ii", sp_info
, gettext("Enabled %s %s %s (%s)"),
2146 master_volume
, shadow_volume
, bitmap_volume
,
2147 parms
.flag
& DSW_GOLDEN
? "independent" : "dependent");
2148 spcs_s_ufree(&parms
.status
);
2152 exit(child_wait(child
, Status
, shadow_volume
));
2164 pid_t child
= (pid_t
)0;
2165 enum copy_wait wait_action
;
2166 spcs_s_info_t
*stat
;
2167 dsw_stat_t prev_stat
;
2169 static int unlocked
= 0;
2171 char key
[CFG_MAX_KEY
];
2172 char optval
[CFG_MAX_BUF
];
2175 wait_action
= WaitForStart
;
2177 if (unlocked
&& !ii_lock(cfg
, CFG_RDLOCK
)) {
2178 dsw_error(gettext("Unable to set locking on the configuration"),
2182 if (!find_shadow_config(volume
, &parms
, &args
))
2183 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2190 spcs_log("ii", NULL
, gettext("Start reset %s"), volume
);
2191 (void) strlcpy(prev_stat
.shadow_vol
, volume
, DSW_NAMELEN
);
2192 prev_stat
.status
= spcs_s_ucreate();
2193 if (do_ioctl(dsw_fd
, DSWIOC_STAT
, &prev_stat
) == -1) {
2194 /* set is suspended, so we do the enable processing instead */
2197 /* first check to see whether the set was offline */
2198 (void) snprintf(key
, CFG_MAX_KEY
, "ii.set%d.options",
2200 if (!ii_lock(cfg
, CFG_RDLOCK
)) {
2201 dsw_error(gettext("Unable to set locking on the "
2202 "configuration"), NULL
);
2206 if (cfg_get_single_option(cfg
, CFG_SEC_CONF
, key
,
2207 NSKERN_II_BMP_OPTION
, optval
, CFG_MAX_BUF
) < 0) {
2208 dsw_error(gettext("unable to read config file"), NULL
);
2213 (void) sscanf(optval
, "%x", &flags
);
2214 if ((flags
& DSW_OFFLINE
) == 0) {
2215 /* set wasn't offline - don't reset */
2216 dsw_error(gettext("Set not offline, will not reset"),
2219 parms
.status
= spcs_s_ucreate();
2220 stat
= &parms
.status
;
2221 stat_flags
= DSW_BMPOFFLINE
;
2223 args
.status
= spcs_s_ucreate();
2224 stat
= &args
.status
;
2225 stat_flags
= prev_stat
.stat
;
2227 spcs_s_ufree(&prev_stat
.status
);
2229 if (wait_action
== WaitForStart
)
2230 (void) sigset(SIGCHLD
, sigchild
);
2232 switch (child
= fork()) {
2235 dsw_error(gettext("Unable to fork"), NULL
);
2240 rc
= do_ioctl(dsw_fd
, DSWIOC_ENABLE
, &parms
);
2242 rc
= do_ioctl(dsw_fd
, DSWIOC_RESET
, &args
);
2244 if (rc
== -1 && errno
!= DSW_EABORTED
&& errno
!= DSW_EIO
) {
2245 spcs_log("ii", stat
, gettext("Fail reset %s"), volume
);
2246 dsw_error(gettext("Reset shadow failed"), stat
);
2248 /* last_overflow is set during find_shadow_config */
2249 if (strlen(last_overflow
) > 0 &&
2250 (stat_flags
& (DSW_SHDOFFLINE
| DSW_BMPOFFLINE
)) != 0) {
2252 (void) strncpy(parms
.bitmap_vol
, last_overflow
,
2256 spcs_log("ii", stat
, gettext("Finish reset %s"), volume
);
2262 if (wait_action
== WaitForStart
) {
2263 rc
= child_wait(child
, CopyStart
, args
.shadow_vol
);
2264 } else { /* wait_action == WaitForEnd */
2266 (void) wait(&wait_loc
);
2267 if (WIFEXITED(wait_loc
) && (WEXITSTATUS(wait_loc
) == 0))
2274 /* if successful, remove flags entry from options field */
2276 if (!ii_lock(cfg
, CFG_WRLOCK
)) {
2277 dsw_error(gettext("Unable to set locking on the "
2278 "configuration"), NULL
);
2281 if (!find_shadow_config(volume
, &parms
, &args
)) {
2282 dsw_error(gettext("Volume is not in a Point-in-Time "
2283 "Copy group"), NULL
);
2285 (void) snprintf(key
, CFG_MAX_KEY
, "ii.set%d.options",
2287 if (cfg_del_option(cfg
, CFG_SEC_CONF
, key
, NSKERN_II_BMP_OPTION
)
2289 dsw_error(gettext("Update of config failed"), NULL
);
2291 (void) cfg_commit(cfg
);
2300 overflow(char *volume
)
2304 spcs_s_info_t
*stat
;
2306 check_action(gettext("Initialize this overflow volume?"));
2307 if (find_matching_cf_line(volume
, NULL
, &args
))
2308 dsw_error(gettext("Volume is part of a Point-in-Time Copy "
2310 args
.status
= spcs_s_ucreate();
2311 (void) strncpy(args
.shadow_vol
, volume
, DSW_NAMELEN
);
2312 rc
= do_ioctl(dsw_fd
, DSWIOC_OCREAT
, &args
);
2314 spcs_log("ii", &args
.status
,
2315 gettext("Create overflow failed %s"), volume
);
2316 dsw_error(gettext("Create overflow failed"), &args
.status
);
2319 stat
= &args
.status
;
2322 spcs_log("ii", stat
, gettext("Create overflow succeeded %s"), volume
);
2323 spcs_s_ufree(&args
.status
);
2329 bitmap_op(char *master_volume
, int print_bitmap
, int bitmap_percent
, int used
,
2332 unsigned char *bitmap
;
2337 unsigned long percent
;
2339 bitmap
= allocate_bitmap(master_volume
);
2343 if (bitmap_percent
) {
2344 /* count the number of bits set in bitmap */
2345 for (i
= n
= 0; i
< bm_size
; i
++)
2346 for (j
= (unsigned)bitmap
[i
]; j
; j
&= j
-1)
2349 (void) printf(gettext("Chunks in map: %d used: %d\n"),
2351 if (bm_actual
< 100) {
2354 percent
= (n
* 100) / bm_actual
;
2356 (void) printf(gettext("Percent of bitmap set: %u\n"), percent
);
2357 percent
= percent
/100;
2358 /* distinguish between 0.0000% and 0.n% of bitmap set */
2360 (void) printf("\t(%s)\n", n
> 0 ?
2361 gettext("bitmap dirty") : gettext("bitmap clean"));
2365 name
= strrchr(master_volume
, '/');
2367 name
= master_volume
;
2369 x
= (int)ceil(sqrt((double)i
));
2370 x
+= (8 - (x
% 8)); /* round up to nearest multiple of 8 */
2374 (void) printf("#define bm%s_width %d\n#define bm%s_height %d\n",
2376 (void) printf("#define bm%s_x_hot 0\n#define bm%s_y_hot 0\n",
2378 (void) printf("static char bm%s_bits[] = {\n", name
);
2379 for (i
= 0; i
< bm_size
; i
++) {
2381 (void) printf("\n");
2382 (void) printf("0x%02x, ", bitmap
[i
]);
2385 for (; i
< y
; i
++) {
2387 (void) printf("\n");
2388 (void) printf("0x00, ");
2390 (void) printf("\n};\n");
2393 free_bitmap(bitmap
);
2397 validate_group_names(char **vol_list
, char *group
)
2401 dsw_aioctl_t
*group_list
;
2404 if (group
== NULL
|| *group
== NULL
) {
2405 /* no group set, just count volume list */
2406 for (i
= 0; *vol_list
++ != NULL
; i
++)
2411 if ((count
= do_ioctl(dsw_fd
, DSWIOC_LISTLEN
, NULL
)) < 0)
2412 dsw_error("DSWIOC_LISTLEN", NULL
);
2414 group_list
= malloc(sizeof (dsw_aioctl_t
) + count
* DSW_NAMELEN
);
2415 if (group_list
== NULL
)
2416 dsw_error(gettext("Failed to allocate memory"), NULL
);
2418 bzero(group_list
, sizeof (dsw_aioctl_t
) + count
* DSW_NAMELEN
);
2419 group_list
->count
= count
;
2420 group_list
->flags
= 0;
2421 group_list
->status
= spcs_s_ucreate();
2422 (void) strncpy(group_list
->shadow_vol
, group
, DSW_NAMELEN
);
2424 rc
= do_ioctl(dsw_fd
, DSWIOC_GLIST
, group_list
);
2426 dsw_error(gettext("Group list access failure"),
2427 &group_list
->status
);
2429 group_list
->shadow_vol
[DSW_NAMELEN
* group_list
->count
] = '\0';
2431 /* create hash and enter all volumes into it */
2432 if (hcreate(group_list
->count
) == 0)
2433 dsw_error(gettext("Failed to allocate memory"), NULL
);
2434 ptr
= group_list
->shadow_vol
;
2435 count
= group_list
->count
;
2438 ptr
[ DSW_NAMELEN
- 1 ] = '\0';
2440 item
.data
= (void *) 0;
2441 (void) hsearch(item
, ENTER
);
2446 /* now compare the volume list with the hash */
2447 for (i
= 0; vol_list
[ i
]; i
++) {
2448 item
.key
= vol_list
[ i
];
2449 found
= hsearch(item
, FIND
);
2451 dsw_error(gettext("Group config does not match kernel"),
2453 if (found
->data
!= (void *) 0)
2454 dsw_error(gettext("Duplicate volume specified"), NULL
);
2455 found
->data
= (void *) 1;
2458 dsw_error(gettext("Group config does not match kernel"), NULL
);
2460 /* everything checks out */
2468 do_acopy(char **vol_list
, enum copy_update update_mode
,
2469 enum copy_direction direction
)
2471 dsw_aioctl_t
*acopy_args
;
2472 dsw_ioctl_t copy_args
;
2483 n_vols
= validate_group_names(vol_list
, group_name
);
2485 acopy_args
= calloc(sizeof (dsw_aioctl_t
) + n_vols
* DSW_NAMELEN
, 1);
2486 if (acopy_args
== NULL
)
2487 dsw_error(gettext("Too many volumes given for update"), NULL
);
2489 acopy_args
->count
= n_vols
;
2491 acopy_args
->flags
= 0;
2493 if (update_mode
== Update
)
2494 acopy_args
->flags
|= CV_BMP_ONLY
;
2495 if (direction
== ToMaster
)
2496 acopy_args
->flags
|= CV_SHD2MST
;
2498 acopy_args
->flags
|= CV_LOCK_PID
;
2500 ppid
= getenv("IIADM_PPID");
2502 acopy_args
->pid
= atoi(ppid
);
2503 (void) fprintf(stderr
, "(using %s for ppid)\n", ppid
);
2505 acopy_args
->pid
= getppid();
2508 acopy_args
->pid
= getppid();
2512 for (i
= 0; i
< n_vols
; i
++) {
2513 if (!find_shadow_config(vol_list
[i
], &parms
, ©_args
))
2514 dsw_error(gettext("Volume is not in a Point-in-Time "
2516 if (direction
== ToMaster
) {
2517 t
= parms
.master_vol
;
2519 t
= parms
.shadow_vol
;
2524 dsw_error(gettext("Target of copy/update is mounted, "
2525 "unmount it first"), NULL
);
2528 (void) strlcpy(stat_s
.shadow_vol
, parms
.shadow_vol
,
2530 stat_s
.status
= spcs_s_ucreate();
2531 rc
= do_ioctl(dsw_fd
, DSWIOC_STAT
, &stat_s
);
2532 spcs_s_ufree(&stat_s
.status
);
2535 gettext("Shadow group %s is suspended"),
2537 dsw_error(buf
, NULL
);
2540 if (stat_s
.stat
& DSW_COPYINGP
) {
2541 (void) fprintf(stderr
, "%s: %s\n", cmdnam
,
2542 gettext("Copy already in progress"));
2546 acopy_args
->status
= spcs_s_ucreate();
2547 for (i
= 0; i
< n_vols
; i
++) {
2548 spcs_log("ii", NULL
, gettext("Atomic %s %s %s"),
2549 update_mode
== Update
? gettext("update") : gettext("copy"),
2551 direction
== ToMaster
? gettext("from shadow") :
2552 gettext("to shadow"));
2554 if (group_name
== NULL
|| *group_name
== NULL
) {
2555 sp
= acopy_args
->shadow_vol
;
2556 for (i
= 0; i
< n_vols
; i
++, sp
+= DSW_NAMELEN
)
2557 (void) strncpy(sp
, vol_list
[i
], DSW_NAMELEN
);
2559 (void) strncpy(acopy_args
->shadow_vol
, group_name
, DSW_NAMELEN
);
2560 acopy_args
->flags
|= CV_IS_GROUP
;
2562 rc
= do_ioctl(dsw_fd
, DSWIOC_ACOPY
, acopy_args
);
2564 i
= acopy_args
->count
;
2565 if (i
< 0 || i
>= n_vols
) {
2566 spcs_log("ii", NULL
, gettext("Atomic update failed"));
2567 (void) sprintf(buf
, gettext("Update failed"));
2569 spcs_log("ii", NULL
,
2570 gettext("Atomic update of %s failed"),
2571 vol_list
[acopy_args
->count
]);
2572 (void) sprintf(buf
, gettext("Update of %s failed"),
2573 vol_list
[acopy_args
->count
]);
2575 dsw_error(buf
, &(acopy_args
->status
));
2581 do_copy(char **vol_list
, enum copy_update update_mode
,
2582 enum copy_direction direction
, enum copy_wait wait_action
)
2584 dsw_ioctl_t copy_args
;
2591 pid_t child
= (pid_t
)0;
2594 if (vol_list
[0] && vol_list
[1])
2595 return (do_acopy(vol_list
, update_mode
, direction
));
2597 volume
= vol_list
[0];
2598 if (!find_shadow_config(volume
, &parms
, ©_args
))
2599 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2604 copy_args
.flags
= 0;
2606 if (update_mode
== Update
)
2607 copy_args
.flags
|= CV_BMP_ONLY
;
2608 if (direction
== ToMaster
) {
2609 copy_args
.flags
|= CV_SHD2MST
;
2610 t
= parms
.master_vol
;
2612 t
= parms
.shadow_vol
;
2615 copy_args
.flags
|= CV_LOCK_PID
;
2617 ppid
= getenv("IIADM_PPID");
2619 copy_args
.pid
= atoi(ppid
);
2620 (void) fprintf(stderr
, "(using %s for ppid)\n", ppid
);
2622 copy_args
.pid
= getppid();
2625 copy_args
.pid
= getppid();
2631 dsw_error(gettext("Target of copy/update is mounted, "
2632 "unmount it first"), NULL
);
2635 (void) strlcpy(stat_s
.shadow_vol
, copy_args
.shadow_vol
, DSW_NAMELEN
);
2636 stat_s
.status
= spcs_s_ucreate();
2637 rc
= do_ioctl(dsw_fd
, DSWIOC_STAT
, &stat_s
);
2638 spcs_s_ufree(&stat_s
.status
);
2640 dsw_error(gettext("Shadow group suspended"), NULL
);
2642 if (stat_s
.stat
& DSW_COPYINGP
) {
2643 (void) fprintf(stderr
, "%s: %s\n", cmdnam
,
2644 gettext("Copy already in progress"));
2648 copy_args
.status
= spcs_s_ucreate();
2649 spcs_log("ii", NULL
, gettext("Start %s %s %s"),
2650 update_mode
== Update
? gettext("update") : gettext("copy"),
2652 direction
== ToMaster
? gettext("from shadow") :
2653 gettext("to shadow"));
2655 if (wait_action
== WaitForStart
)
2656 (void) sigset(SIGCHLD
, sigchild
);
2657 switch (child
= fork()) {
2660 dsw_error(gettext("Unable to fork"),
2665 rc
= do_ioctl(dsw_fd
, DSWIOC_COPY
, ©_args
);
2667 spcs_log("ii", ©_args
.status
,
2668 gettext("Fail %s %s %s"),
2669 update_mode
== Update
?
2670 gettext("update") : gettext("copy"),
2672 direction
== ToMaster
?
2673 gettext("from shadow") : gettext("to shadow"));
2674 dsw_error(gettext("Copy failed"), ©_args
.status
);
2676 spcs_s_ufree(©_args
.status
);
2677 spcs_log("ii", NULL
, gettext("Finish %s %s %s"),
2678 update_mode
== Update
? gettext("update") : gettext("copy"),
2680 direction
== ToMaster
? gettext("from shadow") :
2681 gettext("to shadow"));
2686 if (wait_action
== WaitForStart
) {
2687 rc
= child_wait(child
, CopyStart
, copy_args
.shadow_vol
);
2688 } else { /* wait_action == WaitForEnd */
2690 (void) wait(&wait_loc
);
2691 if (WIFEXITED(wait_loc
) && (WEXITSTATUS(wait_loc
) == 0))
2702 print_status(dsw_config_t
*conf
, int in_config
)
2706 static int need_sep
= 0;
2710 (void) printf("--------------------------------------"
2711 "----------------------------------------\n");
2712 (void) strlcpy(args
.shadow_vol
, conf
->shadow_vol
, DSW_NAMELEN
);
2714 (void) printf("%s: %s\n",
2715 conf
->master_vol
, gettext("(master volume)"));
2716 (void) printf("%s: %s\n",
2717 conf
->shadow_vol
, gettext("(shadow volume)"));
2718 (void) printf("%s: %s\n",
2719 conf
->bitmap_vol
, gettext("(bitmap volume)"));
2723 * Do special checking on the status of this volume in a Sun Cluster
2725 if (check_cluster() == II_CLUSTER
) {
2726 char dgname
[CFG_MAX_BUF
], *other_node
;
2728 if (cfg_dgname(conf
->bitmap_vol
, dgname
, sizeof (dgname
))) {
2729 if (strlen(dgname
)) {
2730 int rc
= cfg_dgname_islocal(dgname
,
2734 (void) printf(gettext(
2735 "Suspended on this node, "
2736 "not active elsewhere\n"));
2738 } else if (rc
== 0) {
2739 (void) printf(gettext(
2740 "Suspended on this node, "
2741 "active on %s\n"), other_node
);
2748 args
.status
= spcs_s_ucreate();
2749 if (do_ioctl(dsw_fd
, DSWIOC_STAT
, &args
) == -1) {
2751 /* Handle Not found or not in config */
2752 if (errno
!= DSW_ENOTFOUND
|| !in_config
)
2753 dsw_error(gettext("Stat failed"), &args
.status
);
2756 (void) printf(gettext("Suspended.\n"));
2760 if (args
.overflow_vol
[0] != '\0')
2761 (void) printf("%s: %s\n", args
.overflow_vol
,
2762 gettext("(overflow volume)"));
2764 if (conf
->group_name
[0] != '\0')
2765 (void) printf(gettext("Group name: %s\n"),
2768 if (conf
->cluster_tag
[0] != '\0')
2769 (void) printf(gettext("Cluster tag: %s\n"),
2772 stat_flags
= args
.stat
;
2773 spcs_s_ufree(&args
.status
);
2774 if (stat_flags
& DSW_GOLDEN
)
2775 (void) printf(gettext("Independent copy"));
2777 (void) printf(gettext("Dependent copy"));
2779 if (stat_flags
& DSW_TREEMAP
)
2780 (void) printf(gettext(", compacted shadow space"));
2782 if (stat_flags
& DSW_COPYINGP
)
2783 (void) printf(gettext(", copy in progress"));
2784 else if (stat_flags
& DSW_COPYING
)
2785 (void) printf(gettext(", copy not active"));
2787 if (stat_flags
& DSW_COPYINGM
)
2788 (void) printf(gettext(", copying master to shadow"));
2790 if (stat_flags
& DSW_COPYINGS
)
2791 (void) printf(gettext(", copying shadow to master"));
2793 if (stat_flags
& DSW_COPYINGX
)
2794 (void) printf(gettext(", abort of copy requested"));
2796 if (stat_flags
& DSW_MSTOFFLINE
)
2797 (void) printf(gettext(", master volume offline"));
2799 if (stat_flags
& DSW_SHDOFFLINE
)
2800 (void) printf(gettext(", shadow volume offline"));
2802 if (stat_flags
& DSW_BMPOFFLINE
)
2803 (void) printf(gettext(", bitmap volume offline"));
2805 if (stat_flags
& DSW_OVROFFLINE
)
2806 (void) printf(gettext(", overflow volume offline"));
2808 if (stat_flags
& DSW_SHDEXPORT
)
2809 (void) printf(gettext(", shadow volume exported"));
2811 if (stat_flags
& DSW_SHDIMPORT
)
2812 (void) printf(gettext(", shadow volume imported"));
2814 if (stat_flags
& DSW_OVERFLOW
)
2815 (void) printf(gettext(", out of space"));
2817 if (stat_flags
& DSW_VOVERFLOW
)
2818 (void) printf(gettext(", spilled into overflow volume"));
2819 (void) printf("\n");
2821 tmp_time
= args
.mtime
;
2823 (void) printf("%s %s", gettext("Latest modified time:"),
2826 (void) printf("%s\n", gettext("Latest modified time: unknown"));
2828 (void) printf("%s %8llu\n", gettext("Volume size:"), args
.size
);
2829 if (args
.shdsize
!= 0) {
2830 (void) printf("%s %lld %s %lld\n",
2831 gettext("Shadow chunks total:"), args
.shdsize
,
2832 gettext("Shadow chunks used:"), args
.shdused
);
2834 bitmap_op(args
.shadow_vol
, 0, 1, 0, 0);
2838 abort_copy(char *volume
)
2842 if (!find_shadow_config(volume
, NULL
, &args
))
2843 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2845 args
.status
= spcs_s_ucreate();
2846 if (do_ioctl(dsw_fd
, DSWIOC_ABORT
, &args
) == -1)
2847 dsw_error(gettext("Abort failed"), &args
.status
);
2848 spcs_log("ii", NULL
, gettext("Abort %s"), args
.shadow_vol
);
2849 spcs_s_ufree(&args
.status
);
2858 args
.status
= spcs_s_ucreate();
2859 if (do_ioctl(dsw_fd
, DSWIOC_VERSION
, &args
) == -1)
2860 dsw_error(gettext("Version failed"), &args
.status
);
2861 spcs_s_ufree(&args
.status
);
2863 (void) printf(gettext("Point in Time Copy version %d.%d.%d.%d\n"),
2864 args
.major
, args
.minor
, args
.micro
, args
.baseline
);
2867 (void) printf(gettext("Point in Time Copy version %d.%d.%d\n"),
2868 args
.major
, args
.minor
, args
.micro
);
2870 (void) printf(gettext("Point in Time Copy version %d.%d\n"),
2871 args
.major
, args
.minor
);
2885 if ((i
= do_ioctl(dsw_fd
, DSWIOC_LISTLEN
, &args
)) == -1)
2886 dsw_error("DSWIOC_LISTLEN", NULL
);
2888 args
.status
= spcs_s_ucreate();
2890 args
.list_size
= i
+ 4;
2891 lp
= args
.list
= (dsw_config_t
*)
2892 malloc(args
.list_size
* sizeof (dsw_config_t
));
2894 if (args
.list
== NULL
)
2895 dsw_error(gettext("Failed to allocate memory"), NULL
);
2896 if (do_ioctl(dsw_fd
, DSWIOC_LIST
, &args
) == -1)
2897 dsw_error(gettext("List failed"), &args
.status
);
2898 spcs_s_ufree(&args
.status
);
2900 /* make a hashtable */
2901 if (args
.list_used
> 0) {
2902 if (hcreate(args
.list_used
) == 0) {
2903 dsw_error(gettext("Failed to allocate memory"), NULL
);
2908 /* populate the hashtable */
2909 for (i
= 0; i
< args
.list_used
; i
++, lp
++) {
2910 item
.key
= lp
->shadow_vol
;
2911 item
.data
= (char *)lp
;
2912 if (hsearch(item
, ENTER
) == NULL
) {
2913 dsw_error(gettext("Failed to allocate memory"), NULL
);
2918 /* perform action for each line of the stored config file */
2919 for (set
= 1; get_dsw_config(set
, &parms
) == 0; set
++) {
2921 /* Are there any II sets configured on this node? */
2922 if (args
.list_used
> 0) {
2923 item
.key
= parms
.shadow_vol
;
2925 /* Is this volume configured on this node? */
2926 if (ip
= hsearch(item
, FIND
)) {
2928 /* Handle Imported Shadows */
2929 /* LINTED alignment of cast ok */
2930 lp
= (dsw_config_t
*)ip
->data
;
2931 if (strcmp(parms
.master_vol
,
2932 II_IMPORTED_SHADOW
))
2933 found
= !(lp
->flag
& DSW_SHDIMPORT
);
2935 found
= (lp
->flag
& DSW_SHDIMPORT
);
2943 if ((cfg_cluster_tag
) &&
2944 strcmp(cfg_cluster_tag
, parms
.cluster_tag
))
2947 if ((group_name
) && strcmp(group_name
, parms
.group_name
))
2950 (void) printf("%s %.*s %.*s %.*s%s\n",
2951 (parms
.flag
& DSW_GOLDEN
) ? "ind" : "dep",
2952 DSW_NAMELEN
, parms
.master_vol
,
2953 DSW_NAMELEN
, parms
.shadow_vol
,
2954 DSW_NAMELEN
, parms
.bitmap_vol
,
2955 found
? "" : gettext(" (suspended)"));
2962 wait_for_copy(char *volume
)
2966 static int unlocked
= 0;
2969 if (unlocked
&& !ii_lock(cfg
, CFG_RDLOCK
)) {
2970 dsw_error(gettext("Unable to set locking on the configuration"),
2974 if (!find_shadow_config(volume
, NULL
, &parms
))
2975 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2981 parms
.status
= spcs_s_ucreate();
2984 ppid
= getenv("IIADM_PPID");
2986 parms
.pid
= atoi(ppid
);
2987 (void) fprintf(stderr
, "(using %s for ppid)\n", ppid
);
2989 parms
.pid
= (nflg
) ? -1 : getppid();
2992 parms
.pid
= (nflg
) ? -1 : getppid();
2994 parms
.flags
|= CV_LOCK_PID
;
2997 rc
= do_ioctl(dsw_fd
, DSWIOC_WAIT
, &parms
);
2999 dsw_error(gettext("Wait failed"), &parms
.status
);
3000 spcs_s_ufree(&parms
.status
);
3005 export(char *volume
)
3009 char *old_ctag
, dgname
[DSW_NAMELEN
];
3012 if (!find_shadow_config(volume
, &conf
, &parms
))
3013 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3015 if (mounted(volume
))
3016 dsw_error(gettext("Can't export a mounted volume"), NULL
);
3018 /* If this is an exportable shadow in the cluster, change ctag */
3019 if (strlen(conf
.cluster_tag
) &&
3020 (cfg_dgname(volume
, dgname
, sizeof (dgname
)))) {
3021 old_ctag
= cfg_cluster_tag
;
3022 cfg_resource(cfg
, cfg_cluster_tag
= strdup(dgname
));
3023 } else old_ctag
= NULL
;
3025 if (cfg_load_dsvols(cfg
) < 0 || cfg_load_shadows(cfg
) < 0) {
3026 dsw_error(gettext("Unable to parse config file"), NULL
);
3028 reload_vols
= LD_DSVOLS
| LD_SHADOWS
;
3029 conform_name(&volume
);
3031 spcs_log("ii", NULL
, gettext("Export %s"), volume
);
3032 parms
.status
= spcs_s_ucreate();
3033 rc
= do_ioctl(dsw_fd
, DSWIOC_EXPORT
, &parms
);
3035 dsw_error(gettext("Export failed"), &parms
.status
);
3036 if (perform_autosv()) {
3037 if (cfg_vol_disable(cfg
, volume
, cfg_cluster_tag
, "ii") < 0) {
3038 dsw_error(gettext("SV-disable failed"), NULL
);
3040 (void) cfg_commit(cfg
);
3043 /* restore old cluster tag, if changed */
3044 if (old_ctag
!= NULL
)
3045 cfg_resource(cfg
, cfg_cluster_tag
= old_ctag
);
3047 spcs_s_ufree(&parms
.status
);
3052 detach(char *volume
)
3057 if (!find_shadow_config(volume
, NULL
, &parms
))
3058 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3060 parms
.status
= spcs_s_ucreate();
3061 rc
= do_ioctl(dsw_fd
, DSWIOC_ODETACH
, &parms
);
3063 /* remove overflow from cfg line */
3064 (void) sprintf(key
, "ii.set%d.overflow", setnumber
);
3065 if (cfg_put_cstring(cfg
, key
, "-", 1) < 0) {
3066 perror("cfg_put_cstring");
3068 (void) cfg_commit(cfg
);
3070 spcs_log("ii", NULL
, gettext("Detach of overflow %s failed"),
3072 dsw_error(gettext("Failed to detach overflow volume"),
3079 can_disable(char *vol
)
3084 (void) strlcpy(args
.shadow_vol
, vol
, DSW_NAMELEN
);
3085 args
.status
= spcs_s_ucreate();
3086 if (do_ioctl(dsw_fd
, DSWIOC_STAT
, &args
) != -1 &&
3087 (args
.stat
& DSW_GOLDEN
) == 0) {
3089 dsw_error(gettext("Shadow Volume is currently mounted "
3090 "and dependent on the master volume"), NULL
);
3092 spcs_s_ufree(&args
.status
);
3097 clean_up_after_failed_disable(dsw_ioctl_t
*parms
)
3102 for (p
= group_volumes
; *p
; p
++) {
3103 (void) strlcpy(args
.shadow_vol
, *p
, DSW_NAMELEN
);
3104 args
.status
= spcs_s_ucreate();
3105 if (do_ioctl(dsw_fd
, DSWIOC_STAT
, &args
) == -1) {
3106 /* set was successfully disabled */
3107 if (find_shadow_config(*p
, NULL
, NULL
))
3108 remove_iiset(setnumber
, *p
, 0);
3110 spcs_s_ufree(&args
.status
);
3113 dsw_error(gettext("Some sets in the group failed to disable"),
3118 dsw_group_or_single_disable(int argc
, char *argv
[])
3125 int shd_exported
= 0;
3128 usage(gettext("Incorrect number of arguments"));
3131 if (find_group_members(group_name
) < 1)
3132 dsw_error(gettext("Group does not exist or "
3133 "has no members"), NULL
);
3134 for (p
= group_volumes
; *p
; p
++) {
3138 (void) strncpy(parms
.shadow_vol
, group_name
, DSW_NAMELEN
);
3140 flags
= CV_IS_GROUP
;
3142 if (!find_shadow_config(argv
[1], &conf
, &parms
)) {
3143 dsw_error(gettext("Volume is not in a Point-in-Time "
3144 "Copy group"), NULL
);
3147 can_disable(argv
[1]);
3151 if (group_name
&& !*group_name
) {
3152 /* user typed iiadm -g "" -d */
3153 for (p
= group_volumes
; *p
; p
++) {
3154 parms
.status
= spcs_s_ucreate();
3155 parms
.flags
= flags
;
3156 (void) strncpy(parms
.shadow_vol
, *p
, DSW_NAMELEN
);
3157 rc
= do_ioctl(dsw_fd
, DSWIOC_DISABLE
, &parms
);
3158 if (rc
== -1 && errno
!= DSW_ENOTFOUND
)
3159 dsw_error(gettext("Disable failed"),
3161 if (!find_shadow_config(*p
, NULL
, NULL
))
3162 dsw_error(gettext("Volume is not in a Point-in"
3163 "-Time Copy group"), &parms
.status
);
3164 remove_iiset(setnumber
, *p
, 0);
3165 spcs_s_ufree(&parms
.status
);
3166 spcs_log("ii", NULL
, gettext("Disabled %s"),
3170 if (is_exported(conf
.shadow_vol
)) {
3173 if ((strcmp(conf
.master_vol
, II_IMPORTED_SHADOW
) == 0) &&
3174 is_exported(conf
.shadow_vol
)) {
3176 "Imported shadow not disabled"), NULL
);
3179 parms
.status
= spcs_s_ucreate();
3180 parms
.flags
= flags
;
3181 rc
= do_ioctl(dsw_fd
, DSWIOC_DISABLE
, &parms
);
3182 if (rc
== -1 && errno
!= DSW_ENOTFOUND
) {
3183 if (errno
== DSW_EDISABLE
) {
3185 * one or more sets within the group
3188 clean_up_after_failed_disable(&parms
);
3190 dsw_error(gettext("Disable failed"),
3194 spcs_log("ii", NULL
, gettext("Disabled %s"), parms
.shadow_vol
);
3198 if (group_name
&& *group_name
) {
3199 for (p
= group_volumes
; *p
; p
++) {
3200 if (!find_shadow_config(*p
, NULL
, NULL
)) {
3202 (void) fprintf(stderr
,
3203 gettext("Volume '%s' is not "
3204 "in a Point-in-Time Copy group"), *p
);
3206 remove_iiset(setnumber
, *p
, 0);
3209 } else if (!group_name
) {
3210 if (!find_shadow_config(argv
[1], NULL
, NULL
)) {
3212 dsw_error(gettext("Volume is not in a Point-in-Time "
3213 "Copy group"), NULL
);
3216 remove_iiset(setnumber
, argv
[1], shd_exported
);
3223 dsw_group_or_single_op(int argc
, char *argv
[], int (*op
)(char *))
3228 usage(gettext("Incorrect number of arguments"));
3231 if (find_group_members(group_name
) < 1)
3232 dsw_error(gettext("Group does not exist or "
3233 "has no members"), NULL
);
3234 for (; *group_volumes
; group_volumes
++)
3235 rc
|= (*op
)(*group_volumes
);
3237 rc
= (*op
)(argv
[1]);
3243 dsw_list_clusters(char *cluster
)
3245 dsw_aioctl_t
*acopy_args
;
3249 if ((count
= do_ioctl(dsw_fd
, DSWIOC_LISTLEN
, NULL
)) < 0)
3250 dsw_error("DSWIOC_LISTLEN", NULL
);
3252 acopy_args
= malloc(sizeof (dsw_aioctl_t
) + count
* DSW_NAMELEN
);
3253 if (acopy_args
== NULL
)
3254 dsw_error(gettext("Can't get memory for list enquiry"), NULL
);
3256 bzero(acopy_args
, sizeof (dsw_aioctl_t
) + count
* DSW_NAMELEN
);
3257 acopy_args
->count
= count
;
3258 acopy_args
->flags
= 0;
3259 acopy_args
->status
= spcs_s_ucreate();
3261 (void) strncpy(acopy_args
->shadow_vol
, cluster
, DSW_NAMELEN
);
3263 rc
= do_ioctl(dsw_fd
, DSWIOC_CLIST
, acopy_args
);
3265 dsw_error(gettext("Cluster list access failure"),
3266 &acopy_args
->status
);
3268 acopy_args
->shadow_vol
[DSW_NAMELEN
*acopy_args
->count
] = NULL
;
3271 (void) printf(gettext("Sets in cluster resource group %s:\n"),
3275 gettext("Currently configured resource groups\n"));
3277 for (i
= 0, ptr
= acopy_args
->shadow_vol
; *ptr
&&
3278 i
< acopy_args
->count
; i
++, ptr
+= DSW_NAMELEN
) {
3279 (void) printf(" %-64.64s\n", ptr
);
3284 dsw_enable(int argc
, char *argv
[])
3287 usage(gettext("Incorrect number of arguments"));
3289 enable(argv
[1], argv
[2], argv
[3], argv
[4]);
3295 dsw_disable(int argc
, char *argv
[])
3297 (void) dsw_group_or_single_disable(argc
, argv
);
3303 dsw_copy_to_shadow(int argc
, char *argv
[])
3308 usage(gettext("Incorrect number of arguments"));
3309 if (group_name
== NULL
)
3310 volume_list
= ++argv
;
3312 if (find_group_members(group_name
) < 1)
3313 dsw_error(gettext("Group does not exist or "
3314 "has no members"), NULL
);
3315 volume_list
= group_volumes
;
3318 exit(do_copy(volume_list
, Copy
, ToShadow
, WaitForStart
));
3323 dsw_update_shadow(int argc
, char *argv
[])
3328 usage(gettext("Incorrect number of arguments"));
3329 if (group_name
== NULL
)
3330 volume_list
= ++argv
;
3332 if (find_group_members(group_name
) < 1)
3333 dsw_error(gettext("Group does not exist or "
3334 "has no members"), NULL
);
3335 volume_list
= group_volumes
;
3338 exit(do_copy(volume_list
, Update
, ToShadow
, WaitForStart
));
3343 dsw_copy_to_master(int argc
, char *argv
[])
3348 usage(gettext("Incorrect number of arguments"));
3349 if (group_name
== NULL
) {
3350 volume_list
= ++argv
;
3351 check_action(gettext("Overwrite master with shadow volume?"));
3353 check_action(gettext("Overwrite every"
3354 " master in this group with its shadow volume?"));
3355 if (find_group_members(group_name
) < 1)
3356 dsw_error(gettext("Group does not exist or "
3357 "has no members"), NULL
);
3358 volume_list
= group_volumes
;
3361 exit(do_copy(volume_list
, Copy
, ToMaster
, WaitForStart
));
3366 dsw_update_master(int argc
, char *argv
[])
3371 usage(gettext("Incorrect number of arguments"));
3372 if (group_name
== NULL
) {
3373 volume_list
= ++argv
;
3374 check_action(gettext("Overwrite master with shadow volume?"));
3376 check_action(gettext("Overwrite every"
3377 " master in this group with its shadow volume?"));
3378 if (find_group_members(group_name
) < 1)
3379 dsw_error(gettext("Group does not exist or "
3380 "has no members"), NULL
);
3381 volume_list
= group_volumes
;
3384 exit(do_copy(volume_list
, Update
, ToMaster
, WaitForStart
));
3389 dsw_abort_copy(int argc
, char *argv
[])
3391 exit(dsw_group_or_single_op(argc
, argv
, abort_copy
));
3396 dsw_display_status(int argc
, char *argv
[])
3401 if (argc
!= 2 && argc
!= 1)
3402 usage(gettext("Incorrect number of arguments"));
3404 /* "iiadm -i" and "iiadm -i all" are equivalent */
3405 if (argc
== 2 && strcmp("all", argv
[1]) != 0) {
3406 in_config
= find_shadow_config(argv
[1], &parms
, NULL
);
3408 (void) printf(gettext(
3409 "Volume is not in configuration file\n"), NULL
);
3410 (void) fflush(stdout
);
3411 (void) strlcpy(parms
.shadow_vol
, argv
[1], DSW_NAMELEN
);
3413 print_status(&parms
, in_config
);
3414 } else if (group_name
) {
3415 if (find_group_members(group_name
) < 1)
3416 dsw_error(gettext("Group does not exist or "
3417 "has no members"), NULL
);
3418 for (; *group_volumes
; group_volumes
++) {
3419 in_config
= find_shadow_config(*group_volumes
,
3422 print_status(&parms
, in_config
);
3425 /* perform action for each line of the stored config file */
3427 !get_dsw_config(setnumber
, &parms
); setnumber
++) {
3428 switch (check_cluster()) {
3430 if ((cfg_cluster_tag
) &&
3431 (strcmp(cfg_cluster_tag
,
3432 parms
.cluster_tag
)))
3435 case II_CLUSTER_LCL
:
3436 if (strlen(parms
.cluster_tag
))
3440 print_status(&parms
, 1);
3447 dsw_display_bitmap(int argc
, char *argv
[])
3453 usage(gettext("Incorrect number of arguments"));
3455 in_config
= find_shadow_config(argv
[1], &parms
, NULL
);
3457 (void) printf(gettext(
3458 "Volume is not in configuration file\n"), NULL
);
3459 (void) fflush(stdout
);
3460 (void) strlcpy(parms
.master_vol
, argv
[1], DSW_NAMELEN
);
3463 bitmap_op(parms
.shadow_vol
, 1, 0, 0, 0);
3470 dsw_version(int argc
, char *argv
[])
3477 dsw_reset(int argc
, char *argv
[])
3479 exit(dsw_group_or_single_op(argc
, argv
, reset
));
3483 dsw_overflow(int argc
, char *argv
[])
3486 usage(gettext("Incorrect number of arguments"));
3488 exit(overflow(argv
[1]));
3492 dsw_wait(int argc
, char *argv
[])
3494 exit(dsw_group_or_single_op(argc
, argv
, wait_for_copy
));
3499 dsw_list_volumes(int argc
, char *argv
[])
3502 usage(gettext("Incorrect number of arguments"));
3509 dsw_export(int argc
, char *argv
[])
3512 usage(gettext("Incorrect number of arguments"));
3514 exit(dsw_group_or_single_op(argc
, argv
, export
));
3518 dsw_detach(int argc
, char *argv
[])
3520 (void) dsw_group_or_single_op(argc
, argv
, detach
);
3525 import(char *shadow_volume
, char *bitmap_volume
)
3527 dsw_config_t parms
= {0};
3529 char shd_dg
[DSW_NAMELEN
];
3530 char bmp_dg
[DSW_NAMELEN
];
3533 * If importing a shadow volume and the shadow volume is already
3534 * configured, we only support this if we are in a Sun Cluster
3535 * and the current user specified a cluster tag of -C local
3537 if (find_shadow_config(shadow_volume
, &parms
, NULL
)) {
3538 dsw_error(gettext("Can't import volume on same node"), NULL
);
3541 switch (check_cluster()) {
3543 case II_CLUSTER_LCL
:
3544 (void) check_resource_group(shadow_volume
);
3545 if (cfg_cluster_tag
) { /* check all volumes are in same dg */
3546 if (cfg_dgname(shadow_volume
, shd_dg
, DSW_NAMELEN
)
3548 dsw_error(gettext("Shadow volume not in a"
3549 " disk group"), NULL
);
3550 if (cfg_dgname(bitmap_volume
, bmp_dg
, DSW_NAMELEN
)
3552 dsw_error(gettext("Bitmap volume not in a"
3553 " disk group"), NULL
);
3554 if (strcmp(bmp_dg
, shd_dg
) != 0)
3555 dsw_error(gettext("Bitmap volume not in"
3556 " same disk group as shadow set members"),
3560 case II_NOT_CLUSTER
:
3565 "Unexpected return from check_cluster()"), NULL
);
3568 /* Local configuration volumes */
3569 if (cfg_load_dsvols(cfg
) < 0 || cfg_load_shadows(cfg
) < 0) {
3570 dsw_error(gettext("Unable to parse config file"), NULL
);
3573 reload_vols
= LD_DSVOLS
| LD_SHADOWS
;
3574 conform_name(&shadow_volume
);
3575 (void) strcpy(parms
.master_vol
, II_IMPORTED_SHADOW
);
3576 (void) strlcpy(parms
.shadow_vol
, shadow_volume
, DSW_NAMELEN
);
3577 (void) strlcpy(parms
.bitmap_vol
, bitmap_volume
, DSW_NAMELEN
);
3578 parms
.flag
= DSW_GOLDEN
;
3580 spcs_log("ii", NULL
, gettext("Import %s %s"),
3581 parms
.shadow_vol
, parms
.bitmap_vol
);
3582 parms
.status
= spcs_s_ucreate();
3583 rc
= do_ioctl(dsw_fd
, DSWIOC_IMPORT
, &parms
);
3585 spcs_log("ii", NULL
, gettext("Import failed %s %s"),
3586 parms
.shadow_vol
, parms
.bitmap_vol
);
3587 dsw_error(gettext("Import failed"), &parms
.status
);
3589 if (perform_autosv()) {
3590 if (cfg_vol_enable(cfg
, shadow_volume
, cfg_cluster_tag
, "ii")
3592 dsw_error(gettext("SV-enable failed"), NULL
);
3594 /* cfg_commit is called by add_cfg_entry below */
3596 spcs_s_ufree(&parms
.status
);
3597 add_cfg_entry(&parms
);
3601 dsw_import(int argc
, char *argv
[])
3604 usage(gettext("Incorrect number of arguments"));
3605 import(argv
[1], argv
[2]);
3611 join(char *shadow_volume
, char *bitmap_file
)
3619 uchar_t
*shd_bitmap
= 0;
3621 char dgname
[DSW_NAMELEN
];
3623 if (!find_shadow_config(shadow_volume
, &conf
, &shd
))
3624 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3627 /* If this is an exportable shadow in the cluster, change ctag */
3628 if (strlen(conf
.cluster_tag
) &&
3629 (cfg_dgname(shadow_volume
, dgname
, sizeof (dgname
))))
3630 cfg_resource(cfg
, cfg_cluster_tag
= strdup(dgname
));
3632 if (cfg_load_dsvols(cfg
) < 0 || cfg_load_shadows(cfg
) < 0) {
3633 dsw_error(gettext("Unable to parse config file"), NULL
);
3635 reload_vols
= LD_DSVOLS
| LD_SHADOWS
;
3636 conform_name(&shadow_volume
);
3638 if ((bmpfp
= fopen(bitmap_file
, "r")) == NULL
) {
3639 perror(bitmap_file
);
3640 (void) fprintf(stderr
,
3641 gettext("Can't open imported bitmap volume\n"));
3645 if (fread(&header
, sizeof (header
), 1, bmpfp
) != 1) {
3646 (void) fprintf(stderr
,
3647 gettext("Can't read imported bitmap volume\n"));
3651 /* See if this is a bitmap header */
3652 switch (header
.ii_magic
) {
3653 case DSW_DIRTY
: /* A copy of a enable bitmap volume */
3655 check_action(gettext("Use the never imported bitmap?"));
3657 case DSW_INVALID
: /* A valid diskable secondary bitmap */
3660 (void) fprintf(stderr
,
3661 gettext("Secondary bitmap is not a valid bitmap volume\n"));
3665 size
= FBA_SIZE(header
.ii_copyfba
- header
.ii_shdfba
);
3666 if ((shd_bitmap
= malloc(size
)) == NULL
) {
3671 if (fseek(bmpfp
, FBA_SIZE(header
.ii_shdfba
), SEEK_SET
)) {
3676 if (fread(shd_bitmap
, 1, size
, bmpfp
) != size
) {
3677 (void) fprintf(stderr
,
3678 gettext("Can't read imported bitmap volume\n"));
3682 (void) fclose(bmpfp
);
3684 (void) strlcpy(parms
.shadow_vol
, shadow_volume
, DSW_NAMELEN
);
3685 parms
.shd_bitmap
= shd_bitmap
;
3686 parms
.shd_size
= size
;
3687 parms
.copy_bitmap
= NULL
;
3688 parms
.copy_size
= 0;
3690 spcs_log("ii", NULL
, gettext("Join %s %s"),
3691 parms
.shadow_vol
, bitmap_file
);
3692 parms
.status
= spcs_s_ucreate();
3693 rc
= do_ioctl(dsw_fd
, DSWIOC_JOIN
, &parms
);
3695 spcs_log("ii", NULL
, gettext("Join failed %s %s"),
3696 parms
.shadow_vol
, bitmap_file
);
3697 dsw_error(gettext("Join failed"), &parms
.status
);
3699 if (perform_autosv()) {
3700 rc
= cfg_vol_enable(cfg
, shadow_volume
, cfg_cluster_tag
, "ii");
3702 dsw_error(gettext("SV-enable failed"), NULL
);
3704 (void) cfg_commit(cfg
);
3706 spcs_s_ufree(&parms
.status
);
3710 params(char *shadow_volume
)
3712 char *delay
= param_delay
;
3713 char *unit
= param_unit
;
3720 (void) strlcpy(parms
.shadow_vol
, shadow_volume
, DSW_NAMELEN
);
3721 if (delay
== NULL
|| unit
== NULL
) {
3723 parms
.copy_delay
= -1;
3724 parms
.copy_unit
= -1;
3726 new_delay
= parms
.copy_delay
= convert_int(delay
);
3727 new_unit
= parms
.copy_unit
= convert_int(unit
);
3730 parms
.status
= spcs_s_ucreate();
3731 rc
= do_ioctl(dsw_fd
, DSWIOC_COPYP
, &parms
);
3733 (void) fprintf(stderr
,
3734 gettext("Parameter ranges are delay(%d - %d), "
3735 "units(%d - %d)\n"), MIN_THROTTLE_DELAY
, MAX_THROTTLE_DELAY
,
3736 MIN_THROTTLE_UNIT
, MAX_THROTTLE_UNIT
);
3737 dsw_error(gettext("Set Copy Parameters failed"), &parms
.status
);
3740 spcs_log("ii", NULL
, gettext("Changed copy parameters %s from "
3741 "%d %d to %d %d"), parms
.shadow_vol
, parms
.copy_delay
,
3742 parms
.copy_unit
, new_delay
, new_unit
);
3744 (void) printf(gettext("volume: %s\ncopy delay: %d\ncopy unit:"
3745 " %d\n"), parms
.shadow_vol
, parms
.copy_delay
,
3747 spcs_s_ufree(&parms
.status
);
3752 do_attach(dsw_config_t
*parms
)
3758 spcs_log("ii", NULL
, gettext("Attach %s %s"),
3759 parms
->shadow_vol
, parms
->bitmap_vol
);
3760 parms
->status
= spcs_s_ucreate();
3761 rc
= do_ioctl(dsw_fd
, DSWIOC_OATTACH
, parms
);
3764 /* if overflow() fails, it calls dsw_error to exit */
3765 (void) overflow(parms
->bitmap_vol
);
3767 spcs_s_ufree(&parms
->status
);
3769 if (!find_shadow_config(parms
->shadow_vol
, &io
, NULL
))
3771 gettext("Volume is not in a Point-in-Time Copy "
3773 (void) strlcpy(io
.bitmap_vol
, parms
->bitmap_vol
, DSW_NAMELEN
);
3774 io
.status
= spcs_s_ucreate();
3775 if (do_ioctl(dsw_fd
, DSWIOC_OATTACH
, &io
) == -1) {
3776 spcs_log("ii", NULL
, gettext("Attach failed %s %s"),
3777 io
.shadow_vol
, parms
->bitmap_vol
);
3778 dsw_error(gettext("Attach failed"), &io
.status
);
3780 spcs_s_ufree(&io
.status
);
3785 attach(char *shadow_volume
)
3789 char shd_dg
[DSW_NAMELEN
];
3790 char ovr_dg
[DSW_NAMELEN
];
3792 switch (check_cluster()) {
3794 case II_CLUSTER_LCL
:
3795 (void) check_resource_group(shadow_volume
);
3796 if (cfg_cluster_tag
) { /* check all volumes are in same dg */
3797 if (cfg_dgname(shadow_volume
, shd_dg
, DSW_NAMELEN
)
3799 dsw_error(gettext("Shadow volume not in a"
3800 " disk group"), NULL
);
3801 if (cfg_dgname(overflow_file
, ovr_dg
, DSW_NAMELEN
)
3803 dsw_error(gettext("Overflow volume not in a"
3804 " disk group"), NULL
);
3805 if (strcmp(ovr_dg
, shd_dg
) != 0)
3806 dsw_error(gettext("Overflow volume not in"
3807 " same disk group as shadow set members"),
3811 case II_NOT_CLUSTER
:
3816 "Unexpected return from check_cluster()"), NULL
);
3819 /* assure that the overflow_file is not an II volume */
3820 if (find_any_cf_line(overflow_file
))
3822 "Overflow volume is already in a Point-in-Time Copy "
3825 /* use find_shadow_config() to find setnumber */
3826 if (!find_shadow_config(shadow_volume
, &parms
, NULL
))
3827 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3830 /* can only attach an overflow volume to dependent, compact shadow */
3831 (void) strlcpy(args
.shadow_vol
, shadow_volume
, DSW_NAMELEN
);
3833 args
.status
= spcs_s_ucreate();
3834 if ((do_ioctl(dsw_fd
, DSWIOC_STAT
, &args
) == -1) ||
3835 !(args
.stat
& DSW_TREEMAP
))
3836 dsw_error(gettext("Not a compact dependent shadow"), NULL
);
3838 /* bitmap_vol is overloaded */
3839 (void) strlcpy(parms
.bitmap_vol
, overflow_file
, DSW_NAMELEN
);
3843 /* add overflow to cfg line */
3844 (void) sprintf(key
, "ii.set%d.overflow", setnumber
);
3845 if (cfg_put_cstring(cfg
, key
, overflow_file
,
3846 strlen(overflow_file
)) < 0) {
3847 perror("cfg_put_cstring");
3849 (void) cfg_commit(cfg
);
3854 dsw_join(int argc
, char *argv
[])
3857 usage(gettext("Incorrect number of arguments"));
3859 join(argv
[1], argv
[2]);
3864 dsw_params(int argc
, char *argv
[])
3866 if (argc
!= 4 && argc
!= 2 && argc
!= 0)
3867 usage(gettext("Incorrect number of arguments"));
3869 if ((argc
== 4) || (argc
== 2)) {
3870 param_delay
= argv
[1];
3871 param_unit
= argv
[2];
3877 exit(dsw_group_or_single_op(2, argv
, params
));
3882 dsw_attach(int argc
, char *argv
[])
3884 overflow_file
= argv
[1];
3886 (void) dsw_group_or_single_op(2, argv
, attach
);
3892 dsw_olist(int argc
, char *argv
[])
3894 char *sp
, *overflow_list
, **vol
;
3897 char key
[ CFG_MAX_KEY
], buf
[ CFG_MAX_BUF
];
3899 overflow_list
= get_overflow_list();
3903 for (sp
= overflow_list
; *sp
; sp
+= DSW_NAMELEN
) {
3907 /* create hash (adding room for suspended overflow volumes) */
3908 if (hcreate(count
+ 1024) == 0) {
3909 dsw_error(gettext("Out of memory creating lookup table"), NULL
);
3914 /* create memory to store copy of list */
3915 vol
= (char **)calloc(count
, sizeof (char *));
3918 gettext("Out of memory creating lookup table"),
3924 for (i
= 0, sp
= overflow_list
; *sp
; sp
+= DSW_NAMELEN
, i
++) {
3926 /* make copy of string */
3927 vol
[ i
] = (char *)malloc(DSW_NAMELEN
+ 1);
3928 (void) strlcpy(vol
[ i
], sp
, DSW_NAMELEN
);
3930 item
.key
= vol
[ i
];
3931 item
.data
= (char *)0;
3932 (void) hsearch(item
, ENTER
);
3936 /* loop through config file entries */
3938 cfg_rewind(cfg
, CFG_SEC_CONF
);
3943 (void) snprintf(key
, CFG_MAX_KEY
, "ii.set%d.overflow", i
);
3944 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
3948 /* has this set got an overflow volume? */
3953 /* look up overflow in hash */
3955 if (count
> 0 && (found
= hsearch(item
, FIND
)) != NULL
) {
3956 if (0 == (int)found
->data
) {
3957 (void) printf("%s\n", buf
);
3958 found
->data
= (char *)1;
3959 (void) hsearch(*found
, ENTER
);
3962 /* must be part of a suspended set */
3963 (void) printf("%s (attached to suspended set)\n", buf
);
3965 item
.data
= (char *)1;
3966 (void) hsearch(item
, ENTER
);
3974 dsw_ostat(int argc
, char *argv
[])
3980 usage(gettext("Incorrect number of arguments"));
3982 (void) strlcpy(args
.overflow_vol
, argv
[1], DSW_NAMELEN
);
3984 args
.status
= spcs_s_ucreate();
3985 if (do_ioctl(dsw_fd
, DSWIOC_OSTAT2
, &args
) == -1)
3986 dsw_error(gettext("Stat failed"), &args
.status
);
3987 spcs_s_ufree(&args
.status
);
3989 if ((args
.hversion
>= 1) && (args
.hmagic
== II_OMAGIC
)) {
3990 stat_flags
= args
.flags
;
3991 if (stat_flags
& IIO_CNTR_INVLD
)
3992 (void) printf(gettext("Clean shutdown of volume "
3993 "sets associated with overflow volume "
3995 "Overflow counters will be inconsistent "
3996 "until new point-in-time(s) are taken.\n"));
3998 (void) printf(gettext("Total number of attached shadows: %d\n"),
4000 (void) printf(gettext("Number of currently attached shadows: %d\n"),
4002 (void) printf(gettext("Total number of chunks: %lld\n"), args
.nchunks
);
4003 (void) printf(gettext("Number of chunks ever allocated: %lld\n"),
4005 (void) printf(gettext("Number of used chunks: %lld\n"),
4006 (args
.nchunks
- args
.unused
));
4007 (void) printf(gettext("Number of unused chunks: %lld\n"), args
.unused
);
4013 dsw_move_2_group(int argc
, char *argv
[])
4016 dsw_movegrp_t movegrp
;
4020 /* handle move to NULL group, or group of all spaces or tabs */
4021 (void) strncpy(movegrp
.new_group
, group_name
, DSW_NAMELEN
);
4022 if ((strlen(group_name
) == 0) || (strcspn(group_name
, " \t") == 0)) {
4024 bzero(movegrp
.new_group
, DSW_NAMELEN
);
4027 /* get the ctag for this group (if any) */
4028 gdata
= (grptag_t
*)nsc_lookup(volhash
, group_name
);
4031 movegrp
.status
= spcs_s_ucreate();
4033 for (++argv
; *argv
; argv
++) {
4034 if (!find_shadow_config(*argv
, &parms
, NULL
))
4035 dsw_error(gettext("Volume is not in a Point-in-Time "
4036 "Copy group"), NULL
);
4038 /* ensure the ctag matches the group */
4039 if (gdata
&& *gdata
->ctag
) {
4040 if (strncmp(parms
.cluster_tag
, gdata
->ctag
,
4041 DSW_NAMELEN
) != 0) {
4042 (void) fprintf(stderr
, "%s: %s %s %s\n", cmdnam
,
4043 gettext("unable to move set"), *argv
,
4044 gettext("into new group - cluster "
4045 "resource mismatch"));
4051 /* move the set in the kernel */
4052 (void) strncpy(movegrp
.shadow_vol
, parms
.shadow_vol
,
4054 if (do_ioctl(dsw_fd
, DSWIOC_MOVEGRP
, &movegrp
) < 0)
4055 dsw_error(gettext("Failed to move group in kernel"),
4058 /* now update the config */
4059 (void) sprintf(key
, "ii.set%d.group", setnumber
);
4060 if (cfg_put_cstring(cfg
, key
, group_name
,
4061 strlen(group_name
)) < 0) {
4062 perror("cfg_put_cstring");
4064 (void) cfg_commit(cfg
);
4066 spcs_s_ufree(&movegrp
.status
);
4076 if ((pfp
= popen("/usr/bin/sort -u", "w")) == NULL
) {
4077 dsw_error(gettext("Can't open sort program"), NULL
);
4080 (void) fflush(stdout
);
4081 for (setnumber
= 1; /*CSTYLED*/; setnumber
++) {
4082 (void) snprintf(key
, sizeof (key
), "ii.set%d.group", setnumber
);
4083 if (cfg_get_cstring(cfg
, key
, buf
, sizeof (buf
)) < 0)
4086 /* skip if shadow set is not in any group */
4087 if (strcmp(buf
, "") == 0)
4089 (void) fprintf(pfp
, "%s\n", buf
);
4095 dsw_list_group_volumes()
4099 if (find_group_members(group_name
) < 1)
4100 dsw_error(gettext("Group does not exist or has no members"),
4103 if ((pfp
= popen("/usr/bin/sort -u", "w")) == NULL
) {
4104 dsw_error(gettext("Can't open sort program"), NULL
);
4107 (void) fflush(stdout
);
4108 for (; *group_volumes
; group_volumes
++)
4109 (void) fprintf(pfp
, "%s\n", *group_volumes
);
4114 load_ii_vols(CFGFILE
*cfg
)
4117 char *mst
, *shd
, *buf
, **entry
;
4122 static int whinged
= 0;
4128 volhash
= nsc_create_hash();
4129 cfg_rewind(cfg
, CFG_SEC_CONF
);
4130 entries
= cfg_get_section(cfg
, &entry
, "ii");
4131 for (set
= 1; set
<= entries
; set
++) {
4132 buf
= entry
[set
- 1];
4134 /* grab master volume name */
4135 mst
= strtok(buf
, " ");
4141 /* grab shadow, group & cnode fields */
4142 shd
= strtok(NULL
, " ");
4143 (void) strtok(NULL
, " "); /* bitmap */
4144 (void) strtok(NULL
, " "); /* mode */
4145 (void) strtok(NULL
, " "); /* overflow */
4146 ctag
= strtok(NULL
, " "); /* cnode */
4147 (void) strtok(NULL
, " "); /* options */
4148 group
= strtok(NULL
, " "); /* group */
4150 /* Fix optional tags */
4152 ctag
+= strspn(ctag
, "-");
4154 group
+= strspn(group
, "-");
4156 /* If cluster tags don't match, skip record */
4157 if ((cfg_cluster_tag
&& strcmp(ctag
, cfg_cluster_tag
)) ||
4158 (!cfg_cluster_tag
&& strlen(ctag
))) {
4163 /* master volume, may be duplicates */
4164 mdata
= (mstcount_t
*)nsc_lookup(volhash
, mst
);
4168 mdata
= (mstcount_t
*)malloc(sizeof (mstcount_t
));
4170 (void) nsc_insert_node(volhash
, mdata
, mst
);
4173 /* grab shadow volume name */
4174 sdata
= (shdvol_t
*)malloc(sizeof (shdvol_t
));
4175 (void) strncpy(sdata
->master
, mst
, DSW_NAMELEN
);
4176 (void) nsc_insert_node(volhash
, sdata
, shd
);
4178 /* No need to continue if no groups or ctags */
4179 if (!group
|| !*group
|| !ctag
|| !*ctag
) {
4184 gdata
= (grptag_t
*)nsc_lookup(volhash
, group
);
4186 /* group already exists - check ctag */
4188 (strncmp(ctag
, gdata
->ctag
, DSW_NAMELEN
) != 0)) {
4190 (void) printf(gettext(
4191 "Warning: multiple "
4192 "cluster resource groups "
4193 "defined within a single "
4199 gdata
= (grptag_t
*)malloc(sizeof (grptag_t
));
4200 (void) strncpy(gdata
->ctag
, ctag
, DSW_NAMELEN
);
4201 (void) nsc_insert_node(volhash
, gdata
, group
);
4207 /* free up any leftovers */
4208 while (set
< entries
)
4217 nsc_remove_all(volhash
, free
);
4225 static int calculated
= 0;
4229 if (getenv("II_SET_CLUSTER"))
4238 * we only perform auto-sv if we're in a sun cluster or if
4239 * we're on a standalone system. I.e. we don't do auto-sv on Harry
4241 rc
= check_cluster();
4243 if (II_NOT_CLUSTER
== rc
) {
4246 result
= cfg_issuncluster();
4254 * Returns true if set has had the shadow volume exported.
4255 * Returns false if shadow volume is not exported, or set is suspended.
4258 is_exported(char *set
)
4263 (void) strlcpy(args
.shadow_vol
, set
, DSW_NAMELEN
);
4264 args
.status
= spcs_s_ucreate();
4266 rc
= do_ioctl(dsw_fd
, DSWIOC_STAT
, &args
);
4267 spcs_s_ufree(&args
.status
);
4270 /* set must be suspended, or being disabled */
4274 return ((args
.stat
& DSW_SHDEXPORT
) == DSW_SHDEXPORT
);
4278 conform_name(char **path
)
4281 int rc
= cfg_get_canonical_name(cfg
, *path
, &cfgname
);
4284 dsw_error(gettext("Unable to parse config file"), NULL
);
4287 (void) printf(" '%s'\n%s\n '%s'\n", *path
,
4288 gettext("is currently configured as"), cfgname
);
4289 check_action(gettext("Perform operation with indicated volume"
4293 * NOTE: *path ought to be deallocated ('free(*path)') after
4294 * we're done with it, but since this routine is called just
4295 * before we exit, it doesn't really matter
4301 * verify_groupname(char *, int);
4303 * Check the group name for the following rules:
4304 * 1. The name does not start with a '-'
4305 * 2. The name does not contain any space characters as defined by
4307 * If either of these rules are broken, error immediately. The check for a
4308 * leading dash can be skipped if the 'testDash' argument is false. This is to
4309 * allow for the '-g -L' functionality.
4313 verify_groupname(char *grp
, int testDash
)
4317 if (testDash
&& grp
[0] == '-') {
4319 dsw_error(gettext("group name cannot start with a '-'"), NULL
);
4322 for (i
= 0; grp
[i
] != '\0'; i
++) {
4323 if (isspace(grp
[i
])) {
4325 dsw_error(gettext("group name cannot contain a space"),
4332 check_iishadow(char *shadow_vol
) {
4342 * See if librdc is around
4343 * If not, we can just return
4345 if (librdc
= dlopen(RDC_LIB
, RTLD_LAZY
| RTLD_GLOBAL
))
4346 self_check
= (int (*)(char *)) dlsym(librdc
, "self_check");
4352 entries
= cfg_get_section(cfg
, &entry
, "sndr");
4353 for (i
= 0; i
< entries
; i
++) {
4356 (void) strtok(buf
, " "); /* phost */
4357 (void) strtok(NULL
, " "); /* primary */
4358 (void) strtok(NULL
, " "); /* pbitmap */
4359 shost
= strtok(NULL
, " "); /* shost */
4360 svol
= strtok(NULL
, " "); /* secondary */
4362 if (self_check(shost
) && (strcmp(shadow_vol
, svol
) == 0)) {
4368 "shadow volume is in use as SNDR secondary volume"),
4374 (void) dlclose(librdc
);