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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/types.h>
28 #include <sys/utsname.h>
47 #include <sys/nsctl/rdc_io.h>
48 #include <sys/nsctl/rdc_ioctl.h>
49 #include <sys/nsctl/rdc_prot.h>
51 #include <sys/nsctl/cfg.h>
53 #include <sys/unistat/spcs_s.h>
54 #include <sys/unistat/spcs_s_u.h>
55 #include <sys/unistat/spcs_errors.h>
57 #include <sys/socket.h>
58 #include <netinet/in.h>
59 #include <arpa/inet.h>
60 #include <netinet/tcp.h>
61 #include <rpc/rpc_com.h>
64 #include <sys/nsctl/librdc.h>
65 #include <sys/nsctl/nsc_hash.h>
70 * support for the special cluster tag "local" to be used with -C in a
71 * cluster for local volumes.
74 #define RDC_LOCAL_TAG "local"
76 typedef struct volcount_s
{
79 hash_node_t
**volhash
= NULL
;
82 * rdc_islocal is only pertinent while creating the pairs array.
83 * after all the pairs are set, its value is useless, retaining
84 * the last value it was set to.
85 * its only reason in life is to suppress an error message in 2
86 * places where the inappropriate becomes appropriate (a supplied
87 * ctag which does not match an implied one cfg_dgame()). This
88 * happens when C "local" is supplied. It is then used to make an
89 * error message clearer. A
90 * gettext("set %s does not match", rdc_islocal < 1?dga:dgb) situation
92 static int rdc_islocal
= 0;
96 #define min(a, b) ((a) > (b) ? (b) : (a))
98 static char place_holder
[] = "-"; /* cfg place holder value */
101 * config file user level Dual copy pair structure
103 typedef struct _sd_dual_pair
{
104 char fhost
[MAX_RDC_HOST_SIZE
]; /* Hostname for primary device */
105 char fnetaddr
[RDC_MAXADDR
]; /* Host netaddr for primary device */
106 char ffile
[NSC_MAXPATH
]; /* Primary device */
107 char fbitmap
[NSC_MAXPATH
]; /* Primary bitmap device */
108 char thost
[MAX_RDC_HOST_SIZE
]; /* Hostname for secondary device */
109 char tnetaddr
[RDC_MAXADDR
]; /* Host netaddr for secondary device */
110 char tfile
[NSC_MAXPATH
]; /* Secondary device */
111 char tbitmap
[NSC_MAXPATH
]; /* Secondary bitmap device */
112 char directfile
[NSC_MAXPATH
]; /* Local FCAL direct IO volume */
113 char group
[NSC_MAXPATH
]; /* Group name */
114 char ctag
[MAX_RDC_HOST_SIZE
]; /* Cluster resource name tag */
115 char diskqueue
[NSC_MAXPATH
]; /* Disk Queue volume */
116 int doasync
; /* Device is in sync/async mode */
119 #define EXTRA_ARGS 6 /* g grp C ctag q diskqueue */
121 static int rdc_operation(
122 CFGFILE
*, char *, char *, char *, char *, char *, char *,
123 int, int, char *, char *, char *, char *, int *, int);
124 int read_config(int, char *, char *, char *);
125 static int read_libcfg(int, char *, char *);
126 int prompt_user(int, int);
127 static void rdc_check_dgislocal(char *);
128 void process_clocal(char *);
129 static void usage(void);
131 static void load_rdc_vols(CFGFILE
*);
132 static void unload_rdc_vols();
133 static int perform_autosv();
134 static void different_devs(char *, char *);
135 static void validate_name(CFGFILE
*, char *);
136 static void set_autosync(int, char *, char *, char *);
137 static int autosync_is_on(char *tohost
, char *tofile
);
138 static void enable_autosync(char *fhost
, char *ffile
, char *thost
, char *tfile
);
139 static void checkgfields(CFGFILE
*, int, char *, char *, char *, char *,
140 char *, char *, char *, char *, char *);
141 static void checkgfield(CFGFILE
*, int, char *, char *, char *);
142 static int rdc_bitmapset(char *, char *, char *, int, nsc_off_t
);
143 static int parse_cfg_buf(char *, _sd_dual_pair_t
*, char *);
144 static void verify_groupname(char *grp
);
145 extern char *basename(char *);
148 static _sd_dual_pair_t
*pair_list
;
150 struct netbuf svaddr
;
152 struct netconfig nconf
;
153 struct netconfig
*conf
;
154 struct knetconfig knconf
;
156 static char *reconfig_pbitmap
= NULL
;
157 static char *reconfig_sbitmap
= NULL
;
159 static char *reconfig_direct
= NULL
;
161 static char *reconfig_group
= NULL
;
162 static char reconfig_ctag
[MAX_RDC_HOST_SIZE
];
163 static int reconfig_doasync
= -1;
165 static int clustered
= 0;
166 static int proto_test
= 0;
171 rdc_print_state(rdc_set_t
*urdc
)
176 if (urdc
->sync_flags
& RDC_VOL_FAILED
)
177 return (gettext("volume failed"));
178 else if (urdc
->sync_flags
& RDC_FCAL_FAILED
)
179 return (gettext("fcal failed"));
180 else if (urdc
->bmap_flags
& RDC_BMP_FAILED
)
181 return (gettext("bitmap failed"));
182 else if (urdc
->flags
& RDC_DISKQ_FAILED
)
183 return (gettext("disk queue failed"));
184 else if (urdc
->flags
& RDC_LOGGING
) {
185 if (urdc
->sync_flags
& RDC_SYNC_NEEDED
)
186 return (gettext("need sync"));
187 else if (urdc
->sync_flags
& RDC_RSYNC_NEEDED
)
188 return (gettext("need reverse sync"));
189 else if (urdc
->flags
& RDC_QUEUING
)
190 return (gettext("queuing"));
192 return (gettext("logging"));
193 } else if ((urdc
->flags
& RDC_SLAVE
) && (urdc
->flags
& RDC_SYNCING
)) {
194 if (urdc
->flags
& RDC_PRIMARY
)
195 return (gettext("reverse syncing"));
197 return (gettext("syncing"));
198 } else if (urdc
->flags
& RDC_SYNCING
) {
199 if (urdc
->flags
& RDC_PRIMARY
)
200 return (gettext("syncing"));
202 return (gettext("reverse syncing"));
205 return (gettext("replicating"));
210 rdc_print(int file_format
, int verbose
, char *group_arg
, char *ctag_arg
,
211 char *user_shost
, char *user_sdev
, CFGFILE
*cfgp
)
213 rdc_status_t
*rdc_status
;
214 spcs_s_info_t ustatus
;
218 char *tohost
, *tofile
;
219 _sd_dual_pair_t pair
;
220 char *tmptohost
= pair
.thost
;
221 char *tmptofile
= pair
.tfile
;
222 char *fromhost
= pair
.fhost
;
223 char *fromfile
= pair
.ffile
;
224 char *frombitmap
= pair
.fbitmap
;
225 char *tobitmap
= pair
.tbitmap
;
226 char *directfile
= pair
.directfile
;
227 char *group
= pair
.group
;
228 char *diskqueue
= pair
.diskqueue
;
229 char *ctag
= pair
.ctag
;
233 char key
[CFG_MAX_KEY
];
234 char buf
[CFG_MAX_BUF
];
238 size
= sizeof (rdc_status_t
) + (sizeof (rdc_set_t
) * (rdc_maxsets
- 1));
239 match
= (user_shost
!= NULL
|| user_sdev
!= NULL
);
242 if (user_shost
== NULL
&& user_sdev
!= NULL
)
244 else if (user_shost
!= NULL
&& user_sdev
== NULL
)
247 rdc_status
= malloc(size
);
250 gettext("unable to allocate %ld bytes"), size
);
253 rdc_status
->nset
= rdc_maxsets
;
254 ustatus
= spcs_s_ucreate();
256 rc
= RDC_IOCTL(RDC_STATUS
, rdc_status
, 0, 0, 0, 0, ustatus
);
257 if (rc
== SPCS_S_ERROR
) {
258 rdc_err(&ustatus
, gettext("statistics error"));
261 spcs_s_ufree(&ustatus
);
263 max
= min(rdc_status
->nset
, rdc_maxsets
);
267 cfg_rewind(cfg
, CFG_SEC_CONF
);
269 if ((cfg
= cfg_open(NULL
)) == NULL
)
271 gettext("unable to access configuration"));
273 if (!cfg_lock(cfg
, CFG_RDLOCK
))
274 rdc_err(NULL
, gettext("unable to lock configuration"));
277 for (i
= 0; i
< max
; i
++) {
278 urdc
= &rdc_status
->rdc_set
[i
];
280 if (!(urdc
->flags
& RDC_ENABLED
))
284 (strcmp(user_shost
, urdc
->secondary
.intf
) != 0 ||
285 strcmp(user_sdev
, urdc
->secondary
.file
) != 0))
288 tohost
= urdc
->secondary
.intf
;
289 tofile
= urdc
->secondary
.file
;
292 /* get sndr entries until shost, sfile match */
293 for (j
= 0; j
< rdc_maxsets
; j
++) {
295 (void) snprintf(key
, sizeof (key
),
296 "sndr.set%d", setnumber
);
297 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
301 if (parse_cfg_buf(buf
, &pair
, NULL
))
302 rdc_err(NULL
, gettext("cfg input error"));
304 if (strcmp(tmptofile
, tofile
) != 0)
306 if (strcmp(tmptohost
, tohost
) != 0)
309 if (pair
.doasync
== 0)
310 (void) strcpy(sync
, "sync");
312 (void) strcpy(sync
, "async");
314 /* Got the matching entry */
319 if (j
== rdc_maxsets
)
320 continue; /* not found in config */
322 if (strcmp(group_arg
, "") != 0 &&
323 strncmp(group_arg
, group
, NSC_MAXPATH
) != 0)
326 if (strcmp(ctag_arg
, "") != 0 &&
327 strncmp(ctag_arg
, ctag
, MAX_RDC_HOST_SIZE
) != 0)
331 (void) printf("%s %s %s %s %s %s %s %s",
332 fromhost
, fromfile
, frombitmap
,
333 tohost
, tofile
, tobitmap
,
335 if (strlen(group
) != 0)
336 (void) printf(" g %s", group
);
337 if ((strlen(ctag
) != 0) && (ctag
[0] != '-'))
338 (void) printf(" C %s", ctag
);
339 if (strlen(diskqueue
) != 0)
340 (void) printf(" q %s", diskqueue
);
345 if (strcmp(group_arg
, "") != 0 &&
346 strncmp(group_arg
, urdc
->group_name
, NSC_MAXPATH
) != 0)
349 if (!(urdc
->flags
& RDC_PRIMARY
)) {
350 (void) printf(gettext("%s\t<-\t%s:%s\n"),
351 urdc
->secondary
.file
, urdc
->primary
.intf
,
354 (void) printf(gettext("%s\t->\t%s:%s\n"),
355 urdc
->primary
.file
, urdc
->secondary
.intf
,
356 urdc
->secondary
.file
);
362 (void) printf(gettext("autosync: on"));
364 (void) printf(gettext("autosync: off"));
366 (void) printf(gettext(", max q writes: %lld"), urdc
->maxqitems
);
367 (void) printf(gettext(", max q fbas: %lld"), urdc
->maxqfbas
);
368 (void) printf(gettext(", async threads: %d"),
370 (void) printf(gettext(", mode: %s"),
371 pair
.doasync
? "async" : "sync");
373 if (strlen(urdc
->group_name
) != 0)
374 (void) printf(gettext(", group: %s"), urdc
->group_name
);
375 if ((strlen(ctag
) != 0) && (ctag
[0] != '-'))
376 (void) printf(gettext(", ctag: %s"), ctag
);
377 if (strlen(urdc
->disk_queue
) != 0) {
378 (void) printf(gettext(", %s diskqueue: %s"),
379 (urdc
->flags
& RDC_QNOBLOCK
) ? gettext("non blocking") :
380 gettext("blocking"), urdc
->disk_queue
);
383 (void) printf(gettext(", state: %s"), rdc_print_state(urdc
));
384 (void) printf(gettext("\n"));
393 if (match
&& !found
) {
394 rdc_warn(NULL
, gettext("unable to find set %s:%s"),
395 user_shost
, user_sdev
);
403 parse_extras(int argc
, char *args
[], int i
)
410 (void) strcpy(pair_list
[i
].ctag
, "");
411 (void) strcpy(pair_list
[i
].group
, "");
412 (void) strcpy(pair_list
[i
].diskqueue
, "");
417 if (argc
!= 2 && argc
!= 4 && argc
!= 6)
420 for (j
= 0; j
< argc
; j
+= 2) {
421 if (strcmp(args
[j
], "g") == 0) {
424 (void) strncpy(pair_list
[i
].group
, args
[j
+ 1],
428 if (strcmp(args
[j
], "C") == 0) {
433 (void) strncpy(pair_list
[i
].ctag
, args
[j
+ 1],
435 process_clocal(pair_list
[i
].ctag
);
438 if (strcmp(args
[j
], "q") == 0) {
441 (void) strncpy(pair_list
[i
].diskqueue
, args
[j
+ 1],
451 parse_cfg_buf(char *buf
, _sd_dual_pair_t
*pair
, char *lghn
)
455 char options
[64], *p
, *q
;
458 rc
= sscanf(buf
, "%s %s %s %s %s %s %s %s %s %s %s %s", pair
->fhost
,
459 pair
->ffile
, pair
->fbitmap
, pair
->thost
, pair
->tfile
,
460 pair
->tbitmap
, pair
->directfile
, sync
, pair
->group
,
461 pair
->ctag
, options
, pair
->diskqueue
);
464 rdc_err(NULL
, gettext("cfg input error"));
466 if (strcmp(pair
->diskqueue
, place_holder
) == 0)
467 (void) strcpy(pair
->diskqueue
, "");
469 if (strcmp(pair
->group
, place_holder
) == 0)
470 (void) strcpy(pair
->group
, "");
472 if (strcmp(sync
, "sync") == 0)
474 else if (strcmp(sync
, "async") == 0)
478 gettext("set %s:%s neither sync nor async"),
479 pair
->thost
, pair
->tfile
);
482 if (lghn
&& (p
= strstr(options
, "lghn="))) {
486 /* LINTED p & q limited to options[64] */
491 (void) strncpy(lghn
, p
, len
);
501 ctag_check(char *fromhost
, char *fromfile
, char *frombitmap
, char *tohost
,
502 char *tofile
, char *tobitmap
, char *ctag
, char *diskq
)
508 char file_buf
[MAX_RDC_HOST_SIZE
];
509 char bmp_buf
[MAX_RDC_HOST_SIZE
];
510 char que_buf
[NSC_MAXPATH
];
513 char fromname
[MAXHOSTNAMELEN
], toname
[MAXHOSTNAMELEN
];
518 hp
= gethost_byname(fromhost
);
519 (void) strncpy(fromname
, hp
->h_name
, MAXHOSTNAMELEN
);
520 hp
= gethost_byname(tohost
);
521 (void) strncpy(toname
, hp
->h_name
, MAXHOSTNAMELEN
);
522 if (!self_check(fromname
) && !self_check(toname
)) {
524 * If we could get a list of logical hosts on this cluster
525 * then we could print something intelligent about where
526 * the volume is mastered. For now, just print some babble
527 * about the fact that we have no idea.
530 gettext("either %s:%s or %s:%s is not local"),
531 fromhost
, fromfile
, tohost
, tofile
);
534 is_primary
= self_check(fromname
);
537 * If implicit disk group name and no ctag specified by user,
538 * we set the ctag to it.
539 * If implicit disk group name, it must match any supplied ctag.
541 localfile
= is_primary
? fromfile
: tofile
;
542 file_dgname
= cfg_dgname(localfile
, file_buf
, sizeof (file_buf
));
543 if (file_dgname
&& strlen(file_dgname
))
544 rdc_check_dgislocal(file_dgname
);
547 * Autogenerate a ctag, if not "-C local" or no "-C " specified
549 if (!rdc_islocal
&& !strlen(ctag
) && file_dgname
&& strlen(file_dgname
))
550 (void) strncpy(ctag
, file_dgname
, MAX_RDC_HOST_SIZE
);
553 * making an exception here for users giving the "local"tag
554 * this overrides this error message. (rdc_islocal ! = 1)
556 if (!rdc_islocal
&& strlen(ctag
) &&
557 file_dgname
&& strlen(file_dgname
) &&
558 strncmp(ctag
, file_dgname
, MAX_RDC_HOST_SIZE
)) {
559 rdc_warn(NULL
, gettext("ctag \"%s\" does not "
560 "match disk group name \"%s\" of volume %s"), ctag
,
561 file_dgname
, localfile
);
566 * Do we have a non-volume managed disk without -C local specified?
568 if (!rdc_islocal
&& (!file_dgname
|| !strlen(file_dgname
))) {
569 rdc_err(NULL
, gettext("volume \"%s\" is not part"
570 " of a disk group,\nplease specify resource ctag\n"),
575 * Do we have a volume managed disk with -C local?
577 if (rdc_islocal
&& file_dgname
&& (strlen(file_dgname
) > 0)) {
578 rdc_err(NULL
, gettext(
579 "volume \"%s\" is part of a disk group\n"), localfile
);
583 * Local bitmap must also have same ctag.
585 localfile
= is_primary
? frombitmap
: tobitmap
;
586 bmp_dgname
= cfg_dgname(localfile
, bmp_buf
, sizeof (bmp_buf
));
587 if (bmp_dgname
&& strlen(bmp_dgname
))
588 rdc_check_dgislocal(bmp_dgname
);
591 * Assure that if the primary has a device group, so must the bitmap
593 if ((file_dgname
&& strlen(file_dgname
)) &&
594 (!bmp_dgname
|| !strlen(bmp_dgname
))) {
595 rdc_warn(NULL
, gettext("bitmap %s is not in disk group \"%s\""),
596 localfile
, rdc_islocal
< 1?file_dgname
:ctag
);
601 * Assure that if the if there is a ctag, it must match the bitmap
603 if (!rdc_islocal
&& strlen(ctag
) &&
604 bmp_dgname
&& strlen(bmp_dgname
) &&
605 strncmp(ctag
, bmp_dgname
, MAX_RDC_HOST_SIZE
)) {
606 rdc_warn(NULL
, gettext("ctag \"%s\" does not "
607 "match disk group name \"%s\" of bitmap %s"), ctag
,
608 bmp_dgname
, localfile
);
613 * If this is the SNDR primary and there is a local disk queue
615 if (is_primary
&& diskq
[0]) {
618 * Local disk queue must also have same ctag.
620 que_dgname
= cfg_dgname(diskq
, que_buf
, sizeof (que_buf
));
621 if (que_dgname
&& strlen(que_dgname
))
622 rdc_check_dgislocal(que_dgname
);
625 * Assure that if the primary has a device group, so must
628 if ((file_dgname
&& strlen(file_dgname
)) &&
629 (!que_dgname
|| !strlen(que_dgname
))) {
630 rdc_warn(NULL
, gettext("disk queue %s is not in disk "
631 "group \"%s\""), diskq
,
632 rdc_islocal
< 1?file_dgname
:ctag
);
637 * Assure that if the if there is a ctag, it must match
640 if (!rdc_islocal
&& strlen(ctag
) &&
641 que_dgname
&& strlen(que_dgname
) &&
642 strncmp(ctag
, que_dgname
, MAX_RDC_HOST_SIZE
)) {
643 rdc_warn(NULL
, gettext("ctag \"%s\" does not "
644 "match disk group name \"%s\" of disk queue %s"),
645 ctag
, que_dgname
, diskq
);
655 #define DISKQ_REWRITEG 2
657 * check that newq is compatable with the groups current disk queue.
658 * Newq is incompatable if it is set and the groups queue is set and the queues
661 * if newq is not set but should be, it will be set to the correct value.
663 * DISK_REWRITEG entire group needs to take new value of disk_queue
664 * DISKQ_OKAY newq contains a value that matches the group.
665 * DISKQ_FAIL disk queues are incompatible.
668 check_diskqueue(CFGFILE
*cfg
, char *newq
, char *newgroup
)
671 _sd_dual_pair_t pair
;
672 char *group
= pair
.group
;
673 char *diskqueue
= pair
.diskqueue
;
674 char buf
[CFG_MAX_BUF
];
675 char key
[CFG_MAX_KEY
];
676 int open_cfg
= cfg
== NULL
? 1 : 0;
679 if (newgroup
== NULL
|| *newgroup
== '\0') {
681 return (DISKQ_OKAY
); /* okay, */
682 newgroup
= "--nomatch--";
686 if ((cfg
= cfg_open(NULL
)) == NULL
)
688 gettext("unable to access configuration"));
689 if (!cfg_lock(cfg
, CFG_RDLOCK
))
690 rdc_err(NULL
, gettext("unable to lock configuration"));
696 (void) snprintf(key
, sizeof (key
), "sndr.set%d", setnumber
);
697 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
700 * I think this is quicker than
701 * having to double dip into the config
703 if (parse_cfg_buf(buf
, &pair
, NULL
))
704 rdc_err(NULL
, gettext("cfg input error"));
706 if (strncmp(group
, newgroup
, NSC_MAXPATH
) != 0) {
707 if (((strncmp(diskqueue
, newq
, NSC_MAXPATH
) == 0)) &&
708 (diskqueue
[0] != '\0')) {
716 if (diskqueue
[0] != '\0')
717 (void) strncpy(newq
, diskqueue
, NSC_MAXPATH
);
720 return (DISKQ_OKAY
); /* okay, */
725 if (diskqueue
[0] == '\0') /* no queue here */
726 return (DISKQ_REWRITEG
);
727 return (strncmp(diskqueue
, newq
, NSC_MAXPATH
)
728 == 0 ? DISKQ_OKAY
: DISKQ_FAIL
);
737 pair_diskqueue_check(int newpair
)
742 for (i
= 0; i
< newpair
; i
++) {
743 if (strcmp(pair_list
[i
].group
, pair_list
[newpair
].group
) != 0)
745 if (strcmp(pair_list
[i
].diskqueue
, pair_list
[newpair
].diskqueue
)
747 return (DISKQ_OKAY
); /* matches existing group */
748 if ((pair_list
[newpair
].group
[0] != '\0') &&
749 (pair_list
[newpair
].diskqueue
[0] != '\0') &&
750 (pair_list
[i
].diskqueue
[0] != '\0')) {
752 gettext("disk queue %s does not match %s "
753 "skipping set"), pair_list
[newpair
].diskqueue
,
754 pair_list
[i
].diskqueue
);
758 if ((strcmp(pair_list
[newpair
].diskqueue
, "") == 0) &&
759 pair_list
[newpair
].group
[0] != '\0') {
760 (void) strncpy(pair_list
[newpair
].diskqueue
,
761 pair_list
[i
].diskqueue
, NSC_MAXPATH
);
762 return (DISKQ_OKAY
); /* changed to existing group que */
764 if (strcmp(pair_list
[i
].diskqueue
, "") == 0) {
765 for (j
= 0; j
< newpair
; j
++) {
766 if ((pair_list
[j
].group
[0] != '\0') &&
767 (strncmp(pair_list
[j
].group
,
768 pair_list
[newpair
].group
,
769 NSC_MAXPATH
) == 0)) {
770 (void) strncpy(pair_list
[j
].diskqueue
,
771 pair_list
[newpair
].diskqueue
,
777 break; /* no problem with pair_list sets */
781 /* now check with already configured sets */
782 rc
= check_diskqueue(NULL
, pair_list
[newpair
].diskqueue
,
783 pair_list
[newpair
].group
);
784 if (rc
== DISKQ_REWRITEG
) {
785 for (i
= 0; i
< newpair
; i
++) {
786 if (strcmp(pair_list
[i
].group
,
787 pair_list
[newpair
].group
) != 0)
790 (void) strncpy(pair_list
[i
].diskqueue
,
791 pair_list
[newpair
].diskqueue
, NSC_MAXPATH
);
798 ii_set_exists(CFGFILE
*cfg
, char *ma
, char *sh
, char *bm
)
800 char buf
[CFG_MAX_BUF
];
801 char key
[CFG_MAX_KEY
];
802 char master
[NSC_MAXPATH
];
803 char shadow
[NSC_MAXPATH
];
804 char bitmap
[NSC_MAXPATH
];
808 (void) snprintf(key
, sizeof (key
), "ii.set%d", i
);
809 bzero(&master
, sizeof (master
));
810 bzero(&shadow
, sizeof (shadow
));
811 bzero(&bitmap
, sizeof (bitmap
));
812 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
814 (void) sscanf(buf
, "%s %s %s", master
, shadow
, bitmap
);
815 if (strcmp(master
, ma
) != 0)
817 if (strcmp(shadow
, sh
) != 0)
819 if (strcmp(bitmap
, bm
) != 0)
827 rdc_ii_config(int argc
, char **argv
)
836 char key
[CFG_MAX_KEY
];
837 char buf
[CFG_MAX_BUF
];
841 /* Parse the rest of the arguments to see what to do */
843 if (argc
- optind
!= 4) {
851 /* Delete an ndr_ii entry */
853 master
= argv
[++optind
];
854 shadow
= argv
[++optind
];
855 bitmap
= argv
[++optind
];
857 if ((cfg
= cfg_open(NULL
)) == NULL
)
859 gettext("unable to access configuration"));
860 if (!cfg_lock(cfg
, CFG_WRLOCK
))
861 rdc_err(NULL
, gettext("unable to lock configuration"));
864 /* get ndr_ii entries until a match is found */
869 (void) snprintf(key
, sizeof (key
),
870 "ndr_ii.set%d.secondary",
872 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
874 if (strcmp(buf
, master
) != 0)
877 /* Got a matching entry */
879 (void) snprintf(key
, sizeof (key
),
880 "ndr_ii.set%d.shadow",
882 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
884 if (strcmp(buf
, shadow
) != 0)
887 (void) snprintf(key
, sizeof (key
),
888 "ndr_ii.set%d.bitmap",
890 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
892 if (strcmp(buf
, bitmap
) != 0)
895 (void) snprintf(key
, sizeof (key
),
896 "ndr_ii.set%d", setnumber
);
897 if (cfg_put_cstring(cfg
, key
, NULL
, 0) < 0) {
899 gettext("unable to remove \"%s\" "
900 "from configuration storage: %s"),
901 key
, cfg_error(&sev
));
903 if (cfg_commit(cfg
) < 0)
905 gettext("ndr_ii set %s %s %s "
906 "not deconfigured."),
907 master
, shadow
, bitmap
);
909 spcs_log("sndr", NULL
,
910 gettext("ndr_ii set %s %s %s "
911 "has been deconfigured."),
912 master
, shadow
, bitmap
);
920 gettext("did not find matching ndr_ii "
921 "entry for %s %s %s"), master
, shadow
, bitmap
);
929 /* Add an ndr_ii entry */
931 master
= argv
[++optind
];
932 shadow
= argv
[++optind
];
933 bitmap
= argv
[++optind
];
935 if ((cfg
= cfg_open(NULL
)) == NULL
)
937 gettext("unable to access configuration"));
938 if (!cfg_lock(cfg
, CFG_WRLOCK
))
939 rdc_err(NULL
, gettext("unable to lock configuration"));
942 /* get ndr_ii entries in case a match is found */
947 (void) snprintf(key
, sizeof (key
),
948 "ndr_ii.set%d.secondary",
950 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
952 if (strcmp(buf
, master
) == 0) {
954 gettext("found matching ndr_ii "
955 "entry for %s"), master
);
959 * check to see if this is using a sndr bitmap.
960 * kind of a courtesy check, as the ii copy would fail anyway
961 * excepting the case where they had actually configured
962 * ii/sndr that way, in which case they are broken
970 * Checking local bitmaps
972 (void) snprintf(key
, sizeof (key
), "sndr.set%d.phost",
975 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
977 if (self_check(buf
)) {
978 (void) snprintf(key
, sizeof (key
),
979 "sndr.set%d.pbitmap",
982 (void) snprintf(key
, sizeof (key
),
983 "sndr.set%d.sbitmap",
987 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
990 if ((strcmp(buf
, bitmap
) == 0) ||
991 (strcmp(buf
, master
) == 0) ||
992 (strcmp(buf
, shadow
) == 0)) {
994 gettext("%s is already configured "
995 "as a Remote Mirror bitmap"), buf
);
998 if (!ii_set_exists(cfg
, master
, shadow
, bitmap
)) {
999 rdc_warn(NULL
, gettext("Point-in-Time Copy set "
1000 "%s %s %s is not already configured. Remote "
1001 "Mirror will attempt to configure this set when "
1002 "a sync is issued to it. The results of that "
1003 "operation will be in /var/adm/ds.log"),
1004 master
, shadow
, bitmap
);
1005 spcs_log("sndr", NULL
, gettext("Point-in-Time Copy set "
1006 "%s %s %s is not already configured. Remote "
1007 "Mirror will attempt to configure this set when "
1008 "a sync is issued to it. The results of that "
1009 "operation will be in /var/adm/ds.log"),
1010 master
, shadow
, bitmap
);
1012 spcs_log("sndr", NULL
, gettext("ndr_ii set "
1013 "%s %s %s has been configured."),
1014 master
, shadow
, bitmap
);
1018 * Prior to insertion in ndr_ii entry, if in a Sun Cluster
1019 * assure device groups are the same and cluster tag is set
1021 if (clustered
&& !rdc_islocal
) {
1022 char mst_dg
[NSC_MAXPATH
] = {0};
1023 char shd_dg
[NSC_MAXPATH
] = {0};
1024 char bmp_dg
[NSC_MAXPATH
] = {0};
1026 if (!(cfg_dgname(master
, mst_dg
, sizeof (mst_dg
)) &&
1027 cfg_dgname(shadow
, shd_dg
, sizeof (shd_dg
)) &&
1028 cfg_dgname(bitmap
, bmp_dg
, sizeof (bmp_dg
))))
1029 rdc_warn(NULL
, gettext("ndr_ii: %s %s %s are "
1030 "not in a device group"),
1031 master
, shadow
, bitmap
);
1032 else if (strcmp(mst_dg
, bmp_dg
) ||
1033 strcmp(mst_dg
, shd_dg
))
1034 rdc_warn(NULL
, gettext("ndr_ii: %s %s %s are "
1035 "not in different device groups"),
1036 master
, shadow
, bitmap
);
1038 cfg_resource(cfg
, shd_dg
);
1039 (void) snprintf(buf
, sizeof (buf
),
1040 "%s %s %s update %s",
1041 master
, shadow
, bitmap
, shd_dg
);
1044 (void) snprintf(buf
, sizeof (buf
), "%s %s %s update",
1045 master
, shadow
, bitmap
);
1048 if ((cfg_put_cstring(cfg
, "ndr_ii", buf
, strlen(buf
)) < 0) ||
1049 (cfg_commit(cfg
) < 0))
1050 rdc_warn(NULL
, gettext("unable to add \"%s\" to "
1051 "configuration storage: %s"),
1052 buf
, cfg_error(&sev
));
1065 check_rdcbitmap(int cmd
, char *hostp
, char *bmp
)
1071 char *host
, *pri
, *sec
, *sbm
, *bit
, *mas
, *sha
, *ovr
;
1072 char *shost
, *buf
, *que
;
1074 if ((cfg
= cfg_open(NULL
)) == NULL
)
1076 gettext("unable to access configuration"));
1077 if (!cfg_lock(cfg
, CFG_RDLOCK
))
1078 rdc_err(NULL
, gettext("unable to lock configuration"));
1081 * look into II config to see if this is being used elsewhere
1084 entries
= cfg_get_section(cfg
, &entry
, "ii");
1085 for (i
= 0; i
< entries
; i
++) {
1088 mas
= strtok(buf
, " "); /* master */
1089 sha
= strtok(NULL
, " "); /* shadow */
1090 bit
= strtok(NULL
, " "); /* bitmap */
1091 (void) strtok(NULL
, " "); /* mode */
1092 ovr
= strtok(NULL
, " "); /* overflow */
1095 * got master, shadow, overflow, and bitmap, now compare
1097 if ((strcmp(bmp
, mas
) == 0) ||
1098 (strcmp(bmp
, sha
) == 0) ||
1099 (strcmp(bmp
, ovr
) == 0) ||
1100 (strcmp(bmp
, bit
) == 0)) {
1102 gettext("bitmap %s is in use by"
1103 " Point-in-Time Copy"), bmp
);
1112 * and last but not least, make sure sndr is not using vol for anything
1115 entries
= cfg_get_section(cfg
, &entry
, "sndr");
1116 for (i
= 0; i
< entries
; i
++) {
1120 * I think this is quicker than
1121 * having to double dip into the config
1123 host
= strtok(buf
, " "); /* phost */
1124 pri
= strtok(NULL
, " "); /* primary */
1125 bit
= strtok(NULL
, " "); /* pbitmap */
1126 shost
= strtok(NULL
, " "); /* shost */
1127 sec
= strtok(NULL
, " "); /* secondary */
1128 sbm
= strtok(NULL
, " "); /* sbitmap */
1129 (void) strtok(NULL
, " "); /* type */
1130 (void) strtok(NULL
, " "); /* mode */
1131 (void) strtok(NULL
, " "); /* group */
1132 (void) strtok(NULL
, " "); /* cnode */
1133 (void) strtok(NULL
, " "); /* options */
1134 que
= strtok(NULL
, " "); /* diskq */
1136 if (cmd
== RDC_CMD_ENABLE
) {
1137 if (self_check(host
)) {
1138 if ((strcmp(bmp
, pri
) == 0) ||
1139 (strcmp(bmp
, que
) == 0) ||
1140 (strcmp(bmp
, bit
) == 0)) {
1142 gettext("bitmap %s is already "
1143 "in use by StorEdge Network Data "
1144 "Replicator"), bmp
);
1147 if ((strcmp(bmp
, sec
) == 0) ||
1148 (strcmp(bmp
, sbm
) == 0)) {
1150 gettext("bitmap %s is already "
1151 "in use by StorEdge Network Data "
1152 "Replicator"), bmp
);
1155 } else if (cmd
== RDC_CMD_RECONFIG
) {
1158 * read this logic 1000 times and consider
1159 * multi homed, one to many, many to one (marketing)
1160 * etc, etc, before changing
1162 if (self_check(hostp
)) {
1163 if (self_check(host
)) {
1164 if ((strcmp(bmp
, pri
) == 0) ||
1165 (strcmp(bmp
, que
) == 0) ||
1166 (strcmp(bmp
, bit
) == 0)) {
1168 gettext("bitmap %s is already "
1169 "in use by StorEdge Network "
1170 "Data Replicator"), bmp
);
1173 if ((strcmp(hostp
, shost
) == 0) &&
1174 (strcmp(bmp
, sec
) == 0) ||
1175 (strcmp(bmp
, sbm
) == 0)) {
1177 gettext("bitmap %s is already "
1178 "in use by StorEdge Network "
1179 "Data Replicator"), bmp
);
1183 } else { /* self_check(hostp) failed */
1184 if (self_check(host
)) {
1185 if ((strcmp(shost
, hostp
) == 0) &&
1186 (strcmp(bmp
, sec
) == 0) ||
1187 (strcmp(bmp
, sbm
) == 0)) {
1189 gettext("bitmap %s is already "
1190 "in use by StorEdge Network "
1191 "Data Replicator"), bmp
);
1194 if ((strcmp(host
, hostp
) == 0) &&
1195 (strcmp(bmp
, pri
) == 0) ||
1196 (strcmp(bmp
, que
) == 0) ||
1197 (strcmp(bmp
, bit
) == 0)) {
1199 gettext("bitmap %s is already "
1200 "in use by StorEdge Network "
1201 "Data Replicator"), bmp
);
1216 check_intrange(char *arg
) {
1219 for (i
= 0; i
< strlen(arg
); i
++) {
1220 if (arg
[i
] < '0' || arg
[i
] > '9') {
1221 rdc_warn(NULL
, "not a valid number, must be a "
1222 "decimal between 1 and %d", MAXINT
);
1227 i
= (int)strtol(arg
, NULL
, 10);
1228 if ((errno
) || (i
< 1) || (i
> MAXINT
)) {
1229 rdc_warn(NULL
, "not a valid number, must be a decimal "
1230 "between 1 and %d", MAXINT
);
1237 rewrite_group_diskqueue(CFGFILE
*cfg
, _sd_dual_pair_t
*pair
, char *diskqueue
)
1240 char buf
[CFG_MAX_BUF
];
1241 char key
[CFG_MAX_KEY
];
1242 _sd_dual_pair_t tmpair
;
1244 for (set
= 1; /*CSTYLED*/; set
++) {
1245 bzero(buf
, CFG_MAX_BUF
);
1246 bzero(&tmpair
, sizeof (tmpair
));
1248 (void) snprintf(key
, sizeof (key
), "sndr.set%d", set
);
1249 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
1252 if (parse_cfg_buf(buf
, &tmpair
, NULL
))
1254 if (pair
->group
&& pair
->group
[0]) {
1255 if (strcmp(pair
->group
, tmpair
.group
) != 0)
1256 continue; /* not the group we want */
1258 } else { /* no group specified */
1259 if (strcmp(pair
->thost
, tmpair
.thost
) != 0)
1261 if (strcmp(pair
->tfile
, tmpair
.tfile
) != 0)
1265 (void) sprintf(key
, "sndr.set%d.diskq", set
);
1267 if (cfg_put_cstring(cfg
, key
, diskqueue
,
1268 strlen(diskqueue
)) < 0) {
1269 perror(cfg_error(NULL
));
1275 diskq_subcmd(int subcmd
, char *qvol
, char *group_arg
, char *ctag_arg
,
1276 char *tohost_arg
, char *tofile_arg
)
1280 char key
[CFG_MAX_KEY
];
1281 char buf
[CFG_MAX_BUF
];
1285 _sd_dual_pair_t pair
;
1290 if ((cfg
= cfg_open(NULL
)) == NULL
)
1292 gettext("unable to access configuration"));
1294 if (!cfg_lock(cfg
, CFG_WRLOCK
))
1296 gettext("unable to lock configuration"));
1299 if (cfg_load_svols(cfg
) < 0 ||
1300 cfg_load_dsvols(cfg
) < 0 ||
1301 cfg_load_shadows(cfg
) < 0)
1303 gettext("Unable to parse config filer"));
1307 for (i
= 0; i
< rdc_maxsets
;) {
1310 bzero(buf
, CFG_MAX_BUF
);
1311 (void) snprintf(key
, sizeof (key
),
1312 "sndr.set%d", setnumber
);
1313 rc
= cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
);
1316 if (parse_cfg_buf(buf
, &pair
, NULL
))
1319 if (strlen(group_arg
) == 0) {
1320 if (strcmp(tohost_arg
, pair
.thost
) == 0 &&
1321 strcmp(tofile_arg
, pair
.tfile
) == 0) {
1322 (void) strcpy(group_arg
, pair
.group
);
1328 if (strcmp(group_arg
, pair
.group
) == 0) {
1336 if (strlen(group_arg
) == 0) {
1338 gettext("Unable to find %s:%s in "
1339 "configuration storage"),
1340 tohost_arg
, tofile_arg
);
1343 gettext("Unable to find group %s in "
1344 "configuration storage"), group_arg
);
1347 if (!resourced
&& strlen(pair
.ctag
)) { /* uh-oh... */
1348 cfg_unload_svols(cfg
);
1349 cfg_unload_dsvols(cfg
);
1350 cfg_unload_shadows(cfg
);
1352 cfg_resource(cfg
, pair
.ctag
);
1353 ctag
= strdup(pair
.ctag
);
1359 if (clustered
&& !rdc_islocal
) {
1360 if (strcmp(ctag_arg
, "") &&
1361 strncmp(ctag_arg
, pair
.ctag
, MAX_RDC_HOST_SIZE
))
1362 rdc_warn(NULL
, gettext("ctags %s and %s "
1363 "do not match, proceeding with operation based "
1364 "on existing set information"), ctag_arg
, ctag
);
1368 if (clustered
&& (ctag_check(pair
.fhost
, pair
.ffile
,
1369 pair
.fbitmap
, pair
.thost
, pair
.tfile
, pair
.tbitmap
,
1370 pair
.ctag
, qvol
) < 0))
1373 if (strlen(pair
.diskqueue
) > 0) {
1374 rdc_err(NULL
, gettext("Remote Mirror set already "
1375 "has a disk queue"));
1377 if (check_diskqueue(cfg
, qvol
, group_arg
) == DISKQ_FAIL
) {
1379 gettext("diskqueue %s is incompatible"), qvol
);
1381 if (rdc_operation(cfg
, pair
.fhost
, pair
.ffile
, pair
.fbitmap
,
1382 pair
.thost
, pair
.tfile
, pair
.tbitmap
, subcmd
, 0,
1383 pair
.directfile
, pair
.group
, pair
.ctag
, qvol
, &pair
.doasync
,
1385 if (cfg_vol_disable(cfg
, qvol
, ctag
, "sndr") < 0)
1386 rdc_warn(NULL
, gettext("Failed to remove disk "
1387 "queue [%s] from configuration"), qvol
);
1388 rdc_err(NULL
, gettext("Add disk queue operation "
1391 if (nsc_lookup(volhash
, qvol
) == NULL
) {
1392 if (cfg_vol_enable(cfg
, qvol
, ctag
, "sndr") < 0) {
1393 rdc_err(NULL
, gettext("Add disk queue "
1394 "operation failed"));
1397 rewrite_group_diskqueue(cfg
, &pair
, qvol
);
1399 spcs_log("sndr", NULL
, gettext("Remote Mirror: added "
1400 "diskqueue %s to set %s:%s and its group"), qvol
,
1401 pair
.thost
, pair
.tfile
);
1403 case RDC_OPT_FORCE_QINIT
:
1404 if (strlen(pair
.diskqueue
) == 0) {
1405 rdc_err(NULL
, gettext("Remote Mirror set does not "
1406 "have a disk queue"));
1408 subcmd
= RDC_CMD_INITQ
;
1409 option
= RDC_OPT_FORCE_QINIT
;
1410 if (rdc_operation(cfg
, pair
.fhost
, pair
.ffile
, pair
.fbitmap
,
1411 pair
.thost
, pair
.tfile
, pair
.tbitmap
, subcmd
, option
,
1412 pair
.directfile
, pair
.group
, pair
.ctag
, qvol
, &pair
.doasync
,
1418 if (strlen(pair
.diskqueue
) == 0) {
1419 rdc_err(NULL
, gettext("Remote Mirror set does not "
1420 "have a disk queue"));
1422 if (rdc_operation(cfg
, pair
.fhost
, pair
.ffile
, pair
.fbitmap
,
1423 pair
.thost
, pair
.tfile
, pair
.tbitmap
, subcmd
, 0,
1424 pair
.directfile
, pair
.group
, pair
.ctag
, qvol
, &pair
.doasync
,
1430 if (strlen(pair
.diskqueue
) == 0) {
1431 rdc_err(NULL
, gettext("Remote Mirror set does not "
1432 "have a disk queue"));
1434 if (rdc_operation(cfg
, pair
.fhost
, pair
.ffile
, pair
.fbitmap
,
1435 pair
.thost
, pair
.tfile
, pair
.tbitmap
, subcmd
, 0,
1436 pair
.directfile
, pair
.group
, pair
.ctag
, qvol
, &pair
.doasync
,
1440 if (cfg_vol_disable(cfg
, pair
.diskqueue
, ctag
, "sndr") < 0)
1441 rdc_warn(NULL
, gettext("Failed to remove disk queue "
1442 "[%s] from configuration"), pair
.diskqueue
);
1443 rewrite_group_diskqueue(cfg
, &pair
, place_holder
);
1445 spcs_log("sndr", NULL
, gettext("Remote Mirror: removed "
1446 "diskqueue from set %s:%s and its group"), pair
.thost
,
1450 if (strlen(pair
.diskqueue
) == 0) {
1451 rdc_err(NULL
, gettext("Remote Mirror set does not "
1452 "have a disk queue"));
1454 if (rdc_operation(cfg
, pair
.fhost
, pair
.ffile
, pair
.fbitmap
,
1455 pair
.thost
, pair
.tfile
, pair
.tbitmap
, subcmd
, 0,
1456 pair
.directfile
, pair
.group
, pair
.ctag
, qvol
, &pair
.doasync
,
1458 rdc_err(NULL
, gettext("Failed to remove disk queue"));
1460 if (cfg_vol_disable(cfg
, pair
.diskqueue
, ctag
, "sndr") < 0)
1461 rdc_warn(NULL
, gettext("Failed to remove disk queue "
1462 "[%s] from configuration"), pair
.diskqueue
);
1464 rewrite_group_diskqueue(cfg
, &pair
, place_holder
);
1466 spcs_log("sndr", NULL
, gettext("Remote Mirror: forcibly "
1467 "removed diskqueue from set %s:%s and its group "),
1468 pair
.thost
, pair
.tfile
);
1471 if (clustered
&& (ctag_check(pair
.fhost
, pair
.ffile
,
1472 pair
.fbitmap
, pair
.thost
, pair
.tfile
, pair
.tbitmap
,
1473 pair
.ctag
, qvol
) < 0))
1476 if (strlen(pair
.diskqueue
) == 0) {
1477 rdc_err(NULL
, gettext("Remote Mirror set does not "
1478 "have a disk queue"));
1480 if (rdc_operation(cfg
, pair
.fhost
, pair
.ffile
, pair
.fbitmap
,
1481 pair
.thost
, pair
.tfile
, pair
.tbitmap
, RDC_CMD_REMQ
, 0,
1482 pair
.directfile
, pair
.group
, pair
.ctag
, qvol
, &pair
.doasync
,
1484 rdc_err(NULL
, gettext("Failed to remove disk queue"));
1486 if (cfg_vol_disable(cfg
, pair
.diskqueue
, ctag
, "sndr") < 0)
1487 rdc_warn(NULL
, gettext("Failed to remove disk queue "
1488 "[%s] from configuration"), pair
.diskqueue
);
1490 rewrite_group_diskqueue(cfg
, &pair
, place_holder
);
1492 /* commit here, enable may fail */
1493 if (cfg_commit(cfg
) < 0) {
1494 rdc_err(NULL
, gettext("commit replace disk queue %s "
1495 "with %s failed"), pair
.diskqueue
, qvol
);
1498 if (check_diskqueue(cfg
, qvol
, group_arg
) == DISKQ_FAIL
) {
1500 gettext("cannot replace disk queue %s with %s"),
1501 pair
.diskqueue
, qvol
);
1503 if (rdc_operation(cfg
, pair
.fhost
, pair
.ffile
, pair
.fbitmap
,
1504 pair
.thost
, pair
.tfile
, pair
.tbitmap
, RDC_CMD_ADDQ
, 0,
1505 pair
.directfile
, pair
.group
, pair
.ctag
, qvol
, &pair
.doasync
,
1507 if (cfg_vol_disable(cfg
, qvol
, ctag
, "sndr") < 0)
1508 rdc_warn(NULL
, gettext("Failed to remove disk "
1509 "queue [%s] from configuration"), qvol
);
1510 rdc_err(NULL
, gettext("Failed to add new disk queue"));
1512 if (nsc_lookup(volhash
, qvol
) == NULL
)
1513 if (cfg_vol_enable(cfg
, qvol
, ctag
, "sndr") < 0) {
1514 rdc_err(NULL
, gettext("Replace disk queue "
1515 "operation failed"));
1518 rewrite_group_diskqueue(cfg
, &pair
, qvol
);
1520 spcs_log("sndr", NULL
, gettext("Remote Mirror: replaced "
1521 "diskqueue for set %s:%s and its group with %s"),
1522 pair
.thost
, pair
.tfile
, qvol
);
1526 cfg_unload_svols(cfg
);
1527 cfg_unload_dsvols(cfg
);
1528 cfg_unload_shadows(cfg
);
1531 if (cfg_commit(cfg
) < 0)
1532 rdc_err(NULL
, gettext("commit failed on disk queue operation"));
1539 spcslog_sync(rdcconfig_t
*sets
, int start
, int type
)
1541 rdcconfig_t
*setp
= sets
;
1545 spcs_log("sndr", NULL
,
1546 gettext("%s %s %s %s %s %s %s %s\nSync Started"),
1547 program
, rdc_decode_flag(RDC_CMD_COPY
, type
),
1548 setp
->phost
, setp
->pfile
, setp
->pbmp
,
1549 setp
->shost
, setp
->sfile
, setp
->sbmp
);
1551 spcs_log("sndr", NULL
,
1552 gettext("%s %s %s %s %s %s %s %s\nSync Ended"),
1553 program
, rdc_decode_flag(RDC_CMD_COPY
, type
),
1554 setp
->phost
, setp
->pfile
, setp
->pbmp
,
1555 setp
->shost
, setp
->sfile
, setp
->sbmp
);
1562 spcslog_tunable(char *shost
, char *svol
)
1564 if (qblock
== RDC_OPT_SET_QNOBLOCK
)
1565 spcs_log("sndr", NULL
, gettext("diskqueue "
1566 "set to non blocking for %s:%s and any members "
1567 "of it's group"), shost
, svol
);
1568 else if (qblock
== RDC_OPT_CLR_QNOBLOCK
)
1569 spcs_log("sndr", NULL
, gettext("diskqueue "
1570 "set to blocking for %s:%s and any members "
1571 "of it's group"), shost
, svol
);
1574 spcs_log("sndr", NULL
, gettext("maxqfbas set to %d for %s:%s"),
1575 maxqfbas
, shost
, svol
);
1577 spcs_log("sndr", NULL
, gettext("maxwrites set to %d for %s:%s"),
1578 maxqitems
, shost
, svol
);
1580 spcs_log("sndr", NULL
, gettext("%d async threads configured "
1581 "for %s:%s"), asyncthr
, shost
, svol
);
1585 set_qblock(char *blockarg
)
1587 if (strcmp(blockarg
, "block") == 0)
1588 qblock
= RDC_OPT_CLR_QNOBLOCK
;
1589 else if (strcmp(blockarg
, "noblock") == 0)
1590 qblock
= RDC_OPT_SET_QNOBLOCK
;
1598 rdc_force_disable(CFGFILE
*cfg
, char *phost
, char *pvol
, char *pbmp
,
1599 char *shost
, char *svol
, char *sbmp
, char *ctag
, char *lhname
)
1602 spcs_s_info_t ustatus
;
1604 char *datavol
= NULL
;
1605 char *bmpvol
= NULL
;
1609 /* are we on the primary or secondary host? */
1610 if (ctag
&& *ctag
&& *lhname
) {
1611 if (strcmp(phost
, lhname
) == 0) {
1613 } else if (strcmp(shost
, lhname
) == 0) {
1616 } else if (self_check(phost
)) {
1618 } else if (self_check(shost
)) {
1625 } else if (on_sec
) {
1629 rdc_err(NULL
, gettext("Unable to determine whether current "
1630 "node is primary or secondary"));
1633 /* set up parms structure */
1634 parms
.command
= RDC_CMD_DISABLE
;
1635 (void) strncpy(parms
.rdc_set
->primary
.intf
, phost
, MAX_RDC_HOST_SIZE
);
1636 (void) strncpy(parms
.rdc_set
->primary
.file
, pvol
, NSC_MAXPATH
);
1637 (void) strncpy(parms
.rdc_set
->secondary
.intf
, shost
, MAX_RDC_HOST_SIZE
);
1638 (void) strncpy(parms
.rdc_set
->secondary
.file
, svol
, NSC_MAXPATH
);
1639 ustatus
= spcs_s_ucreate();
1640 parms
.options
= RDC_OPT_FORCE_DISABLE
;
1643 * We are now going to 'force' the kernel to disable the set. By
1644 * setting the RDC_OPT_FORCE_DISABLE flag, the kernel will bypass some
1645 * of the checks that are normally done when attempting to disable
1646 * a set. We need to do this force option in a cluster environment
1647 * when the logical hostname for the primary or secondary volume
1648 * is no longer available.
1650 spcs_log("sndr", NULL
, "%s sndradm -d %s %s %s %s %s %s",
1651 gettext("FORCE DISABLE"), phost
, pvol
, pbmp
, shost
, svol
, sbmp
);
1652 rdc_warn(NULL
, gettext("Forcing set disable"));
1653 if (RDC_IOCTL(RDC_CONFIG
, &parms
, 0, 0, 0, 0, ustatus
) != SPCS_S_OK
)
1654 rdc_warn(&ustatus
, gettext("set %s:%s not enabled in kernel"),
1657 /* if we get to this point, then a set was disabled. try sv-disable */
1658 vc
= nsc_lookup(volhash
, datavol
);
1659 if (vc
&& (1 == vc
->count
))
1660 if (cfg_vol_disable(cfg
, datavol
, ctag
, "sndr") < 0)
1661 rdc_warn(NULL
, gettext("Failed to remove data volume "
1662 "[%s] from configuration"), datavol
);
1663 vc
= nsc_lookup(volhash
, bmpvol
);
1664 if (vc
&& (1 == vc
->count
))
1665 if (cfg_vol_disable(cfg
, bmpvol
, ctag
, "sndr") < 0)
1666 rdc_warn(NULL
, gettext("Failed to remove bitmap "
1667 "[%s] from configuration"), bmpvol
);
1671 check_rdcsecondary(char *secondary
)
1680 if ((cfg
= cfg_open(NULL
)) == NULL
)
1682 gettext("error opening config"));
1683 if (!cfg_lock(cfg
, CFG_RDLOCK
))
1684 rdc_err(NULL
, gettext("error locking config"));
1687 entries
= cfg_get_section(cfg
, &entry
, "ii");
1688 for (i
= 0; i
< entries
; i
++) {
1691 (void) strtok(buf
, " "); /* master */
1692 sha
= strtok(NULL
, " "); /* shadow */
1693 if (strcmp(secondary
, sha
) == 0) {
1695 gettext("secondary %s is in use by"
1696 " Point-in-Time Copy"), secondary
);
1706 main(int argc
, char *argv
[])
1708 char config_file
[FILENAME_MAX
];
1709 char fromhost
[MAX_RDC_HOST_SIZE
];
1710 char tohost
[MAX_RDC_HOST_SIZE
];
1711 char fromfile
[NSC_MAXPATH
];
1712 char tofile
[NSC_MAXPATH
];
1713 char frombitmap
[NSC_MAXPATH
];
1714 char tobitmap
[NSC_MAXPATH
];
1715 char directfile
[NSC_MAXPATH
];
1716 char group
[NSC_MAXPATH
];
1717 char ctag
[MAX_RDC_HOST_SIZE
];
1718 char options_cfg
[CFG_MAX_BUF
];
1719 char fromnetaddr
[RDC_MAXADDR
];
1720 char tonetaddr
[RDC_MAXADDR
];
1721 char tmphost
[MAX_RDC_HOST_SIZE
];
1722 char tmpfile
[NSC_MAXPATH
];
1723 char tmpbitmap
[NSC_MAXPATH
];
1724 char diskqueue
[NSC_MAXPATH
];
1725 char lhname
[MAX_RDC_HOST_SIZE
];
1727 rdc_version_t rdc_version
;
1752 CFGFILE
*cfg
= NULL
;
1755 char key
[CFG_MAX_KEY
];
1756 char buf
[CFG_MAX_BUF
];
1757 char ctag_arg
[MAX_RDC_HOST_SIZE
];
1758 char group_arg
[NSC_MAXPATH
];
1759 int file_format
= 0;
1761 int diskq_group
= DISKQ_OKAY
;
1763 char *ctag_p
, *group_p
, *diskqueue_p
;
1766 int checksetfields
= -1;
1767 nsc_off_t boffset
= 0;
1769 rdcconfig_t
*sets
= NULL
;
1770 rdcconfig_t
*sets_p
= NULL
;
1771 rdc_rc_t
*rclist
= NULL
;
1772 rdc_rc_t
*rcp
= NULL
;
1773 int host_not_found
= 0;
1775 (void) setlocale(LC_ALL
, "");
1776 (void) textdomain("rdc");
1777 role_env
= getenv("SNDR_ROLE_REVERSE");
1778 if (role_env
&& strcmp(role_env
, "sndr_allow_reverse") == 0)
1781 program
= basename(argv
[0]);
1783 rc
= rdc_check_release(&required
);
1786 gettext("unable to determine the current "
1787 "Solaris release: %s\n"), strerror(errno
));
1788 } else if (rc
== FALSE
) {
1790 gettext("incorrect Solaris release (requires %s)\n"),
1794 if ((clustered
= cfg_iscluster()) < 0) {
1795 rdc_err(NULL
, gettext("unable to ascertain environment"));
1798 (void) strcpy(ctag_arg
, "");
1799 (void) strcpy(group_arg
, "");
1800 bzero(ctag
, MAX_RDC_HOST_SIZE
);
1801 bzero(reconfig_ctag
, MAX_RDC_HOST_SIZE
);
1802 bzero(diskqueue
, NSC_MAXPATH
);
1804 rdc_maxsets
= rdc_get_maxsets();
1805 if (rdc_maxsets
== -1) {
1807 gettext("unable to get maxsets value from kernel"));
1810 pair_list
= calloc(rdc_maxsets
, sizeof (*pair_list
));
1811 if (pair_list
== NULL
) {
1813 gettext("unable to allocate pair_list array for %d sets"),
1817 bzero(group
, sizeof (group
));
1818 bzero(diskqueue
, sizeof (diskqueue
));
1823 getopt(argc
, argv
, "A:B:C:D:EF:HIO:PRUW:a:bdef:g:hilmno:pq:rsuvw"))
1825 getopt(argc
, argv
, "A:B:C:D:EF:HIO:PRUW:a:bdef:g:hilmno:pq:rsuvw"))
1830 if (!allow_role
|| flag
) {
1836 flag
= RDC_BITMAPOP
;
1839 /* 'h' was already assigned */
1842 flag
= RDC_CMD_HEALTH
;
1845 /* List or edit ndr_ii configuration entries */
1851 flag
= RDC_CMD_RECONFIG
;
1854 case 'U': /* UDP support */
1859 if (flag
&& flag
!= RDC_CMD_TUNABLE
)
1861 flag
= RDC_CMD_TUNABLE
;
1863 if (check_intrange(optarg
))
1864 maxqfbas
= atoi(optarg
);
1870 if (flag
&& flag
!= RDC_CMD_TUNABLE
)
1872 flag
= RDC_CMD_TUNABLE
;
1874 if (check_intrange(optarg
))
1875 maxqitems
= atoi(optarg
);
1881 if (flag
&& flag
!= RDC_CMD_TUNABLE
)
1883 flag
= RDC_CMD_TUNABLE
;
1885 if (check_intrange(optarg
))
1886 asyncthr
= atoi(optarg
);
1892 if (flag
&& flag
!= RDC_CMD_TUNABLE
)
1894 flag
= RDC_CMD_TUNABLE
;
1896 if (set_qblock(optarg
)) {
1903 if (flag
&& flag
!= RDC_CMD_TUNABLE
)
1905 flag
= RDC_CMD_TUNABLE
;
1906 if (strcmp(optarg
, "off") == 0)
1907 autosync
= AUTOSYNC_OFF
;
1908 else if (strcmp(optarg
, "on") == 0)
1909 autosync
= AUTOSYNC_ON
;
1915 (void) strncpy(ctag_arg
, optarg
,
1917 process_clocal(ctag_arg
);
1922 if (flag
== RDC_CMD_ENABLE
)
1925 (void) strncpy(group_arg
, optarg
, NSC_MAXPATH
);
1926 verify_groupname(group_arg
);
1937 flag
= RDC_CMD_DISABLE
;
1942 flag
= RDC_CMD_ENABLE
;
1943 iflag
|= RDC_OPT_SETBMP
;
1948 flag
= RDC_CMD_ENABLE
;
1949 iflag
|= RDC_OPT_CLRBMP
;
1953 (void) strcpy(config_file
, optarg
);
1967 flag
= RDC_CMD_COPY
;
1968 iflag
|= RDC_OPT_FULL
;
1973 if (!allow_role
|| oflag
) {
1978 oflag
= RDC_BITMAPOR
;
1980 oflag
= RDC_BITMAPSET
;
1982 boffset
= strtoull(optarg
, NULL
, 0);
1998 flag
= RDC_CMD_INITQ
;
2010 iflag
|= RDC_OPT_REVERSE
;
2015 flag
= RDC_CMD_STATUS
;
2016 nflag
= 1; /* No prompt for a status */
2021 flag
= RDC_CMD_COPY
;
2022 iflag
|= RDC_OPT_UPDATE
;
2033 flag
= RDC_CMD_WAIT
;
2040 if (inval
|| ((flag
!= RDC_BITMAPOP
) && oflag
)) {
2041 rdc_warn(NULL
, gettext("invalid argument combination"));
2045 if (flag
&& Iflag
) {
2046 /* Mutually incompatible */
2052 rdc_ii_config(argc
, argv
);
2057 spcs_s_info_t ustatus
;
2059 ustatus
= spcs_s_ucreate();
2060 rc
= RDC_IOCTL(RDC_VERSION
, &rdc_version
, 0, 0, 0, 0, ustatus
);
2061 if (rc
== SPCS_S_ERROR
) {
2062 rdc_err(&ustatus
, gettext("statistics error"));
2064 spcs_s_ufree(&ustatus
);
2066 (void) printf(gettext("Remote Mirror version %d.%d.%d.%d\n"),
2067 rdc_version
.major
, rdc_version
.minor
,
2068 rdc_version
.micro
, rdc_version
.baseline
);
2070 if (rdc_version
.micro
) {
2071 (void) printf(gettext(
2072 "Remote Mirror version %d.%d.%d\n"),
2077 (void) printf(gettext("Remote Mirror version %d.%d\n"),
2078 rdc_version
.major
, rdc_version
.minor
);
2084 if (!(flag
|| pflag
) || errflag
) {
2089 if (pflag
&& !fflag
&& (argc
- optind
) == 0) {
2090 /* print with no set specified */
2091 exit(rdc_print(file_format
, verbose
,
2092 group_arg
, ctag_arg
, NULL
, NULL
, NULL
));
2095 if (qflag
) { /* change disk queue setting */
2100 char tohost_arg
[MAX_RDC_HOST_SIZE
];
2101 char tofile_arg
[NSC_MAXPATH
];
2103 if (strcmp("a", qarg
) == 0) {
2104 subcmd
= RDC_CMD_ADDQ
;
2106 } else if (strcmp("d", qarg
) == 0) {
2107 subcmd
= RDC_CMD_REMQ
;
2109 } else if (strcmp("r", qarg
) == 0) {
2110 subcmd
= RDC_CMD_REPQ
;
2113 rdc_warn(NULL
, " %s Invalid qopt", qarg
);
2117 if (strlen(group_arg
) == 0) {
2118 /* pick out single set as shost:svol */
2119 ptr
= strtok(argv
[qflag
+ offset
], ":");
2121 (void) strncpy(tohost_arg
, ptr
,
2124 rdc_warn(NULL
, gettext("Bad host specified"));
2128 ptr
= strtok(NULL
, ":");
2130 (void) strncpy(tofile_arg
, ptr
, NSC_MAXPATH
);
2132 rdc_warn(NULL
, gettext("Bad set specified"));
2139 if ((qvol
== NULL
) && (subcmd
!= RDC_CMD_REMQ
)) {
2140 rdc_warn(NULL
, gettext("missing queue volume"));
2144 diskq_subcmd(subcmd
, qvol
, group_arg
, ctag_arg
,
2145 tohost_arg
, tofile_arg
);
2149 if (flag
== RDC_CMD_RECONFIG
&& !fflag
) {
2150 /* See what is to be reconfigured */
2151 if (argc
- optind
== 0)
2152 flag
= RDC_CMD_RESET
;
2154 if (argc
- optind
< 2) {
2158 c
= *argv
[optind
++];
2159 if (argv
[optind
-1][1] != '\0') {
2165 if (argc
- optind
< 2) {
2169 if (*argv
[optind
] == 'p')
2170 reconfig_pbitmap
= argv
[++optind
];
2171 else if (*argv
[optind
] == 's')
2172 reconfig_sbitmap
= argv
[++optind
];
2181 reconfig_direct
= argv
[optind
++];
2185 reconfig_group
= argv
[optind
++];
2186 verify_groupname(reconfig_group
);
2190 (void) strncpy(reconfig_ctag
,
2191 argv
[optind
++], MAX_RDC_HOST_SIZE
);
2192 process_clocal(reconfig_ctag
);
2199 if (strcmp(argv
[optind
], "sync") == 0)
2200 reconfig_doasync
= 0;
2201 else if (strcmp(argv
[optind
], "async") == 0)
2202 reconfig_doasync
= 1;
2211 iflag
|= RDC_OPT_REVERSE_ROLE
;
2222 if ((argc
- optind
) != 0) {
2227 if ((argc
- optind
) == 0) {
2228 /* Use libcfg to figure out what to operate on */
2231 rdc_warn(NULL
, gettext("using current config"));
2235 if ((argc
- optind
) < 8 && (argc
- optind
) != 1) {
2243 if (flag
== RDC_CMD_ADDQ
||
2244 flag
== RDC_CMD_REMQ
||
2245 flag
== RDC_CMD_KILLQ
||
2246 flag
== RDC_CMD_INITQ
) {
2247 rdc_err(NULL
, gettext("can not use current config "
2248 "for disk queue operations"));
2251 if (flag
== RDC_CMD_ADDQ
||
2252 flag
== RDC_CMD_REMQ
||
2253 flag
== RDC_CMD_KILLQ
||
2254 flag
== RDC_CMD_INITQ
) {
2255 rdc_err(NULL
, gettext("can not use a config file "
2256 "for disk queue operations"));
2260 if (flag
== RDC_CMD_ENABLE
) {
2261 rdc_err(NULL
, gettext("can not use current config "
2262 "for enable command"));
2264 if ((flag
== RDC_CMD_RECONFIG
) && (reconfig_pbitmap
||
2265 reconfig_sbitmap
)) {
2266 rdc_err(NULL
, gettext("can not use current config "
2267 "for bitmap reconfiguration"));
2269 if (flag
== RDC_BITMAPOP
) {
2270 rdc_err(NULL
, gettext("can not use current config "
2271 "for bitmap set command"));
2273 pairs
= read_libcfg(flag
, group_arg
, ctag_arg
);
2275 (void) fprintf(stderr
,
2276 gettext("no matching Remote Mirror sets found "
2280 } else if (!fflag
) {
2286 * or something like this for example:
2288 * fromhost fromfile frombitmap tohost tofile tobitmap ip sync
2292 if (argc
- optind
== 1) {
2293 char tohost_arg
[MAX_RDC_HOST_SIZE
];
2294 char tofile_arg
[NSC_MAXPATH
];
2298 if (flag
== RDC_CMD_ENABLE
) {
2300 gettext("must specify full set details for "
2303 ptr
= strtok(argv
[optind
], ":");
2305 (void) strncpy(tohost_arg
, ptr
,
2308 rdc_err(NULL
, gettext("Bad host specified"));
2310 ptr
= strtok(NULL
, ":");
2312 (void) strncpy(tofile_arg
, ptr
, NSC_MAXPATH
);
2314 rdc_err(NULL
, gettext("Bad set specified"));
2317 /* Now look up tohost:tofile via libcfg */
2319 if ((cfg
= cfg_open(NULL
)) == NULL
)
2321 gettext("unable to access configuration"));
2323 if (!cfg_lock(cfg
, CFG_RDLOCK
))
2325 gettext("unable to lock configuration"));
2330 for (i
= 0; i
< rdc_maxsets
;) {
2333 bzero(buf
, CFG_MAX_BUF
);
2334 (void) snprintf(key
, sizeof (key
),
2335 "sndr.set%d", setnumber
);
2336 rc
= cfg_get_cstring(cfg
, key
, buf
,
2341 (void) snprintf(key
, sizeof (key
),
2342 "sndr.set%d.shost", setnumber
);
2343 (void) cfg_get_cstring(cfg
, key
, tohost
,
2345 if (strncmp(tohost
, tohost_arg
, NSC_MAXPATH
))
2348 (void) snprintf(key
, sizeof (key
),
2349 "sndr.set%d.secondary", setnumber
);
2350 (void) cfg_get_cstring(cfg
, key
, tofile
,
2352 if (strncmp(tofile
, tofile_arg
, NSC_MAXPATH
))
2357 (void) snprintf(key
, sizeof (key
),
2358 "sndr.set%d.phost", setnumber
);
2359 (void) cfg_get_cstring(cfg
, key
, fromhost
,
2362 (void) snprintf(key
, sizeof (key
),
2363 "sndr.set%d.primary", setnumber
);
2364 (void) cfg_get_cstring(cfg
, key
, fromfile
,
2367 (void) snprintf(key
, sizeof (key
),
2368 "sndr.set%d.pbitmap", setnumber
);
2369 (void) cfg_get_cstring(cfg
, key
, frombitmap
,
2370 sizeof (frombitmap
));
2372 (void) snprintf(key
, sizeof (key
),
2373 "sndr.set%d.sbitmap", setnumber
);
2374 (void) cfg_get_cstring(cfg
, key
, tobitmap
,
2377 (void) snprintf(key
, sizeof (key
),
2378 "sndr.set%d.type", setnumber
);
2379 (void) cfg_get_cstring(cfg
, key
, directfile
,
2380 sizeof (directfile
));
2381 if (strcmp(directfile
, "ip") == 0)
2382 (void) strcpy(directfile
, "");
2384 (void) snprintf(key
, sizeof (key
),
2385 "sndr.set%d.mode", setnumber
);
2386 (void) cfg_get_cstring(
2387 cfg
, key
, mode
, sizeof (mode
));
2389 (void) snprintf(key
, sizeof (key
),
2390 "sndr.set%d.group", setnumber
);
2391 (void) cfg_get_cstring(cfg
, key
, group
,
2393 if (strcmp(group_arg
, "") &&
2394 strncmp(group_arg
, group
, NSC_MAXPATH
))
2396 (void) snprintf(key
, sizeof (key
),
2397 "sndr.set%d.cnode", setnumber
);
2398 (void) cfg_get_cstring(
2399 cfg
, key
, ctag
, sizeof (ctag
));
2400 if ((strlen(ctag_arg
) > 0) &&
2401 (strcmp(ctag_arg
, ctag
) != 0))
2403 gettext("ctags %s and %s "
2404 "do not match"), ctag_arg
, ctag
);
2406 if (strcmp(mode
, "sync") == 0)
2408 else if (strcmp(mode
, "async") == 0)
2412 gettext("set %s:%s neither sync "
2413 "nor async"), tohost
, tofile
);
2420 gettext("set %s:%s not found in config"),
2421 tohost_arg
, tofile_arg
);
2425 (void) strncpy(fromhost
, argv
[optind
],
2427 (void) strncpy(fromfile
, argv
[optind
+1], NSC_MAXPATH
);
2428 (void) strncpy(frombitmap
, argv
[optind
+2], NSC_MAXPATH
);
2429 (void) strncpy(tohost
, argv
[optind
+3],
2431 (void) strncpy(tofile
, argv
[optind
+4], NSC_MAXPATH
);
2432 (void) strncpy(tobitmap
, argv
[optind
+5], NSC_MAXPATH
);
2434 /* Check the length of entries from the command line */
2435 if ((fromhost
[MAX_RDC_HOST_SIZE
- 1] != '\0') ||
2436 (tohost
[MAX_RDC_HOST_SIZE
- 1] != '\0')) {
2438 gettext("hostname is longer than %d "
2439 "characters\n"), (MAX_RDC_HOST_SIZE
- 1));
2442 /* Check if it's ip address -- not allowed */
2443 if ((inet_addr(fromhost
) != (in_addr_t
)(-1)) ||
2444 (inet_addr(tohost
) != (in_addr_t
)(-1))) {
2445 rdc_err(NULL
, gettext(
2446 "The hostname specified is invalid.\n"
2447 "See 'man inet(3SOCKET)'"));
2450 if ((fromfile
[NSC_MAXPATH
- 1] != '\0') ||
2451 (tofile
[NSC_MAXPATH
- 1] != '\0') ||
2452 (frombitmap
[NSC_MAXPATH
- 1] != '\0') ||
2453 (tobitmap
[NSC_MAXPATH
- 1] != '\0')) {
2454 rdc_err(NULL
, gettext("device name is longer "
2455 "than %d characters\n"), (NSC_MAXPATH
- 1));
2458 if (argv
[optind
+6][0] == '/') {
2460 (void) strncpy(directfile
, argv
[optind
+6],
2462 } else if (strcmp(argv
[optind
+6], "ip") != 0) {
2464 if (strcmp(argv
[optind
+6], "ip") != 0) {
2469 (void) strcpy(directfile
, "ip");
2471 if (strcmp(argv
[optind
+7], "sync") == 0)
2473 else if (strcmp(argv
[optind
+7], "async") == 0)
2481 * At this point, we could have a set which is
2482 * clustered, but neither a 'C ctag' or '-C ctag' has
2483 * been specified. To avoid clobbering the ctag if a
2484 * dscfg operation is done in the future, we should get
2485 * the ctag out of the config at this point. To do this,
2486 * set the cluster resource filter to NULL to look at
2487 * all sets in the config, pulling out the ctag for the
2488 * set matching shost:svol. If the set is not found,
2489 * fail here. Note, we skip this set on an enable as the
2490 * set is not yet in the config, so no need to waste
2493 if ((argc
- optind
== 8) && clustered
&&
2494 (flag
!= RDC_CMD_ENABLE
)) {
2496 char key
[CFG_MAX_KEY
];
2498 if ((cfg
= cfg_open(NULL
)) == NULL
) {
2500 gettext("unable to access configuration"));
2502 if (!cfg_lock(cfg
, CFG_RDLOCK
)) {
2504 gettext("unable to lock configuration"));
2507 cfg_resource(cfg
, NULL
);
2510 find_setnumber_in_libcfg(cfg
, NULL
, tohost
,
2514 gettext("unable to find Remote "
2520 (void) snprintf(key
, sizeof (key
),
2521 "sndr.set%d.cnode", setnumber
);
2522 if (cfg_get_cstring(cfg
, key
, ctag_arg
,
2523 MAX_RDC_HOST_SIZE
) < 0) {
2526 gettext("unable to determine ctag "
2527 "for Remote Mirror set %s:%s"),
2531 rdc_islocal
= strcmp(ctag_arg
, "-") ? 0 : 1;
2536 extra_argc
= argc
- optind
;
2537 if (extra_argc
< 8 || extra_argc
> 14 ||
2538 extra_argc
% 2 != 0) {
2544 * Loop through all of the extra arguments specified
2545 * on the command line, setting the appropriate values
2546 * for valid entries. If an unrecognized argument is
2547 * detected, abort with error. Note: This hack should be
2548 * removed and we should not accept these entries as
2549 * arguments, they should be passed in as switches.
2551 for (i
= (8 + optind
); i
< argc
; i
+= 2) {
2552 /* string case statement */
2553 if (strcmp(argv
[i
], "g") == 0) {
2554 (void) strncpy(group
, argv
[i
+ 1],
2556 if (group
[NSC_MAXPATH
- 1] != '\0') {
2557 rdc_err(NULL
, gettext("group name is "
2558 "longer than %d characters\n"),
2561 } else if (strcmp(argv
[i
], "C") == 0) {
2566 (void) strncpy(ctag
, argv
[i
+ 1],
2569 if (ctag
[MAX_RDC_HOST_SIZE
- 1] != '\0') {
2570 rdc_err(NULL
, gettext("cluster name "
2571 "is longer than %d characters\n"),
2572 (MAX_RDC_HOST_SIZE
- 1));
2574 process_clocal(ctag
);
2577 * well here is something.
2578 * what if they went sndradm -C local
2579 * host a b host a b ip sync C foobar?
2580 * they might be confused
2581 * lets stop them if ctag_arg and ctag
2582 * don't match and forgive if they are
2583 * the same, below also.
2585 if ((strlen(ctag_arg
) > 0) &&
2586 (strcmp(ctag_arg
, ctag
) != 0)) {
2587 rdc_err(NULL
, gettext("ctags "
2588 "%s and %s do not match "),
2592 } else if (strcmp(argv
[i
], "q") == 0) {
2593 (void) strncpy(diskqueue
, argv
[i
+ 1],
2595 if (diskqueue
[NSC_MAXPATH
- 1] != '\0') {
2596 rdc_err(NULL
, gettext("diskq name is "
2597 "longer than %d characters\n"),
2601 /* Unrecognized argument */
2609 * Are we able to determine the existance of either
2610 * of these host addresses?
2612 if (gethost_netaddrs(fromhost
, tohost
,
2613 (char *)&fromnetaddr
, (char *)&tonetaddr
) < 0) {
2614 (void) fprintf(stderr
, "\n");
2615 rdc_warn(NULL
, gettext("unable to determine IP "
2616 "addresses for either host %s or host %s"),
2619 if (flag
!= RDC_CMD_DISABLE
)
2626 * Are we running on neither host?
2628 if (!self_check(fromhost
) && !self_check(tohost
)) {
2629 if (flag
== RDC_CMD_DISABLE
) {
2630 (void) fprintf(stderr
, "\n");
2631 rdc_warn(NULL
, gettext("Not running on either host "
2632 "%s or host %s"), fromhost
, tohost
);
2638 * at this point, hopfully it is safe to say that
2639 * if a ctag was supplied via -C tag it is safe to
2640 * move it from ctag_arg to ctag. If it was passed in
2641 * at the end and the beginning of the cli, it must
2642 * match, as per checks above. if it was not passed
2643 * in at the end, but at the beginning, we can deal.
2644 * this should handle the case of shost:svol.
2645 * which is the main reason for this.
2647 * there are 3 cases: passed in by cli, checked just above.
2648 * using libdscfg, you must pass in -C tag to have
2650 * finally a file. same rules as libdscfg.
2652 if ((strlen(ctag
) == 0) && (strlen(ctag_arg
) > 0))
2653 (void) strcpy(ctag
, ctag_arg
);
2655 if (flag
== RDC_CMD_RECONFIG
) {
2656 if (reconfig_pbitmap
) {
2657 (void) strncpy(frombitmap
, reconfig_pbitmap
,
2659 check_rdcbitmap(flag
, fromhost
, frombitmap
);
2661 if (reconfig_sbitmap
) {
2662 (void) strncpy(tobitmap
, reconfig_sbitmap
,
2664 check_rdcbitmap(flag
, tohost
, tobitmap
);
2667 if (reconfig_direct
)
2668 (void) strncpy(directfile
, reconfig_direct
,
2672 (void) strncpy(group
, reconfig_group
,
2675 if (strlen(reconfig_ctag
) > 0)
2676 (void) strncpy(ctag
, reconfig_ctag
,
2678 if (reconfig_doasync
!= -1)
2679 doasync
= reconfig_doasync
;
2682 if (flag
== RDC_CMD_ENABLE
|| flag
== RDC_CMD_RECONFIG
) {
2683 if (ctag_check(fromhost
, fromfile
, frombitmap
,
2684 tohost
, tofile
, tobitmap
, ctag
, diskqueue
) < 0)
2686 if ((diskq_group
= check_diskqueue(NULL
, diskqueue
,
2687 group
)) == DISKQ_FAIL
) {
2688 rdc_err(NULL
, gettext("disk queue %s is "
2689 "incompatible with existing queue"),
2696 pairs
= read_config(flag
, config_file
, group_arg
, ctag_arg
);
2698 rdc_err(NULL
, gettext("%s contains no "
2699 "matching Remote Mirror sets"), config_file
);
2703 if (!nflag
&& !pflag
&& prompt_user(flag
, iflag
) == -1)
2708 if (cfgflag
|| fflag
) {
2709 (void) strncpy(fromfile
, pair_list
[pairs
].ffile
,
2711 (void) strncpy(tofile
, pair_list
[pairs
].tfile
,
2713 (void) strncpy(frombitmap
, pair_list
[pairs
].fbitmap
,
2715 (void) strncpy(fromhost
,
2716 pair_list
[pairs
].fhost
, MAX_RDC_HOST_SIZE
);
2717 (void) strncpy(tohost
, pair_list
[pairs
].thost
,
2719 (void) strncpy(tobitmap
, pair_list
[pairs
].tbitmap
,
2721 (void) strncpy(directfile
, pair_list
[pairs
].directfile
,
2723 (void) strncpy(group
, pair_list
[pairs
].group
,
2725 (void) strncpy(ctag
, pair_list
[pairs
].ctag
,
2727 (void) strncpy(diskqueue
, pair_list
[pairs
].diskqueue
,
2730 bcopy(pair_list
[pairs
].fnetaddr
, fromnetaddr
,
2732 bcopy(pair_list
[pairs
].tnetaddr
, tonetaddr
,
2735 doasync
= pair_list
[pairs
].doasync
;
2739 static int first
= 1;
2742 if ((cfg
= cfg_open(NULL
)) == NULL
)
2744 gettext("unable to access configuration"));
2746 if (!cfg_lock(cfg
, CFG_RDLOCK
))
2748 gettext("unable to lock configuration"));
2753 (void) rdc_print(file_format
, verbose
,
2754 group_arg
, ctag_arg
, tohost
, tofile
, cfg
);
2761 /* short circuit the rest of the command loop */
2766 ret
= rdc_bitmapset(tohost
, tofile
, bitfile
, oflag
,
2770 if ((fflag
|| cfgflag
) && flag
== RDC_CMD_RECONFIG
) {
2771 char orig_fbmp
[MAXHOSTNAMELEN
];
2772 char orig_tbmp
[MAXHOSTNAMELEN
];
2775 spcs_s_info_t ustatus
;
2777 parms
.command
= RDC_CMD_STATUS
;
2778 parms
.rdc_set
->netconfig
= NULL
;
2779 (void) strncpy(parms
.rdc_set
->primary
.intf
, fromhost
,
2781 (void) strncpy(parms
.rdc_set
->secondary
.intf
, tohost
,
2783 (void) strncpy(parms
.rdc_set
->primary
.file
, fromfile
,
2785 (void) strncpy(parms
.rdc_set
->secondary
.file
, tofile
,
2787 ustatus
= spcs_s_ucreate();
2788 ret
= RDC_IOCTL(RDC_CONFIG
, &parms
,
2789 NULL
, 0, 0, 0, ustatus
);
2790 if (ret
!= SPCS_S_OK
) {
2791 rdc_err(NULL
, gettext("unable to get set status"
2792 " before reconfig operation"));
2794 (void) strncpy(orig_fbmp
, parms
.rdc_set
->primary
.bitmap
,
2796 (void) strncpy(orig_tbmp
,
2797 parms
.rdc_set
->secondary
.bitmap
, NSC_MAXPATH
);
2799 if (strncmp(orig_fbmp
, frombitmap
, NSC_MAXPATH
) != 0)
2800 check_rdcbitmap(flag
, fromhost
, frombitmap
);
2801 if (strncmp(orig_tbmp
, tobitmap
, NSC_MAXPATH
) != 0)
2802 check_rdcbitmap(flag
, tohost
, tobitmap
);
2803 spcs_s_ufree(&ustatus
);
2807 * take a peek in the config to see if
2808 * the bitmap is being used elsewhere
2810 if (flag
== RDC_CMD_ENABLE
) {
2813 * just for fun, lets see if some silly person
2814 * specified the same vol and bitmap
2816 if ((strcmp(fromfile
, frombitmap
) == 0) ||
2817 (strcmp(tofile
, tobitmap
) == 0))
2818 rdc_err(NULL
, gettext("volumes and bitmaps"
2819 " must not match"));
2820 if (self_check(fromhost
)) {
2821 check_rdcbitmap(flag
, fromhost
, frombitmap
);
2822 if (stat(fromfile
, &stb
) != 0) {
2824 gettext("unable to access %s: %s"),
2825 fromfile
, strerror(errno
));
2827 if (!S_ISCHR(stb
.st_mode
)) {
2829 gettext("%s is not a character device"),
2832 } else { /* on the secondary */
2833 check_rdcbitmap(flag
, tohost
, tobitmap
);
2834 /* extra check for secondary vol */
2835 check_rdcsecondary(tofile
);
2836 if (stat(tofile
, &stb
) != 0) {
2838 gettext("unable to access %s: %s"),
2839 tofile
, strerror(errno
));
2841 if (!S_ISCHR(stb
.st_mode
)) {
2843 gettext("%s is not a character device"),
2850 if (flag
== RDC_CMD_ENABLE
|| flag
== RDC_CMD_DISABLE
||
2851 flag
== RDC_CMD_RECONFIG
) {
2852 if ((cfg
= cfg_open(NULL
)) == NULL
)
2854 gettext("unable to access configuration"));
2856 if (!cfg_lock(cfg
, CFG_WRLOCK
))
2858 gettext("unable to lock configuration"));
2860 cfg_resource(cfg
, clustered
? ctag
: NULL
);
2864 if (cfg
&& perform_autosv() &&
2865 (flag
== RDC_CMD_ENABLE
|| flag
== RDC_CMD_DISABLE
||
2866 flag
== RDC_CMD_RECONFIG
)) {
2867 if (cfg_load_svols(cfg
) < 0 ||
2868 cfg_load_dsvols(cfg
) < 0 ||
2869 cfg_load_shadows(cfg
) < 0)
2871 gettext("Unable to parse config filer"));
2874 cfg_success
= (cfg
== NULL
);
2875 if (cfg
&& flag
== RDC_CMD_ENABLE
) {
2876 /* Enabled, so add the set via libcfg */
2878 /* Build a new sndr entry and put it */
2879 group_p
= *group
? group
: place_holder
;
2880 diskqueue_p
= *diskqueue
? diskqueue
: place_holder
;
2882 if ((diskqueue_p
== place_holder
) &&
2883 (group_p
!= place_holder
)) {
2884 get_group_diskq(cfg
, group_p
, diskqueue
);
2886 diskqueue_p
= diskqueue
;
2890 * format in pconfig is:
2891 * phost.primary.pbitmap.shost.secondary.
2892 * sbitmap.type.mode.group.cnode.options.diskq
2894 (void) snprintf(buf
, sizeof (buf
),
2895 "%s %s %s %s %s %s %s %s %s %s - %s",
2896 fromhost
, fromfile
, frombitmap
, tohost
, tofile
,
2897 tobitmap
, directfile
,
2898 doasync
? "async" : "sync", group_p
,
2899 clustered
? ctag
: "-", diskqueue_p
);
2901 if (cfg_put_cstring(cfg
, "sndr", buf
, strlen(buf
)) < 0)
2903 gettext("unable to add \"%s\" to "
2904 "configuration storage: %s"),
2905 buf
, cfg_error(&sev
));
2906 setnumber
= find_setnumber_in_libcfg(cfg
, clustered
?
2907 ctag
: NULL
, tohost
, tofile
);
2910 gettext("unable to add \"%s\" to "
2911 "configuration storage: %s"),
2912 diskqueue_p
, cfg_error(&sev
));
2917 /* Add cluster aware info */
2918 if (clustered
&& !rdc_islocal
) {
2919 (void) snprintf(key
, sizeof (key
),
2920 "sndr.set%d.options", setnumber
);
2921 if (self_check(fromhost
)) {
2922 if (cfg_put_options(cfg
, CFG_SEC_CONF
,
2923 key
, "lghn", fromhost
) < 0) {
2925 gettext("unable to add "
2926 "\"%s\" to configuration "
2928 fromhost
, cfg_error(&sev
));
2930 } else if (self_check(tohost
)) {
2931 if (cfg_put_options(cfg
, CFG_SEC_CONF
,
2932 key
, "lghn", tohost
) < 0) {
2934 gettext("unable to add "
2935 "\"%s\" to configuration "
2937 fromhost
, cfg_error(&sev
));
2941 } else if (cfg
&& flag
== RDC_CMD_DISABLE
) {
2943 /* Disabled, so delete the set via libcfg */
2945 /* get sndr entries until shost, sfile match */
2946 for (i
= 0; i
< rdc_maxsets
; i
++) {
2948 (void) snprintf(key
, sizeof (key
), "sndr.set%d",
2950 if (cfg_get_cstring(cfg
, key
, buf
,
2954 (void) snprintf(key
, sizeof (key
),
2955 "sndr.set%d.secondary", setnumber
);
2956 if (cfg_get_cstring(cfg
, key
, buf
,
2959 if (strcmp(buf
, tofile
) != 0)
2961 (void) snprintf(key
, sizeof (key
),
2964 if (cfg_get_cstring(cfg
, key
, buf
,
2967 if (strcmp(buf
, tohost
) != 0)
2971 if (checksetfields
== -1) {
2973 gettext("checksetfields not set"));
2976 if (checksetfields
) {
2977 checkgfields(cfg
, setnumber
, fromhost
,
2978 fromfile
, frombitmap
, tobitmap
,
2979 directfile
, (doasync
== 1)
2980 ? "async" : "sync", group
, ctag
,
2984 /* perform cluster specific options */
2986 /* get the logical host, if set */
2987 (void) snprintf(key
, sizeof (key
),
2988 "sndr.set%d.options", setnumber
);
2989 (void) cfg_get_single_option(cfg
,
2990 CFG_SEC_CONF
, key
, "lghn",
2991 lhname
, MAX_RDC_HOST_SIZE
);
2993 /* figure out the cluster tag, if any */
2994 (void) snprintf(key
, sizeof (key
),
2995 "sndr.set%d.cnode", setnumber
);
2996 if (cfg_get_cstring(cfg
, key
, buf
,
2999 if (strcmp(buf
, ctag
))
3000 rdc_err(NULL
, gettext("ctags %s"
3001 " and %s do not match"),
3008 /* figure out the disk queue, if any */
3009 (void) snprintf(key
, sizeof (key
),
3012 if (cfg_get_cstring(cfg
, key
, buf
,
3015 if (strlen(buf
) > 0) {
3016 (void) strncpy(diskqueue
, buf
,
3021 (void) snprintf(key
, sizeof (key
), "sndr.set%d",
3023 if (cfg_put_cstring(cfg
, key
, NULL
, 0) < 0)
3025 gettext("unable to remove \"%s\" "
3026 "from configuration storage: %s"),
3027 buf
, cfg_error(&sev
));
3034 gettext("Unable to find %s:%s in "
3035 "configuration storage"),
3038 if (host_not_found
) {
3039 rdc_force_disable(cfg
, fromhost
, fromfile
,
3040 frombitmap
, tohost
, tofile
, tobitmap
, ctag
,
3042 if (cfg_commit(cfg
) < 0)
3043 rdc_err(NULL
, gettext("commit on "
3044 "force disable failed"));
3048 } else if (cfg
&& flag
== RDC_CMD_RECONFIG
) {
3049 /* Update relevant cfg record */
3051 cfg_resource(cfg
, NULL
);
3053 /* get sndr entries until shost, sfile match */
3054 for (i
= 0; i
< rdc_maxsets
; i
++) {
3056 (void) snprintf(key
, sizeof (key
), "sndr.set%d",
3058 if (cfg_get_cstring(cfg
, key
, buf
,
3062 (void) snprintf(key
, sizeof (key
),
3063 "sndr.set%d.secondary", setnumber
);
3064 if (cfg_get_cstring(cfg
, key
, buf
,
3067 if (strcmp(buf
, tofile
) != 0)
3069 (void) snprintf(key
, sizeof (key
),
3072 if (cfg_get_cstring(cfg
, key
, buf
,
3075 if (strcmp(buf
, tohost
) != 0)
3077 (void) snprintf(key
, sizeof (key
),
3080 if (cfg_get_cstring(cfg
, key
, buf
,
3083 if (reconfig_ctag
[0] == '\0')
3084 (void) strncpy(ctag
, buf
,
3087 (void) strcpy(mode
, "async");
3089 (void) strcpy(mode
, "sync");
3090 if (strcmp(directfile
, "") == 0)
3091 (void) strcpy(directfile
, "ip");
3093 group_p
= strlen(group
) > 0 ? group
:
3097 * if we are reconfigging out altogether,
3098 * get rid of the diskqueue
3100 if (group_p
== place_holder
)
3101 diskqueue_p
= place_holder
;
3103 diskqueue_p
= strlen(diskqueue
) > 0 ?
3104 diskqueue
: place_holder
;
3107 * do a little diskq dance here for reconfigs
3108 * that did not specify the diskqueue whilst
3111 if ((diskqueue_p
== place_holder
) &&
3112 (group_p
!= place_holder
)) {
3113 get_group_diskq(cfg
, group_p
,
3115 diskqueue_p
= strlen(diskqueue
) > 0 ?
3116 diskqueue
: place_holder
;
3119 (void) snprintf(key
, sizeof (key
),
3120 "sndr.set%d.options", setnumber
);
3121 if (cfg_get_cstring(cfg
, key
, options_cfg
,
3126 ctag_p
= strlen(ctag
) > 0 ?
3127 ctag
: place_holder
;
3128 (void) snprintf(buf
, sizeof (buf
),
3129 "%s %s %s %s %s %s %s %s %s %s %s %s",
3130 fromhost
, fromfile
, frombitmap
,
3131 tohost
, tofile
, tobitmap
,
3132 directfile
, mode
, group_p
,
3133 ctag_p
, options_cfg
, diskqueue_p
);
3135 (void) snprintf(key
, sizeof (key
), "sndr.set%d",
3137 if (cfg_put_cstring(cfg
, key
, buf
,
3140 gettext("unable to update \"%s\" "
3141 "in configuration storage: %s"),
3142 buf
, cfg_error(&sev
));
3150 if (cfg
&& perform_autosv()) {
3151 if (self_check(fromhost
)) {
3153 (strcmp(diskqueue
, fromfile
) == 0) ||
3154 (strcmp(diskqueue
, frombitmap
) == 0)) {
3155 rdc_err(NULL
, gettext("disk "
3156 "queue volume %s must not "
3157 "match any primary Remote "
3158 "Mirror volume or bitmap"),
3163 different_devs(fromfile
, diskqueue
);
3164 different_devs(frombitmap
, diskqueue
);
3165 validate_name(cfg
, diskqueue
);
3167 different_devs(fromfile
, frombitmap
);
3168 validate_name(cfg
, fromfile
);
3169 validate_name(cfg
, frombitmap
);
3171 different_devs(tofile
, tobitmap
);
3172 validate_name(cfg
, tofile
);
3173 validate_name(cfg
, tobitmap
);
3177 * okay, if the command is sync, just build
3178 * a list of rdcconfig_t's after the pairs--
3179 * loop is done, we will pass this list to
3180 * librdc to multithread the syncs (after
3181 * forking off a daemonish type process
3182 * that waits for the libcall to complete
3184 * flag ie RDC_CMD_COPY, iflag RDC_OPT_UPDATE,
3185 * reverse RDC_OPT_REVERSE, RDC_OPT_FORWARD
3186 * if necessary, turn autosync back on
3188 if (flag
== RDC_CMD_COPY
) {
3189 if (autosync_is_on(tohost
, tofile
) ==
3191 enable_autosync(fromhost
, fromfile
,
3196 rdc_alloc_config(fromhost
, fromfile
,
3197 frombitmap
, tohost
, tofile
,
3198 tobitmap
, "mode", "group", "ctag",
3201 if (sets_p
== NULL
) {
3203 gettext("rdc config alloc"
3204 "failed %s"), rdc_error(NULL
));
3209 sets_p
= sets_p
->next
=
3210 rdc_alloc_config(fromhost
, fromfile
,
3211 frombitmap
, tohost
, tofile
, tobitmap
,
3212 "mode", "group", "ctag", "options", 0);
3214 if (sets_p
== NULL
) {
3215 rdc_err(NULL
, gettext("rdc config alloc"
3216 "failed %s"), rdc_error(NULL
));
3222 * block incoming signals until after the possible
3223 * cfg_commit is done
3226 if (rdc_operation(cfg
, fromhost
, fromfile
, frombitmap
,
3227 tohost
, tofile
, tobitmap
, flag
, iflag
, directfile
,
3228 group
, ctag
, diskqueue
, &doasync
, reverse
) < 0) {
3232 if (diskq_group
== DISKQ_REWRITEG
) {
3233 rewrite_group_diskqueue(cfg
,
3234 &pair_list
[pairs
], diskqueue
);
3236 if (perform_autosv() &&
3237 (flag
== RDC_CMD_ENABLE
||
3238 flag
== RDC_CMD_DISABLE
||
3239 flag
== RDC_CMD_RECONFIG
)) {
3241 cfg_unload_shadows();
3242 cfg_unload_dsvols();
3245 if ((iflag
& RDC_OPT_REVERSE_ROLE
) != 0 &&
3247 bzero(tmphost
, MAX_RDC_HOST_SIZE
);
3248 bzero(tmpfile
, NSC_MAXPATH
);
3249 bzero(tmpbitmap
, NSC_MAXPATH
);
3250 (void) strncpy(tmphost
, fromhost
,
3252 (void) strncpy(tmpfile
, fromfile
,
3254 (void) strncpy(tmpbitmap
, frombitmap
,
3257 (void) strncpy(fromhost
, tohost
,
3259 (void) strncpy(fromfile
, tofile
,
3261 (void) strncpy(frombitmap
, tobitmap
,
3264 (void) strncpy(tohost
, tmphost
,
3266 (void) strncpy(tofile
, tmpfile
,
3268 (void) strncpy(tobitmap
, tmpbitmap
,
3270 group_p
= strlen(group
) > 0 ? group
:
3272 diskqueue_p
= strlen(diskqueue
) > 0 ?
3273 diskqueue
: place_holder
;
3274 ctag_p
= strlen(ctag
) > 0 ?
3275 ctag
: place_holder
;
3276 (void) snprintf(buf
, sizeof (buf
), "%s "
3277 "%s %s %s %s %s %s %s %s %s %s %s",
3278 fromhost
, fromfile
, frombitmap
,
3279 tohost
, tofile
, tobitmap
,
3280 directfile
, mode
, group_p
,
3281 ctag_p
, options_cfg
, diskqueue_p
);
3283 (void) snprintf(key
, sizeof (key
),
3284 "sndr.set%d", setnumber
);
3285 if (cfg_put_cstring(cfg
, key
, buf
,
3288 gettext("unable to update \"%s\" "
3289 "in configuration storage: %s"),
3290 buf
, cfg_error(&sev
));
3292 if (cfg_commit(cfg
) < 0) {
3293 rdc_err(NULL
, gettext("commit on role "
3294 "reversal failed"));
3305 if (flag
== RDC_CMD_COPY
) {
3307 if (pid
== -1) { /* error forking */
3314 if (pid
> 0) /* parent process */
3317 spcslog_sync(sets
, 1, iflag
);
3318 if (iflag
& RDC_OPT_REVERSE
) {
3319 if (iflag
& RDC_OPT_UPDATE
)
3320 rclist
= rdc_ursync(sets
);
3322 rclist
= rdc_rsync(sets
);
3323 } else if (iflag
& RDC_OPT_UPDATE
) {
3324 rclist
= rdc_usync(sets
);
3326 rclist
= rdc_fsync(sets
);
3331 /* rclist->msg has already been gettext'd */
3332 (void) fprintf(stderr
,
3333 gettext("Remote Mirror: %s %s %s %s %s %s\n"),
3334 rcp
->set
.phost
, rcp
->set
.pfile
, rcp
->set
.pbmp
,
3335 rcp
->set
.shost
, rcp
->set
.sfile
, rcp
->set
.sbmp
);
3336 rdc_warn(NULL
, "%s", rcp
->msg
);
3337 spcs_log("sndr", NULL
, "%s", rcp
->msg
);
3342 spcslog_sync(sets
, 0, iflag
);
3345 rdc_free_config(sets
, RDC_FREEALL
);
3347 rdc_free_rclist(rclist
);
3353 * pre: a non null string
3354 * post: if the string is "local"
3355 * then it is converted to "-"
3356 * and rdc_islocal is set to 1
3357 * if not rdc_islocal set to 0
3360 process_clocal(char *ctag
)
3363 * Check for the special cluster tag and convert into the
3364 * internal representation.
3367 if (ctag
!= NULL
&& strcmp(ctag
, RDC_LOCAL_TAG
) == 0) {
3368 (void) strcpy(ctag
, "-");
3376 rdc_check_dgislocal(char *dgname
)
3382 * check where this disk service is mastered
3385 rc
= cfg_dgname_islocal(dgname
, &othernode
);
3387 rdc_err(NULL
, gettext("unable to find "
3388 "disk service, %s: %s"), dgname
, strerror(errno
));
3392 rdc_err(NULL
, gettext("disk service, %s, is "
3393 "active on node \"%s\"\nPlease re-issue "
3394 "the command on that node"), dgname
, othernode
);
3399 different_devs(char *dev1
, char *dev2
)
3401 struct stat buf1
, buf2
;
3403 if (stat(dev1
, &buf1
) < 0) {
3404 spcs_log("sndr", NULL
, gettext("Remote Mirror: can't stat %s"),
3406 rdc_err(NULL
, gettext("Remote Mirror: can't stat %s"), dev1
);
3408 if (stat(dev2
, &buf2
) < 0) {
3409 spcs_log("sndr", NULL
, gettext("Remote Mirror: can't stat %s"),
3411 rdc_err(NULL
, gettext("Remote Mirror: can't stat %s"), dev2
);
3413 if (buf1
.st_rdev
== buf2
.st_rdev
) {
3414 spcs_log("sndr", NULL
, gettext("Remote Mirror: '%s' and '%s' "
3415 "refer to the same device"), dev1
, dev2
);
3416 rdc_err(NULL
, gettext("Remote Mirror: '%s' and '%s' refer to "
3417 "the same device"), dev1
, dev2
);
3422 validate_name(CFGFILE
*cfg
, char *vol
)
3428 rdc_err(NULL
, gettext("Remote Mirror: null cfg ptr in "
3432 rc
= cfg_get_canonical_name(cfg
, vol
, &altname
);
3434 spcs_log("sndr", NULL
, gettext("Remote Mirror: unable to parse "
3436 rdc_err(NULL
, gettext("Remote Mirror: unable to parse config "
3440 spcs_log("sndr", NULL
, gettext("Remote Mirror: '%s': already "
3441 "configured as '%s'"), vol
, altname
);
3442 rdc_err(NULL
, gettext("Remote Mirror: The volume '%s' has been "
3443 "configured previously as '%s'. Re-enter command with "
3444 "the latter name."), vol
, altname
);
3449 * Add the autosync value to the option field for the sndr set specified by
3453 * - cfg file is available to take a write lock.
3454 * - set is already configured in dscfg
3457 * autosync_val - value to set autosync to
3458 * tohost - secondary host
3459 * tofile - secondary volume
3466 set_autosync(int autosync_val
, char *tohost
, char *tofile
, char *ctag
)
3469 char key
[CFG_MAX_KEY
], buf
[CFG_MAX_BUF
];
3470 char tag
[CFG_MAX_BUF
], val
[CFG_MAX_BUF
];
3471 char auto_tag
[CFG_MAX_BUF
];
3472 _sd_dual_pair_t pair
;
3473 _sd_dual_pair_t tmpair
;
3474 int setnumber
, options
= 0, already_set
= 0, cfg_success
= 0;
3477 /* verify valid autosync request */
3478 if ((autosync_val
!= AUTOSYNC_ON
) && (autosync_val
!= AUTOSYNC_OFF
)) {
3481 gettext("set_autosync called with improper value"));
3486 if ((cfg
= cfg_open(NULL
)) == NULL
) {
3487 rdc_err(NULL
, gettext("unable to access configuration"));
3489 if (!cfg_lock(cfg
, CFG_WRLOCK
)) {
3490 rdc_err(NULL
, gettext("unable to lock configuration"));
3494 cfg_resource(cfg
, ctag
);
3496 cfg_resource(cfg
, NULL
);
3499 /* find set number in config */
3500 if ((setnumber
= find_setnumber_in_libcfg(cfg
, clustered
? ctag
: NULL
,
3501 tohost
, tofile
)) < 0) {
3503 rdc_err(NULL
, gettext("unable to find Remote Mirror set %s:%s: "
3504 "in config"), tohost
, tofile
);
3506 (void) snprintf(key
, sizeof (key
), "sndr.set%d.options", setnumber
);
3507 (void) snprintf(auto_tag
, sizeof (auto_tag
), "auto");
3509 /* Check if there are any options already set, including ours */
3510 if (cfg_get_options(cfg
, CFG_SEC_CONF
, key
, tag
, CFG_MAX_BUF
, val
,
3511 CFG_MAX_BUF
) >= 0) {
3515 if (strcmp(tag
, auto_tag
) == 0) {
3518 } while (cfg_get_options(cfg
, CFG_SEC_CONF
, NULL
, tag
,
3519 CFG_MAX_BUF
, val
, CFG_MAX_BUF
) >= 0);
3522 /* options already exist, edit ours out */
3523 if (options
&& already_set
) {
3525 int need_to_clear_buf
= 1;
3527 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
3528 rdc_err(NULL
, gettext("unable to get options field "
3529 "for Remote Mirror set %s:%s"), tohost
, tofile
);
3532 /* parse out our options, all of the form "auto=" */
3534 bzero(buf
, sizeof (buf
));
3538 /* if another tag/value exists, keep it */
3539 if (strncmp(auto_tag
, q
, 4) != 0) {
3540 (void) strcat(buf
, q
);
3541 (void) strcat(buf
, ";");
3542 need_to_clear_buf
= 0;
3544 } while (q
= strtok(NULL
, ";"));
3547 /* if we were the only option, clear the field */
3548 if (need_to_clear_buf
) {
3549 (void) strcat(buf
, "-");
3552 if (cfg_put_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
3553 rdc_err(NULL
, gettext("unable to clear autosync value "
3554 "in config for Remote Mirror set %s:%s"), tohost
,
3561 /* autosync is not present in options field, add if on is requested */
3562 if (autosync_val
== AUTOSYNC_ON
) {
3563 if (cfg_put_options(cfg
, CFG_SEC_CONF
, key
, auto_tag
, "on")
3565 rdc_err(NULL
, gettext("unable to update autosync value "
3566 "in config for Remote Mirror set %s:%s"), tohost
,
3572 /* if we are in a group, update any other sets in the same group */
3574 bzero(&pair
, sizeof (pair
));
3575 bzero(buf
, CFG_MAX_BUF
);
3577 (void) snprintf(key
, sizeof (key
), "sndr.set%d", setnumber
);
3578 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
3581 if (parse_cfg_buf(buf
, &pair
, NULL
))
3583 if (pair
.group
== NULL
) /* not in a group */
3586 break; /* not in a group */
3587 for (set
= 1; /*CSTYLED*/; set
++) {
3588 if (set
== setnumber
)
3590 bzero(buf
, CFG_MAX_BUF
);
3594 (void) snprintf(key
, sizeof (key
), "sndr.set%d", set
);
3595 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
3596 break; /* last set processed */
3598 bzero(&tmpair
, sizeof (tmpair
));
3599 if (parse_cfg_buf(buf
, &tmpair
, NULL
))
3601 if (strcmp(pair
.group
, tmpair
.group
) != 0)
3602 continue; /* not the group we want */
3604 (void) snprintf(key
, sizeof (key
), "sndr.set%d.options",
3607 * Check if there are any options already set,
3610 if (cfg_get_options(cfg
, CFG_SEC_CONF
, key
, tag
,
3611 CFG_MAX_BUF
, val
, CFG_MAX_BUF
) >= 0) {
3615 if (strcmp(tag
, auto_tag
) == 0) {
3618 } while (cfg_get_options(cfg
, CFG_SEC_CONF
,
3619 NULL
, tag
, CFG_MAX_BUF
, val
,
3623 /* options already exist, edit ours out */
3624 if (options
&& already_set
) {
3626 int need_to_clear_buf
= 1;
3628 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
)
3630 rdc_err(NULL
, gettext("unable to get "
3631 "options field for Remote Mirror set "
3632 "%s:%s"), tmpair
.thost
, tmpair
.tfile
);
3636 * parse out our options, all of the
3640 bzero(buf
, sizeof (buf
));
3645 * if another tag/value exists,
3648 if (strncmp(auto_tag
, q
, 4) != 0) {
3649 (void) strcat(buf
, q
);
3650 (void) strcat(buf
, ";");
3651 need_to_clear_buf
= 0;
3653 } while (q
= strtok(NULL
, ";"));
3657 * if we were the only option,
3660 if (need_to_clear_buf
) {
3661 (void) strcat(buf
, "-");
3664 if (cfg_put_cstring(cfg
, key
, buf
, CFG_MAX_BUF
)
3666 rdc_err(NULL
, gettext("unable to clear "
3667 "autosync value in config for "
3668 "Remote Mirror set %s:%s"),
3669 tmpair
.thost
, tmpair
.tfile
);
3675 * autosync is not present in options field,
3676 * add if on is requested
3678 if (autosync_val
== AUTOSYNC_ON
) {
3679 if (cfg_put_options(cfg
, CFG_SEC_CONF
, key
,
3680 auto_tag
, "on") < 0) {
3681 rdc_err(NULL
, gettext("unable to update"
3682 " autosync value in config for "
3683 "Remote Mirror set %s:%s"),
3694 if (cfg_commit(cfg
) < 0) {
3695 rdc_err(NULL
, gettext("commit on role reversal failed"));
3703 * Check to see if autosync is on for set specified by tohost:tofile.
3706 * config is available to take a read lock against it.
3709 * tohost - secondary host
3710 * tofile - secondary volume
3714 * AUTOSYNC_ON if autosync is on
3715 * AUTOSYNC_OFF if autosync is off
3718 autosync_is_on(char *tohost
, char *tofile
)
3721 int setnumber
, autosync_val
= AUTOSYNC_OFF
;
3722 char key
[CFG_MAX_KEY
];
3723 char tag
[CFG_MAX_BUF
], val
[CFG_MAX_BUF
];
3725 if ((cfg
= cfg_open(NULL
)) == NULL
) {
3726 rdc_err(NULL
, gettext("unable to access configuration"));
3729 if (!cfg_lock(cfg
, CFG_RDLOCK
)) {
3731 rdc_err(NULL
, gettext("unable to lock configuration"));
3734 if ((setnumber
= find_setnumber_in_libcfg(cfg
, NULL
, tohost
, tofile
)) <
3737 rdc_err(NULL
, gettext("cannot find Remote Mirror set %s:%s in "
3738 "config"), tohost
, tofile
);
3741 (void) snprintf(key
, CFG_MAX_KEY
, "sndr.set%d.options", setnumber
);
3742 if (cfg_get_options(cfg
, CFG_SEC_CONF
, key
, tag
, CFG_MAX_BUF
, val
,
3743 CFG_MAX_BUF
) >= 0) {
3745 if (strcmp(tag
, "auto") == 0) {
3746 if (strcmp(val
, "on") == 0) {
3747 autosync_val
= AUTOSYNC_ON
;
3751 } while (cfg_get_options(cfg
, CFG_SEC_CONF
, NULL
, tag
,
3752 CFG_MAX_BUF
, val
, CFG_MAX_BUF
) >= 0);
3756 return (autosync_val
);
3760 enable_autosync(char *fhost
, char *ffile
, char *thost
, char *tfile
)
3763 spcs_s_info_t ustat
;
3766 ustat
= spcs_s_ucreate();
3767 parms
.command
= RDC_CMD_TUNABLE
;
3769 p
= &parms
.rdc_set
[0].primary
;
3770 (void) strncpy(p
->intf
, fhost
, MAX_RDC_HOST_SIZE
);
3771 (void) strncpy(p
->file
, ffile
, MAX_RDC_HOST_SIZE
);
3773 p
= &parms
.rdc_set
[0].secondary
;
3774 (void) strncpy(p
->intf
, thost
, NSC_MAXPATH
);
3775 (void) strncpy(p
->file
, tfile
, NSC_MAXPATH
);
3777 parms
.rdc_set
[0].autosync
= 1;
3778 parms
.rdc_set
[0].maxqfbas
= -1;
3779 parms
.rdc_set
[0].maxqitems
= -1;
3780 parms
.rdc_set
[0].asyncthr
= -1;
3781 parms
.rdc_set
[0].netconfig
= NULL
;
3783 if ((RDC_IOCTL(RDC_CONFIG
, &parms
, NULL
, 0, 0, 0, ustat
)) !=
3785 rdc_warn(&ustat
, gettext("failed to update autosync for"
3786 " Remote Mirror set %s:%s"), thost
, tfile
);
3787 spcs_log("sndr", &ustat
, gettext("failed to update autosync for"
3788 " Remote Mirror set %s:%s"), thost
, tfile
);
3790 spcs_s_ufree(&ustat
);
3794 rdc_operation(CFGFILE
*cfg
, char *fromhost
, char *fromfile
, char *frombitmap
,
3795 char *tohost
, char *tofile
, char *tobitmap
,
3796 int flag
, int iflag
,
3797 char *directfile
, char *group
, char *ctag
, char *diskqueue
,
3798 int *doasync
, int reverse
)
3800 const int getaddr
= (flag
== RDC_CMD_ENABLE
);
3801 const int rpcbind
= !getaddr
;
3804 spcs_s_info_t ustatus
;
3806 char fromname
[MAXHOSTNAMELEN
], toname
[MAXHOSTNAMELEN
];
3807 char orig_fbmp
[MAXHOSTNAMELEN
], orig_tbmp
[MAXHOSTNAMELEN
];
3808 char orig_diskq
[NSC_MAXPATH
];
3809 struct t_info tinfo
;
3811 int autosync_toggle_needed
= 0;
3812 char *vol1
, *vol2
, *vol3
;
3816 hp
= gethost_byname(fromhost
);
3817 (void) strncpy(fromname
, hp
->h_name
, MAXHOSTNAMELEN
);
3818 hp
= gethost_byname(tohost
);
3819 (void) strncpy(toname
, hp
->h_name
, MAXHOSTNAMELEN
);
3821 if (self_check(fromname
) && self_check(toname
)) {
3822 rdc_err(NULL
, gettext("both %s and %s are local"),
3826 /* we have to find out what to sv disable after reconfig */
3827 if (flag
== RDC_CMD_RECONFIG
) {
3829 parms
.command
= RDC_CMD_STATUS
;
3830 parms
.rdc_set
->netconfig
= NULL
;
3831 (void) strncpy(parms
.rdc_set
->primary
.intf
, fromhost
,
3833 (void) strncpy(parms
.rdc_set
->secondary
.intf
, tohost
,
3835 (void) strncpy(parms
.rdc_set
->primary
.file
, fromfile
,
3837 (void) strncpy(parms
.rdc_set
->secondary
.file
, tofile
,
3839 ustatus
= spcs_s_ucreate();
3840 ret
= RDC_IOCTL(RDC_CONFIG
, &parms
,
3841 NULL
, 0, 0, 0, ustatus
);
3842 if (ret
!= SPCS_S_OK
) {
3843 rdc_err(NULL
, gettext("unable to get set status"
3844 " before reconfig operation"));
3846 (void) strncpy(orig_fbmp
, parms
.rdc_set
->primary
.bitmap
,
3848 (void) strncpy(orig_tbmp
, parms
.rdc_set
->secondary
.bitmap
,
3850 (void) strncpy(orig_diskq
, parms
.rdc_set
->disk_queue
,
3855 * another terrible addition, if we are reconfigging mode
3856 * and not logging, just give up.
3858 if ((reconfig_doasync
!= -1) &&
3859 (!(parms
.rdc_set
->flags
& RDC_LOGGING
))) {
3860 rdc_err(NULL
, gettext("cannot reconfigure sync/async, "
3861 "Remote Mirror set not logging"));
3862 spcs_log("sndr", NULL
, gettext("cannot reconfigure sync/async, "
3863 "Remote Mirror set not logging"));
3867 * Now build up the address for each host including port and transport
3870 svp
= get_addr(toname
, RDC_PROGRAM
, RDC_VERS_MIN
,
3871 &conf
, proto_test
? NC_UDP
:NULL
, "rdc", &tinfo
,
3875 rdc_warn(NULL
, gettext("unable to determine network "
3876 "information for %s"), toname
);
3878 (void) printf("get_addr failed for Ver 4 %s\n", toname
);
3884 bzero(&svaddr
, sizeof (svaddr
));
3887 parms
.rdc_set
->secondary
.addr
.len
= svaddr
.len
;
3888 parms
.rdc_set
->secondary
.addr
.maxlen
=
3890 parms
.rdc_set
->secondary
.addr
.buf
=
3894 (void) fprintf(stderr
, "secondary buf %x len %d\n",
3895 svaddr
.buf
, svaddr
.len
);
3897 for (i
= 0; i
< svaddr
.len
; i
++)
3898 (void) printf("%u ", svaddr
.buf
[i
]);
3899 (void) printf("\n");
3903 svp
= get_addr(fromname
, RDC_PROGRAM
, RDC_VERS_MIN
,
3904 &conf
, proto_test
? NC_UDP
: NULL
, "rdc", &tinfo
,
3908 (void) printf("get_addr failed for Ver 4 %s\n",
3916 parms
.rdc_set
->primary
.addr
.len
= svaddr
.len
;
3917 parms
.rdc_set
->primary
.addr
.maxlen
= svaddr
.maxlen
;
3918 parms
.rdc_set
->primary
.addr
.buf
= (void *)svaddr
.buf
;
3921 (void) fprintf(stderr
, "primary buf %x len %d\n",
3922 svaddr
.buf
, svaddr
.len
);
3923 for (i
= 0; i
< svaddr
.len
; i
++)
3924 (void) printf("%u ", svaddr
.buf
[i
]);
3925 (void) printf("\n");
3929 (void) convert_nconf_to_knconf(conf
, &knconf
);
3931 (void) printf("knconf %x %s %s %x\n", knconf
.knc_semantics
,
3932 knconf
.knc_protofmly
, knconf
.knc_proto
, knconf
.knc_rdev
);
3934 parms
.rdc_set
->netconfig
= &knconf
;
3936 parms
.rdc_set
->netconfig
= NULL
;
3939 if (!self_check(fromname
) && !self_check(toname
)) {
3941 rdc_err(NULL
, gettext("neither %s nor %s is local"),
3945 * IF we could get a list of logical hosts on this cluster
3946 * Then we could print something intelligent about where
3947 * the volume is mastered. For now, just print some babble
3948 * about the fact that we have no idea.
3951 gettext("either %s:%s or %s:%s is not local"),
3952 fromhost
, fromfile
, tohost
, tofile
);
3956 (void) strncpy(parms
.rdc_set
->primary
.intf
, fromhost
,
3958 (void) strncpy(parms
.rdc_set
->primary
.file
, fromfile
, NSC_MAXPATH
);
3959 (void) strncpy(parms
.rdc_set
->primary
.bitmap
, frombitmap
, NSC_MAXPATH
);
3961 (void) strncpy(parms
.rdc_set
->secondary
.intf
, tohost
,
3963 (void) strncpy(parms
.rdc_set
->secondary
.file
, tofile
, NSC_MAXPATH
);
3964 (void) strncpy(parms
.rdc_set
->secondary
.bitmap
, tobitmap
, NSC_MAXPATH
);
3966 if ((group
== NULL
) || ((strcmp(group
, "-")) == 0))
3967 parms
.rdc_set
->group_name
[0] = 0;
3969 (void) strncpy(parms
.rdc_set
->group_name
, group
, NSC_MAXPATH
);
3971 if (self_check(tohost
) &&
3972 (strlen(diskqueue
) > 0) && (diskqueue
[0] != '-'))
3973 if ((flag
== RDC_CMD_ENABLE
) || (flag
== RDC_CMD_ADDQ
))
3974 rdc_err(NULL
, gettext("enabling disk queue on a Remote"
3975 " Mirror secondary is not allowed (%s)"),
3978 if ((diskqueue
== NULL
) || ((strcmp(diskqueue
, "-")) == 0))
3979 parms
.rdc_set
->disk_queue
[0] = 0;
3981 (void) strncpy(parms
.rdc_set
->disk_queue
, diskqueue
,
3984 parms
.rdc_set
->maxqfbas
= maxqfbas
;
3985 parms
.rdc_set
->maxqitems
= maxqitems
;
3986 parms
.rdc_set
->asyncthr
= asyncthr
;
3987 /* set up the permanent set id for this set */
3988 if (flag
== RDC_CMD_ENABLE
) {
3989 char key
[CFG_MAX_KEY
];
3992 parms
.rdc_set
->setid
= get_new_cfg_setid(cfg
);
3993 if (parms
.rdc_set
->setid
<= 0) {
3994 rdc_err(NULL
, gettext("unable to obtain unique set id "
3995 "for %s:%s"), tohost
, tofile
);
3997 if ((set
= find_setnumber_in_libcfg(cfg
, clustered
? ctag
: NULL
,
3998 tohost
, tofile
)) < 0) {
3999 rdc_err(NULL
, gettext("unable to store unique set id"
4000 " for %s:%s"), tohost
, tofile
);
4002 (void) snprintf(key
, sizeof (key
), "sndr.set%d.options", set
);
4003 (void) snprintf(setid
, sizeof (setid
), "%d",
4004 parms
.rdc_set
->setid
);
4006 if (cfg_put_options(cfg
, CFG_SEC_CONF
, key
, "setid",
4008 rdc_err(NULL
, gettext("unable to store unique set "
4009 "id for %s:%s: %s"), tohost
, tofile
,
4010 gettext(cfg_error(NULL
)));
4012 } else if (flag
!= RDC_CMD_DISABLE
) { /* set already gone from cfg */
4013 parms
.rdc_set
->setid
= get_cfg_setid(cfg
, ctag
, tohost
, tofile
);
4014 if (parms
.rdc_set
->setid
<= 0) {
4015 rdc_err(NULL
, gettext("unable to obtain unique set id "
4016 "for %s:%s"), tohost
, tofile
);
4021 * Always set autosync flag to default so nothing gets messed up. If
4022 * we are doing an autosync operation, it'll all get taken care of
4025 parms
.rdc_set
->autosync
= AUTOSYNC
;
4028 /* gethostid(3c) is defined to return a 32bit value */
4029 parms
.rdc_set
->syshostid
= (int32_t)gethostid();
4032 parms
.options
= iflag
;
4033 parms
.command
= flag
;
4034 if (flag
== RDC_CMD_ENABLE
|| flag
== RDC_CMD_RECONFIG
) {
4036 parms
.options
|= RDC_OPT_ASYNC
;
4038 parms
.options
|= RDC_OPT_SYNC
;
4039 } else if (flag
== RDC_CMD_COPY
) {
4041 parms
.options
|= RDC_OPT_REVERSE
;
4043 parms
.options
|= RDC_OPT_FORWARD
;
4046 if (self_check(fromname
)) {
4047 if (flag
== RDC_CMD_COPY
&& reverse
&& mounted(fromfile
))
4048 rdc_err(NULL
, gettext("can not start reverse sync"
4049 " as a file system is mounted on %s"),
4051 parms
.options
|= RDC_OPT_PRIMARY
;
4052 if (strcmp(directfile
, "ip") == 0)
4053 parms
.rdc_set
->direct_file
[0] = 0; /* no directfile */
4055 (void) strncpy(parms
.rdc_set
->direct_file
, directfile
,
4058 parms
.options
|= RDC_OPT_SECONDARY
;
4059 parms
.rdc_set
->direct_file
[0] = 0; /* no fcal directio */
4062 if ((asyncthr
|| maxqitems
|| maxqfbas
|| qblock
) &&
4063 (parms
.options
& RDC_OPT_SECONDARY
)) {
4064 rdc_err(NULL
, gettext("changing queue parameters may "
4065 " only be done on a primary Remote Mirror host"));
4066 spcs_log("sndr", NULL
, gettext("changing queue parameters may "
4067 " only be done on a primary Remote Mirror host"));
4071 ustatus
= spcs_s_ucreate();
4073 if (flag
== RDC_CMD_COPY
) {
4074 parms
.command
= RDC_CMD_STATUS
;
4075 ret
= RDC_IOCTL(RDC_CONFIG
, &parms
, NULL
, 0, 0, 0, ustatus
);
4076 if ((ret
!= SPCS_S_OK
) ||
4077 !(parms
.rdc_set
->flags
& RDC_LOGGING
)) {
4078 rdc_err(NULL
, gettext("can not start sync"
4079 " as Remote Mirror set %s:%s is not logging"),
4082 spcs_log("sndr", NULL
,
4083 gettext("%s %s %s %s %s %s %s %s\nStarting"),
4084 program
, rdc_decode_flag(flag
, parms
.options
),
4085 fromhost
, fromfile
, frombitmap
,
4086 tohost
, tofile
, tobitmap
);
4087 parms
.command
= RDC_CMD_COPY
;
4090 if ((flag
== RDC_CMD_COPY
) &&
4091 (autosync_is_on(tohost
, tofile
) == AUTOSYNC_ON
)) {
4092 /* check if autosync needs to be turned on when doing a copy/update */
4093 parms
.rdc_set
->autosync
= AUTOSYNC_ON
;
4094 autosync_toggle_needed
= 1;
4095 } else if ((flag
== RDC_CMD_LOG
) &&
4096 (autosync_is_on(tohost
, tofile
) == AUTOSYNC_ON
)) {
4097 /* check if autosync needs to be turned off when going to logging */
4098 parms
.rdc_set
->autosync
= AUTOSYNC_OFF
;
4099 autosync_toggle_needed
= 1;
4100 } else if (((autosync
== AUTOSYNC_ON
) || (autosync
== AUTOSYNC_OFF
)) &&
4101 (flag
== RDC_CMD_TUNABLE
)) {
4103 * Request to change the autosync value. cfg file will be
4104 * available at this point. If autosync request is to turn off,
4105 * mark off in both the config and the kernel regardless of
4106 * the state of the set. If the request is to turn autosync on,
4107 * set in the kernel if the set is not in logging mode.
4110 * If the set is in logging mode because of a network
4111 * failure, we will not know. Therefore, a manual update
4112 * will have to be issued to enable autosync in the
4116 set_autosync(autosync
, tohost
, tofile
, ctag
);
4118 if (autosync
== AUTOSYNC_OFF
) {
4119 parms
.rdc_set
->autosync
= AUTOSYNC_OFF
;
4120 } else if (autosync
== AUTOSYNC_ON
) {
4121 parms
.command
= RDC_CMD_STATUS
;
4122 ret
= RDC_IOCTL(RDC_CONFIG
, &parms
, NULL
, 0, 0, 0,
4124 if (ret
!= SPCS_S_OK
) {
4125 rdc_err(NULL
, gettext("can not determine "
4126 "status of Remote Mirror set %s:%s"),
4130 /* need to reset the tunables after a status ioctl */
4131 parms
.rdc_set
->autosync
= autosync
;
4132 parms
.rdc_set
->maxqfbas
= maxqfbas
;
4133 parms
.rdc_set
->maxqitems
= maxqitems
;
4134 parms
.rdc_set
->asyncthr
= asyncthr
;
4137 * if in logging mode, just update config, kernel will
4138 * be updated with the next copy/update request.
4140 if (parms
.rdc_set
->flags
& RDC_LOGGING
) {
4141 parms
.rdc_set
->autosync
= AUTOSYNC
;
4143 parms
.rdc_set
->autosync
= AUTOSYNC_ON
;
4146 parms
.command
= flag
;
4150 if (autosync_toggle_needed
) {
4151 parms
.command
= RDC_CMD_TUNABLE
;
4152 ret
= RDC_IOCTL(RDC_CONFIG
, &parms
, NULL
, 0, 0, 0, ustatus
);
4153 if (ret
!= SPCS_S_OK
) {
4154 spcs_log("sndr", NULL
, gettext("failed to update "
4155 "autosync for Remote Mirror set %s:%s"), tohost
,
4157 rdc_err(NULL
, gettext("failed to update autosync for "
4158 "Remote Mirror set %s:%s"), tohost
, tofile
);
4160 /* reset command and default autosync flags */
4161 parms
.rdc_set
->autosync
= AUTOSYNC
;
4162 parms
.command
= flag
;
4166 ret
= RDC_IOCTL(RDC_CONFIG
, &parms
, NULL
, 0, 0, 0, ustatus
);
4167 if ((ret
!= SPCS_S_OK
) && (flag
!= RDC_CMD_HEALTH
)) {
4168 (void) fprintf(stderr
,
4169 gettext("Remote Mirror: %s %s %s %s %s %s\n"),
4171 frombitmap
, tohost
, tofile
, tobitmap
);
4173 if (errno
== RDC_EEINVAL
) {
4174 spcs_log("sndr", NULL
,
4175 "%s %s %s %s %s %s %s %s\n%s",
4176 program
, rdc_decode_flag(flag
, parms
.options
),
4177 fromhost
, fromfile
, frombitmap
,
4178 tohost
, tofile
, tobitmap
,
4179 gettext("invalid command option"));
4181 gettext("Remote Mirror: invalid command option "
4182 "'%s'"), rdc_decode_flag(flag
,
4185 spcs_log("sndr", &ustatus
,
4186 "%s %s %s %s %s %s %s %s",
4187 program
, rdc_decode_flag(flag
, parms
.options
),
4188 fromhost
, fromfile
, frombitmap
,
4189 tohost
, tofile
, tobitmap
);
4190 if ((flag
== RDC_CMD_RECONFIG
) &&
4191 (!(iflag
& RDC_OPT_REVERSE_ROLE
))) {
4193 rdc_warn(&ustatus
, 0);
4195 rdc_err(&ustatus
, 0);
4198 if ((flag
== RDC_CMD_RECONFIG
) && (iflag
& RDC_OPT_REVERSE_ROLE
) == 0) {
4199 parms
.command
= RDC_CMD_STATUS
;
4200 if (RDC_IOCTL(RDC_CONFIG
, &parms
, NULL
, 0, 0, 0, ustatus
) ==
4202 char shostbuf
[CFG_MAX_BUF
];
4203 char svolbuf
[CFG_MAX_BUF
];
4204 char key
[CFG_MAX_KEY
];
4209 * okeydoke, at this point we could have a reconfig
4210 * gone bad. libdscfg does not know about this.
4211 * parms contains the kernel picture, and we know
4212 * what we tried to reconfig. find out where it went
4213 * wrong, find the set in libdscfg, update it. We'll
4214 * issue a warning, then return 0 (eventually).
4215 * this will allow libdscfg to be committed with the
4216 * good info. got it?
4217 * BTW: the only time we can run into this multiple
4218 * reconfig attempt failure is IF we reconfig from file
4219 * and some thing goes wrong with one of the reconfigs
4222 /* find the set in libdscfg */
4224 numels
= cfg_get_num_entries(cfg
, "sndr");
4225 /* yes, numels could be -1 */
4226 for (i
= 1; i
< numels
; i
++) {
4227 bzero(shostbuf
, sizeof (shostbuf
));
4228 bzero(svolbuf
, sizeof (svolbuf
));
4229 bzero(key
, sizeof (key
));
4231 (void) snprintf(key
, sizeof (key
),
4232 "sndr.set%d.shost", i
);
4234 (void) cfg_get_cstring(cfg
, key
, &shostbuf
,
4236 if (strncmp(shostbuf
, tohost
, sizeof (tohost
)))
4239 bzero(key
, sizeof (key
));
4240 (void) snprintf(key
, sizeof (key
),
4241 "sndr.set%d.secondary", i
);
4242 (void) cfg_get_cstring(cfg
, key
, &svolbuf
,
4244 if (strncmp(svolbuf
, tofile
, NSC_MAXPATH
))
4249 * found it, now i contains the set offset.
4250 * i, being the variable, not bad english.
4254 /* shouldn't happen */
4255 if ((numels
< 1) || (i
> numels
)) {
4256 rdc_warn(NULL
, gettext("unable to retrieve "
4257 "set from configuration database"));
4259 * yuck. but indents are pushing the envelope
4260 * we should not be updating config
4261 * if we did not find the entry
4262 * the error will have to do
4269 * now, put all the correct names back for errors etc.
4270 * also, sock them into dscfg, if the the config was a
4271 * success for one, it will be a redundant but harmless
4275 * we could not have reconfigged mode if we
4276 * are not logging, AND the kernel CAN return
4277 * sync as the status of an async set if it is
4278 * currently syncing.. Hence the flags & RDC_LOGGING
4280 if (parms
.rdc_set
->flags
& RDC_LOGGING
) {
4281 bzero(key
, sizeof (key
));
4282 (void) snprintf(key
, sizeof (key
),
4283 "sndr.set%d.mode", i
);
4284 if (parms
.rdc_set
->flags
& RDC_ASYNC
) {
4286 if (cfg_put_cstring(cfg
, key
, "async",
4287 strlen("async")) < 0) {
4293 if (cfg_put_cstring(cfg
, key
, "sync",
4294 strlen("sync")) < 0) {
4300 if (*parms
.rdc_set
->direct_file
) {
4301 (void) strncpy(directfile
,
4302 parms
.rdc_set
->direct_file
, NSC_MAXPATH
);
4303 bzero(key
, sizeof (key
));
4304 (void) snprintf(key
, sizeof (key
),
4305 "sndr.set%d.type", i
);
4306 if (cfg_put_cstring(cfg
, key
, directfile
,
4307 strlen(directfile
)) < 0)
4310 (void) strncpy(directfile
, "-", NSC_MAXPATH
);
4311 bzero(key
, sizeof (key
));
4312 (void) snprintf(key
, sizeof (key
),
4313 "sndr.set%d.type", i
);
4314 if (cfg_put_cstring(cfg
, key
, directfile
,
4315 strlen(directfile
)) < 0)
4320 if (*parms
.rdc_set
->group_name
) {
4321 (void) strncpy(group
, parms
.rdc_set
->group_name
,
4323 bzero(key
, sizeof (key
));
4324 (void) snprintf(key
, sizeof (key
),
4325 "sndr.set%d.group", i
);
4326 if (cfg_put_cstring(cfg
, key
, group
,
4331 (void) strncpy(group
, "-", NSC_MAXPATH
);
4332 bzero(key
, sizeof (key
));
4333 (void) snprintf(key
, sizeof (key
),
4334 "sndr.set%d.group", i
);
4335 if (cfg_put_cstring(cfg
, key
, group
,
4340 if (*parms
.rdc_set
->disk_queue
) {
4341 (void) strncpy(diskqueue
,
4342 parms
.rdc_set
->disk_queue
, NSC_MAXPATH
);
4344 (void) strncpy(diskqueue
, "-", NSC_MAXPATH
);
4346 bzero(key
, sizeof (key
));
4347 (void) snprintf(key
, sizeof (key
),
4348 "sndr.set%d.diskq", i
);
4349 if (cfg_put_cstring(cfg
, key
, diskqueue
,
4350 strlen(diskqueue
)) < 0)
4353 (void) strncpy(frombitmap
,
4354 parms
.rdc_set
->primary
.bitmap
, NSC_MAXPATH
);
4355 bzero(key
, sizeof (key
));
4356 (void) snprintf(key
, sizeof (key
),
4357 "sndr.set%d.pbitmap", i
);
4358 if (cfg_put_cstring(cfg
, key
, frombitmap
,
4359 strlen(frombitmap
)) < 0)
4362 (void) strncpy(tobitmap
,
4363 parms
.rdc_set
->secondary
.bitmap
, NSC_MAXPATH
);
4364 bzero(key
, sizeof (key
));
4365 (void) snprintf(key
, sizeof (key
),
4366 "sndr.set%d.sbitmap", i
);
4367 if (cfg_put_cstring(cfg
, key
, tobitmap
,
4368 strlen(tobitmap
)) < 0)
4371 bzero(key
, sizeof (key
));
4372 (void) snprintf(key
, sizeof (key
),
4373 "sndr.set%d.cnode", i
);
4375 if (cfg_put_cstring(cfg
, key
, ctag
,
4379 if (cfgsuccess
== 0) {
4380 rdc_warn(NULL
, gettext("unable to update "
4381 "configuration storage"));
4384 spcs_log("sndr", NULL
,
4385 "%s %s %s %s %s %s %s %s\n%s",
4386 program
, rdc_decode_flag(flag
, parms
.options
),
4387 fromhost
, fromfile
, frombitmap
,
4388 tohost
, tofile
, tobitmap
,
4389 gettext("unable to update config file"));
4391 gettext("Remote Mirror: unable to update "
4397 if (flag
== RDC_CMD_HEALTH
&& errno
== 0) {
4398 (void) fprintf(stderr
,
4399 gettext("Remote Mirror: %s %s %s %s %s %s\n"),
4401 frombitmap
, tohost
, tofile
, tobitmap
);
4403 if (ret
== RDC_ACTIVE
)
4404 (void) fprintf(stderr
, "Active\n");
4405 else if (ret
== RDC_INACTIVE
)
4406 (void) fprintf(stderr
, "Inactive\n");
4408 (void) fprintf(stderr
, "Unknown\n");
4409 } else if (ret
!= SPCS_S_OK
) {
4410 if (errno
== RDC_EEINVAL
) {
4411 spcs_log("sndr", NULL
,
4412 "%s %s %s %s %s %s %s %s\n%s",
4413 program
, rdc_decode_flag(flag
, parms
.options
),
4414 fromhost
, fromfile
, frombitmap
,
4415 tohost
, tofile
, tobitmap
,
4416 gettext("invalid command option"));
4418 gettext("Remote Mirror: invalid command option "
4420 rdc_decode_flag(flag
, parms
.options
));
4423 if (flag
== RDC_CMD_STATUS
) {
4424 (void) fprintf(stderr
,
4425 gettext("Remote Mirror: %s %s %s %s %s %s\n"),
4427 frombitmap
, tohost
, tofile
, tobitmap
);
4428 (void) fprintf(stderr
, "flags 0x%x\n", parms
.rdc_set
->flags
|
4429 parms
.rdc_set
->sync_flags
| parms
.rdc_set
->bmap_flags
);
4430 } else if (success
) {
4431 spcs_log("sndr", NULL
,
4432 gettext("%s %s %s %s %s %s %s %s\nSuccessful"),
4433 program
, rdc_decode_flag(flag
, parms
.options
),
4434 fromhost
, fromfile
, frombitmap
,
4435 tohost
, tofile
, tobitmap
);
4436 if (flag
== RDC_CMD_TUNABLE
)
4437 spcslog_tunable(tohost
, tofile
);
4440 if (cfg
&& perform_autosv()) {
4441 spcs_s_ufree(&ustatus
);
4442 /* figure out which are the local volumes */
4443 if (parms
.options
& RDC_OPT_PRIMARY
) {
4446 if ((diskqueue
&& diskqueue
[0]) &&
4447 (strncmp(diskqueue
, "-", 1) != 0))
4455 if ((flag
== RDC_CMD_ENABLE
) &&
4456 (strlen(diskqueue
) > 0) &&
4457 (strncmp(diskqueue
, "-", 1)) != 0) {
4459 gettext("enabling a disk queue on a "
4460 "Remote Mirror secondary is not allowed. "
4461 "(%s) ignored"), diskqueue
);
4465 if (flag
== RDC_CMD_ENABLE
) {
4466 ustatus
= spcs_s_ucreate();
4468 * SV-enable all local volumes
4469 * if the sv_enables fail, disable the sndr vols
4470 * that we just enabled
4471 * and return -1 so the cfg_commit() won't happen
4474 if (nsc_lookup(volhash
, vol1
) == NULL
) {
4475 if (cfg_vol_enable(cfg
, vol1
, ctag
, "sndr")
4477 spcs_log("sndr", NULL
,
4478 "sv enable failed for %s, "
4479 "disabling Remote Mirror set %s:%s",
4480 vol1
, tohost
, tofile
);
4482 * warn here, but we are going to exit
4483 * we want to catch any errors on the
4484 * way down, then exit
4488 "unable to sv enable %s\n"
4489 "disabling Remote Mirror set %s:%s",
4490 vol1
, tohost
, tofile
);
4492 parms
.command
= RDC_CMD_DISABLE
;
4493 ret
= RDC_IOCTL(RDC_CONFIG
, &parms
,
4494 NULL
, 0, 0, 0, ustatus
);
4495 if (ret
!= SPCS_S_OK
) {
4496 (void) fprintf(stderr
,
4497 gettext("Remote Mirror:"
4498 " %s %s %s %s %s %s\n"),
4500 frombitmap
, tohost
, tofile
,
4502 spcs_log("sndr", &ustatus
,
4503 "%s %s %s %s %s %s %s %s",
4505 rdc_decode_flag(parms
.command
,
4508 fromfile
, frombitmap
,
4509 tohost
, tofile
, tobitmap
);
4510 rdc_err(&ustatus
, 0);
4513 * ok, we should've reported any errs
4520 if (vol2
&& nsc_lookup(volhash
, vol2
) == NULL
) {
4521 if (cfg_vol_enable(cfg
, vol2
, ctag
, "sndr")
4523 spcs_log("sndr", NULL
,
4524 "sv enable failed for %s, "
4525 "disabling Remote Mirror set %s:%s",
4526 vol1
, tohost
, tofile
);
4528 * warn here, but we are going to exit
4529 * we want to catch any errors on the
4530 * way down, then exit
4534 "unable to sv enable %s\n"
4535 "disabling Remote Mirror set %s:%s",
4536 vol2
, tohost
, tofile
);
4538 parms
.command
= RDC_CMD_DISABLE
;
4539 ret
= RDC_IOCTL(RDC_CONFIG
, &parms
,
4540 NULL
, 0, 0, 0, ustatus
);
4541 if (ret
!= SPCS_S_OK
) {
4542 (void) fprintf(stderr
,
4543 gettext("Remote Mirror:"
4544 " %s %s %s %s %s %s\n"),
4546 frombitmap
, tohost
, tofile
,
4548 spcs_log("sndr", &ustatus
,
4549 "%s %s %s %s %s %s %s %s",
4551 rdc_decode_flag(parms
.command
,
4554 fromfile
, frombitmap
,
4555 tohost
, tofile
, tobitmap
);
4556 rdc_err(&ustatus
, 0);
4559 * ok, we should've reported any errs
4567 if (vol3
&& nsc_lookup(volhash
, diskqueue
) == NULL
) {
4568 if (cfg_vol_enable(cfg
, diskqueue
, ctag
, "sndr")
4570 spcs_log("sndr", NULL
,
4571 "sv enable failed for %s, "
4572 "disabling Remote Mirror set %s:%s",
4573 diskqueue
, tohost
, tofile
);
4574 if (cfg_vol_disable(cfg
, vol1
, ctag
,
4576 rdc_warn(NULL
, gettext("Failed to "
4577 "remove volume [%s] from "
4578 "configuration"), vol1
);
4579 if (cfg_vol_disable(cfg
, vol2
, ctag
,
4581 rdc_warn(NULL
, gettext("Failed to "
4582 "remove volume [%s] from "
4583 "configuration"), vol2
);
4586 * warn here, but we are going to exit
4587 * we want to catch any errors on the
4588 * way down, then exit
4592 "unable to sv enable %s\n"
4593 "disabling Remote Mirror set %s:%s",
4594 diskqueue
, tohost
, tofile
);
4596 parms
.command
= RDC_CMD_DISABLE
;
4597 ret
= RDC_IOCTL(RDC_CONFIG
, &parms
,
4598 NULL
, 0, 0, 0, ustatus
);
4599 if (ret
!= SPCS_S_OK
) {
4600 (void) fprintf(stderr
,
4601 gettext("Remote Mirror:"
4602 " %s %s %s %s %s %s\n"),
4604 frombitmap
, tohost
, tofile
,
4606 spcs_log("sndr", &ustatus
,
4607 "%s %s %s %s %s %s %s %s",
4609 rdc_decode_flag(parms
.command
,
4612 fromfile
, frombitmap
,
4613 tohost
, tofile
, tobitmap
);
4614 rdc_err(&ustatus
, 0);
4617 * ok, we should've reported any errs
4624 } else if (flag
== RDC_CMD_DISABLE
) {
4626 * If we're no longer using a volume, SV-disable it
4630 vc
= nsc_lookup(volhash
, vol1
);
4631 if (vc
&& (1 == vc
->count
)) {
4632 if (cfg_vol_disable(cfg
, vol1
, ctag
, "sndr")
4634 rdc_warn(NULL
, gettext("Failed to "
4635 "remove volume [%s] from "
4636 "configuration"), vol1
);
4640 gettext("Unable to find %s in config"),
4645 vc
= nsc_lookup(volhash
, vol2
);
4646 if (vc
&& (1 == vc
->count
)) {
4647 if (cfg_vol_disable(cfg
, vol2
, ctag
,
4649 rdc_warn(NULL
, gettext("Failed to "
4650 "remove volume [%s] from "
4651 "configuration"), vol2
);
4653 rdc_warn(NULL
, gettext("Unable to find"
4654 " %s in config"), vol2
);
4658 if (diskqueue
!= NULL
&& strlen(diskqueue
) > 0) {
4659 vc
= nsc_lookup(volhash
, diskqueue
);
4660 if (vc
&& (1 == vc
->count
)) {
4661 if (cfg_vol_disable(cfg
, diskqueue
, ctag
,
4663 rdc_warn(NULL
, gettext("Failed to "
4664 "remove disk queue [%s] from "
4665 "configuration"), diskqueue
);
4667 rdc_warn(NULL
, gettext("Unable to find"
4668 " %s in config"), diskqueue
);
4671 /* WARNING about to go to 4 space indenting */
4672 } else if (flag
== RDC_CMD_RECONFIG
) {
4674 /* disable ex-bitmaps, enable new bitmaps */
4675 if (parms
.options
& RDC_OPT_PRIMARY
) {
4676 if (strcmp(orig_fbmp
, frombitmap
) != 0) {
4677 vc
= nsc_lookup(volhash
, orig_fbmp
);
4678 if (vc
&& (vc
->count
== 1)) {
4679 if (cfg_vol_disable(cfg
, orig_fbmp
, ctag
,
4681 rdc_warn(NULL
, gettext("Failed to "
4682 "remove bitmap [%s] from "
4683 "configuration"), orig_fbmp
);
4685 rdc_warn(NULL
, gettext("Unable to find "
4686 "%s in config"), orig_fbmp
);
4688 if (nsc_lookup(volhash
, frombitmap
) == NULL
) {
4689 if (cfg_vol_enable(cfg
, frombitmap
, ctag
,
4691 spcs_log("sndr", NULL
,
4692 "reconfig sv enable failed for %s, "
4693 "disabling Remote Mirror set %s:%s",
4694 frombitmap
, tohost
, tofile
);
4696 "unable to sv enable %s\n"
4697 "disabling Remote Mirror set %s:%s",
4698 frombitmap
, tohost
, tofile
);
4699 parms
.command
= RDC_CMD_DISABLE
;
4700 ret
= RDC_IOCTL(RDC_CONFIG
, &parms
,
4701 NULL
, 0, 0, 0, ustatus
);
4702 if (ret
!= SPCS_S_OK
) {
4703 (void) fprintf(stderr
,
4704 gettext("Remote Mirror:"
4705 " %s %s %s %s %s %s\n"),
4707 frombitmap
, tohost
, tofile
,
4709 spcs_log("sndr", &ustatus
,
4710 "%s %s %s %s %s %s %s %s",
4712 rdc_decode_flag(parms
.command
,
4715 fromfile
, frombitmap
,
4716 tohost
, tofile
, tobitmap
);
4717 rdc_warn(&ustatus
, 0);
4722 } else if ((orig_diskq
[0] != '\0') &&
4723 (strcmp(orig_diskq
, diskqueue
) != 0)) {
4724 vc
= nsc_lookup(volhash
, orig_diskq
);
4725 if (vc
&& (vc
->count
== 1)) {
4726 if (cfg_vol_disable(cfg
, orig_diskq
, ctag
,
4728 rdc_warn(NULL
, gettext("Failed to "
4729 "remove disk queue [%s] from "
4730 "configuration"), orig_diskq
);
4732 rdc_warn(NULL
, gettext("Unable to find "
4733 "%s in config"), orig_diskq
);
4736 (nsc_lookup(volhash
, diskqueue
) == NULL
)) {
4737 if (cfg_vol_enable(cfg
, diskqueue
, ctag
,
4739 spcs_log("sndr", NULL
, "reconfig sv "
4740 "enable of diskqueue %s failed, "
4741 "disabling Remote Mirror set %s:%s",
4742 diskqueue
, tohost
, tofile
);
4743 rdc_warn(NULL
, "reconfig sv "
4744 "enable of diskqueue %s failed."
4745 "disabling Remote Mirror set %s:%s",
4746 diskqueue
, tohost
, tofile
);
4747 parms
.command
= RDC_CMD_DISABLE
;
4748 ret
= RDC_IOCTL(RDC_CONFIG
, &parms
,
4749 NULL
, 0, 0, 0, ustatus
);
4750 if (ret
!= SPCS_S_OK
) {
4751 (void) fprintf(stderr
,
4752 gettext("Remote Mirror:"
4753 " %s %s %s %s %s %s\n"),
4755 frombitmap
, tohost
, tofile
,
4757 spcs_log("sndr", &ustatus
,
4758 "%s %s %s %s %s %s %s %s",
4760 rdc_decode_flag(parms
.command
,
4763 fromfile
, frombitmap
,
4764 tohost
, tofile
, tobitmap
);
4765 rdc_warn(&ustatus
, 0);
4771 } else if (flag
!= RDC_OPT_PRIMARY
) {
4772 if (strcmp(orig_tbmp
, tobitmap
) != 0) {
4773 vc
= nsc_lookup(volhash
, orig_tbmp
);
4774 if (vc
&& (vc
->count
== 1)) {
4775 if (cfg_vol_disable(cfg
, orig_tbmp
, ctag
,
4777 rdc_warn(NULL
, gettext("Failed to "
4778 "remove bitmap [%s] from "
4779 "configuration"), orig_tbmp
);
4782 gettext("Unable to find %s in config"),
4785 if (nsc_lookup(volhash
, tobitmap
) == NULL
) {
4786 if (cfg_vol_enable(cfg
, tobitmap
, ctag
,
4788 spcs_log("sndr", NULL
,
4789 "reconfig sv enable failed for %s, "
4790 "disabling Remote Mirror set %s:%s",
4791 tobitmap
, tohost
, tofile
);
4793 "unable to sv enable %s\n"
4794 "disabling Remote Mirror set %s:%s",
4795 tobitmap
, tohost
, tofile
);
4796 parms
.command
= RDC_CMD_DISABLE
;
4797 ret
= RDC_IOCTL(RDC_CONFIG
, &parms
,
4798 NULL
, 0, 0, 0, ustatus
);
4799 if (ret
!= SPCS_S_OK
) {
4800 (void) fprintf(stderr
,
4801 gettext("Remote Mirror:"
4802 " %s %s %s %s %s %s\n"),
4804 frombitmap
, tohost
, tofile
,
4806 spcs_log("sndr", &ustatus
,
4807 "%s %s %s %s %s %s %s %s",
4809 rdc_decode_flag(parms
.command
,
4811 fromhost
, fromfile
, frombitmap
,
4812 tohost
, tofile
, tobitmap
);
4813 rdc_warn(&ustatus
, 0);
4820 /* END 4 space indenting */
4823 spcs_s_ufree(&ustatus
);
4832 * DESCRIPTION: Read the lines in a configuration file and return the
4833 * pairs of devices to be mirrored/enabled/disabled/updated.
4834 * The format for the configuration file is as follows:
4836 * fromhost fromfile frombitmap tohost tofile tobitmap
4838 * where fromfile is the primary device which is local to the
4839 * fromhost subsystem, tofile is the secondary device which is
4840 * local to the tohost subsystem, and type is 1 if the device
4841 * a simckd device or 0 otherwise. Any line preceeded by a '#'
4842 * is considered to be a comment.
4845 * char *config_file Name of configuration file for rdcadm
4848 * int i Number of pairs of devices
4850 * Side Effects: The 0 to i-1 entries in the pair_list are filled.
4855 read_config(int flag
, char *config_file
, char *group_arg
, char *ctag_arg
)
4858 char dsk_flagstr
[NSC_MAXPATH
];
4859 char line
[1024], tmp_line
[1024];
4860 char fromhost
[MAX_RDC_HOST_SIZE
];
4861 char fromfile
[NSC_MAXPATH
];
4862 char frombitmap
[NSC_MAXPATH
];
4863 char tohost
[MAX_RDC_HOST_SIZE
];
4864 char tofile
[NSC_MAXPATH
];
4865 char tobitmap
[NSC_MAXPATH
];
4866 char directfile
[NSC_MAXPATH
];
4871 char *extra_args
[EXTRA_ARGS
];
4872 char *tmp
, *split_str
= " \t\n";
4874 for (j
= 0; j
< EXTRA_ARGS
; j
++)
4875 extra_args
[j
] = malloc(NSC_MAXPATH
);
4877 if (!(fp
= fopen(config_file
, "r"))) {
4878 rdc_err(NULL
, gettext("error opening %s"), config_file
);
4882 while (fgets(line
, sizeof (line
), fp
)) {
4883 if (line
[0] == '#') /* this is a comment */
4887 (void) strcpy(tmp_line
, line
);
4889 if ((tmp
= strtok(tmp_line
, split_str
)) != NULL
) {
4890 if (strlen(tmp
) >= MAX_RDC_HOST_SIZE
) {
4891 (void) printf(gettext("hostname is longer than %d "
4892 "characters\n"), (MAX_RDC_HOST_SIZE
- 1));
4895 (void) strncpy(fromhost
, tmp
, (MAX_RDC_HOST_SIZE
- 1));
4896 fromhost
[(MAX_RDC_HOST_SIZE
- 1)] = '\0';
4899 if ((tmp
= strtok(NULL
, split_str
)) != NULL
) {
4900 if (strlen(tmp
) >= NSC_MAXPATH
) {
4901 (void) printf(gettext(
4902 "device name is longer than %d "
4903 "characters\n"), (NSC_MAXPATH
- 1));
4906 (void) strncpy(fromfile
, tmp
, (NSC_MAXPATH
- 1));
4907 fromfile
[(NSC_MAXPATH
- 1)] = '\0';
4910 if ((tmp
= strtok(NULL
, split_str
)) != NULL
) {
4911 if (strlen(tmp
) >= NSC_MAXPATH
) {
4912 (void) printf(gettext(
4913 "device name is longer than %d "
4914 "characters\n"), (NSC_MAXPATH
- 1));
4917 (void) strncpy(frombitmap
, tmp
, (NSC_MAXPATH
- 1));
4918 frombitmap
[(NSC_MAXPATH
- 1)] = '\0';
4921 if ((tmp
= strtok(NULL
, split_str
)) != NULL
) {
4922 if (strlen(tmp
) >= MAX_RDC_HOST_SIZE
) {
4923 (void) printf(gettext(
4924 "hostname is longer than %d "
4925 "characters\n"), (MAX_RDC_HOST_SIZE
- 1));
4928 (void) strncpy(tohost
, tmp
, (MAX_RDC_HOST_SIZE
- 1));
4929 tohost
[(MAX_RDC_HOST_SIZE
- 1)] = '\0';
4932 if ((tmp
= strtok(NULL
, split_str
)) != NULL
) {
4933 if (strlen(tmp
) >= NSC_MAXPATH
) {
4934 (void) printf(gettext(
4935 "device name is longer than %d "
4936 "characters\n"), (NSC_MAXPATH
- 1));
4939 (void) strncpy(tofile
, tmp
, (NSC_MAXPATH
- 1));
4940 tofile
[(NSC_MAXPATH
- 1)] = '\0';
4943 if ((tmp
= strtok(NULL
, split_str
)) != NULL
) {
4944 if (strlen(tmp
) >= NSC_MAXPATH
) {
4945 (void) printf(gettext(
4946 "device name is longer than %d "
4947 "characters\n"), (NSC_MAXPATH
- 1));
4950 (void) strncpy(tobitmap
, tmp
, (NSC_MAXPATH
- 1));
4951 tobitmap
[(NSC_MAXPATH
- 1)] = '\0';
4954 if ((tmp
= strtok(NULL
, split_str
)) != NULL
) {
4955 (void) strncpy(dsk_flagstr
, tmp
, 15);
4956 dsk_flagstr
[15] = '\0';
4959 if ((tmp
= strtok(NULL
, split_str
)) != NULL
) {
4960 (void) strncpy(sync
, tmp
, 15);
4964 for (j
= 0; j
< EXTRA_ARGS
; j
++) {
4965 if ((tmp
= strtok(NULL
, split_str
)) != NULL
) {
4966 (void) strncpy(extra_args
[j
], tmp
,
4968 extra_args
[j
][(NSC_MAXPATH
- 1)] = '\0';
4973 if (ret
== 0) /* this is a blank line */
4979 gettext("invalid format in %s"), config_file
);
4980 rdc_err(NULL
, "%s", line
);
4983 if (i
>= rdc_maxsets
) {
4986 gettext("number of Remote Mirror sets exceeds %d"),
4991 if (dsk_flagstr
[0] == '/') {
4993 (void) strncpy(directfile
, dsk_flagstr
, NSC_MAXPATH
);
4994 } else if (strcmp(dsk_flagstr
, "ip") != 0) {
4996 if (strcmp(dsk_flagstr
, "ip") != 0) {
5001 gettext("ip/fcal specification missing"));
5003 gettext("ip specification missing"));
5006 (void) strcpy(directfile
, "ip");
5008 if (strcmp(sync
, "sync") == 0)
5010 else if (strcmp(sync
, "async") == 0)
5015 gettext("sync/async specification missing"));
5017 (void) strncpy(pair_list
[i
].fhost
, fromhost
, MAX_RDC_HOST_SIZE
);
5018 (void) strncpy(pair_list
[i
].ffile
, fromfile
, NSC_MAXPATH
);
5019 (void) strncpy(pair_list
[i
].fbitmap
, frombitmap
, NSC_MAXPATH
);
5020 (void) strncpy(pair_list
[i
].thost
, tohost
, MAX_RDC_HOST_SIZE
);
5021 (void) strncpy(pair_list
[i
].tfile
, tofile
, NSC_MAXPATH
);
5022 (void) strncpy(pair_list
[i
].tbitmap
, tobitmap
, NSC_MAXPATH
);
5023 (void) strncpy(pair_list
[i
].directfile
, directfile
,
5025 pair_list
[i
].doasync
= doasync
;
5027 if (gethost_netaddrs(fromhost
, tohost
,
5028 (char *)pair_list
[i
].fnetaddr
,
5029 (char *)pair_list
[i
].tnetaddr
) < 0) {
5031 rdc_err(NULL
, gettext("unable to determine IP "
5032 "addresses for hosts %s, %s"), fromhost
, tohost
);
5035 if (parse_extras(ret
- 8, extra_args
, i
) < 0) {
5037 rdc_err(NULL
, gettext("illegal option in:\n%s"),
5041 if (flag
== RDC_CMD_ENABLE
|| flag
== RDC_CMD_RECONFIG
) {
5042 if (ctag_check(fromhost
, fromfile
, frombitmap
,
5043 tohost
, tofile
, tobitmap
, pair_list
[i
].ctag
,
5044 pair_list
[i
].diskqueue
) < 0)
5045 continue; /* Ignore illegal sets */
5046 if (pair_diskqueue_check(i
))
5047 continue; /* ignore sets with incorrect diskq */
5050 /* Filter according to ctag and group arguments */
5051 if (strcmp(ctag_arg
, "") &&
5052 strncmp(ctag_arg
, pair_list
[i
].ctag
,
5055 if (strcmp(group_arg
, "") &&
5056 strncmp(group_arg
, pair_list
[i
].group
, NSC_MAXPATH
))
5062 for (j
= 0; j
< EXTRA_ARGS
; j
++)
5063 free(extra_args
[j
]);
5071 * DESCRIPTION: Read the relevant config info via libcfg
5074 * int i Number of pairs of devices
5076 * Side Effects: The 0 to i-1 entries in the pair_list are filled.
5080 read_libcfg(int flag
, char *group_arg
, char *ctag_arg
)
5085 _sd_dual_pair_t
*pairp
;
5086 char buf
[CFG_MAX_BUF
];
5087 char key
[CFG_MAX_KEY
];
5090 if ((cfg
= cfg_open(NULL
)) == NULL
)
5091 rdc_err(NULL
, gettext("unable to access configuration"));
5093 if (!cfg_lock(cfg
, CFG_RDLOCK
))
5094 rdc_err(NULL
, gettext("unable to lock configuration"));
5096 if (strcmp(ctag_arg
, ""))
5097 cfg_resource(cfg
, ctag_arg
);
5099 cfg_resource(cfg
, NULL
);
5104 for (i
= 0; i
< rdc_maxsets
;) {
5107 bzero(buf
, CFG_MAX_BUF
);
5108 (void) snprintf(key
, sizeof (key
), "sndr.set%d", setnumber
);
5109 rc
= cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
);
5113 pairp
= &pair_list
[i
];
5114 if (parse_cfg_buf(buf
, pairp
, NULL
))
5117 if (strcmp(group_arg
, "") &&
5118 strncmp(group_arg
, pairp
->group
, NSC_MAXPATH
))
5121 if (flag
== RDC_CMD_RECONFIG
) {
5122 if (reconfig_pbitmap
)
5123 (void) strncpy(pairp
->fbitmap
, reconfig_pbitmap
,
5125 if (reconfig_sbitmap
)
5126 (void) strncpy(pairp
->tbitmap
, reconfig_sbitmap
,
5129 if (reconfig_direct
)
5130 (void) strncpy(directfile
, reconfig_direct
,
5134 (void) strncpy(pairp
->group
, reconfig_group
,
5137 if (strlen(reconfig_ctag
) > 0)
5138 (void) strncpy(pairp
->ctag
, reconfig_ctag
,
5141 if (reconfig_doasync
!= -1)
5142 pairp
->doasync
= reconfig_doasync
;
5146 if (ctag_check(pairp
->fhost
, pairp
->ffile
,
5147 pairp
->fbitmap
, pairp
->thost
, pairp
->tfile
,
5148 pairp
->tbitmap
, pairp
->ctag
, pairp
->diskqueue
) < 0)
5149 continue; /* Ignore illegal sets */
5151 if (gethost_netaddrs(pairp
->fhost
, pairp
->thost
,
5152 (char *)pairp
->fnetaddr
,
5153 (char *)pairp
->tnetaddr
) < 0) {
5154 rdc_err(NULL
, gettext("unable to determine IP "
5155 "addresses for hosts %s, %s"), pairp
->fhost
,
5170 (void) fprintf(stderr
, gettext("disk queue usage:\n"));
5172 (void) fprintf(stderr
,
5173 gettext("\t%s -g <group> -q a <vol>\t\tadd disk queue to "
5174 "group\n"), program
);
5175 (void) fprintf(stderr
,
5176 gettext("\t%s -g <group> -q d \t\tremove disk queue from"
5177 " group\n"), program
);
5178 (void) fprintf(stderr
,
5179 gettext("\t%s -g <group> -q r <newvol>\treplace disk queue for a"
5180 " group\n"), program
);
5182 (void) fprintf(stderr
,
5183 gettext("\t%s -q a <vol> <shost>:<sdev>\tadd disk queue to "
5184 "a set\n"), program
);
5185 (void) fprintf(stderr
,
5186 gettext("\t%s -q d <shost>:<sdev>\t\tremove disk queue from "
5187 "a set\n"), program
);
5188 (void) fprintf(stderr
,
5189 gettext("\t%s -q r <newvol> <shost>:<sdev>\treplace disk queue for "
5190 "a set\n"), program
);
5197 (void) fprintf(stderr
, gettext("usage:\n"));
5199 (void) fprintf(stderr
,
5200 gettext("\t%s [opts] -a {on | off} [set]\t"
5201 "set autosync\n"), program
);
5203 (void) fprintf(stderr
,
5204 gettext("\t%s [opts] -A <asyncthr> [set]\t"
5205 "set the number of asynchronous\n\t\t\t\t\t\tthreads\n"),
5208 (void) fprintf(stderr
,
5209 gettext("\t%s [opts] -d [set]\t\t\t"
5210 "disable\n"), program
);
5212 (void) fprintf(stderr
,
5213 gettext("\t%s [opts] -e [set]\t\t\t"
5214 "enable with bits in bitmap set\n"), program
);
5216 (void) fprintf(stderr
,
5217 gettext("\t%s [opts] -E [set]\t\t\t"
5218 "enable with bits in bitmap clear\n"), program
);
5220 (void) fprintf(stderr
,
5221 gettext("\t%s [opts] -F <maxqfbas> [set]\t"
5222 "set maximum fbas to queue\n"), program
);
5224 (void) fprintf(stderr
,
5225 gettext("\t%s [opts] -D {block | noblock} [set]\t"
5226 "set disk queue blocking mode\n"), program
);
5228 (void) fprintf(stderr
,
5229 gettext("\t%s [opts] -H [set]\t\t\t"
5230 "report link health\n"), program
);
5232 (void) fprintf(stderr
,
5233 gettext("\t%s -h\t\t\t\tusage message\n"), program
);
5235 (void) fprintf(stderr
,
5236 gettext("\t%s -I a <master> <shadow> <bitmap>\t"
5237 "add ndr_ii config entry\n"), program
);
5239 (void) fprintf(stderr
,
5240 gettext("\t%s -I d <master> <shadow> <bitmap>\t"
5241 "delete ndr_ii config entry\n"), program
);
5243 (void) fprintf(stderr
,
5244 gettext("\t%s [opts] -i [set]\t\t\t"
5245 "print sets in config file format\n"), program
);
5247 (void) fprintf(stderr
,
5248 gettext("\t%s [opts] -l [set]\t\t\t"
5249 "enter logging mode\n"), program
);
5251 (void) fprintf(stderr
,
5252 gettext("\t%s [opts] -m [set]\t\t\t"
5253 "full sync\n"), program
);
5255 (void) fprintf(stderr
,
5256 gettext("\t%s [opts] -m -r [set]\t\t"
5257 "full reverse sync\n"), program
);
5259 (void) fprintf(stderr
,
5260 gettext("\t%s [opts] -P [set]\t\t\t"
5261 "print sets verbose\n"), program
);
5263 (void) fprintf(stderr
,
5264 gettext("\t%s [opts] -p [set]\t\t\t"
5265 "print sets\n"), program
);
5267 (void) fprintf(stderr
,
5268 gettext("\t%s [opts] -R\t\t\t"
5269 "reset error conditions\n"), program
);
5271 (void) fprintf(stderr
,
5272 gettext("\t%s [opts] -R b p <bitmap> [set]\t"
5273 "reconfig primary bitmap\n"), program
);
5275 (void) fprintf(stderr
,
5276 gettext("\t%s [opts] -R b s <bitmap> [set]\t"
5277 "reconfig secondary bitmap\n"), program
);
5280 (void) fprintf(stderr
,
5281 gettext("\t%s [opts] -R C <ctag> [set]\t"
5282 "reconfig cluster tag\n"), program
);
5285 (void) fprintf(stderr
,
5286 gettext("\t%s [opts] -R d <pathname> [set]\t"
5287 "reconfig campus direct file\n"), program
);
5290 (void) fprintf(stderr
,
5291 gettext("\t%s [opts] -R -f <volset-file> \t"
5292 "reconfig from file\n"), program
);
5294 (void) fprintf(stderr
,
5295 gettext("\t%s [opts] -R g <group> [set]\t"
5296 "reconfig group\n"), program
);
5298 (void) fprintf(stderr
,
5299 gettext("\t%s [opts] -R m {sync|async} [set]\t"
5300 "reconfig mode\n"), program
);
5303 (void) fprintf(stderr
,
5304 gettext("\t%s [opts] -R r [set]\t\t"
5305 "reverse roles\n"), program
);
5307 (void) fprintf(stderr
,
5308 gettext("\t%s [opts] -u [set]\t\t\t"
5309 "update sync\n"), program
);
5311 (void) fprintf(stderr
,
5312 gettext("\t%s [opts] -u -r [set]\t\t"
5313 "update reverse sync\n"), program
);
5315 (void) fprintf(stderr
,
5316 gettext("\t%s -v\t\t\t\tdisplay version\n"), program
);
5318 (void) fprintf(stderr
,
5319 gettext("\t%s [opts] -W <maxwrites> [set]\t"
5320 "set maximum writes to queue\n"), program
);
5322 (void) fprintf(stderr
,
5323 gettext("\t%s [opts] -w [set]\t\t\t"
5324 "wait\n"), program
);
5327 (void) fprintf(stderr
, gettext("\nopts:\n"));
5328 (void) fprintf(stderr
, gettext("\t-n\t\tnon-interactive mode "
5329 "(not valid for print operations)\n"));
5330 (void) fprintf(stderr
, gettext(
5331 "\t-g <group>\toperate on sets in group only "
5332 "(not valid for enable\n\t\t\toperations)\n"));
5334 (void) fprintf(stderr
,
5335 gettext("\t-C <ctag>\tignore sets not in cluster ctag "
5336 "(not valid for enable\n\t\t\toperations)\n"));
5338 (void) fprintf(stderr
, gettext("\nset:\n"));
5340 (void) fprintf(stderr
,
5341 gettext("\t<phost> <pdev> <pbmp> "
5343 "<shost> <sdev> <sbmp> {ip | <directfile>} "
5345 "<shost> <sdev> <sbmp> ip "
5347 "\\\n\t\t{sync | async} [g <group>] [q <qdev>] "
5350 (void) fprintf(stderr
,
5351 gettext("\t<phost> <pdev> <pbmp> "
5353 "<shost> <sdev> <sbmp> {ip | <directfile>} "
5355 "<shost> <sdev> <sbmp> ip "
5357 "\\\n\t\t{sync | async} [g <group>] [q <qdev>]\n"));
5358 (void) fprintf(stderr
,
5359 gettext("\t<shost>:<sdev>\t\t"
5360 "operate on set matching shost and sdev\n"));
5361 (void) fprintf(stderr
,
5362 gettext("\t-f volset-file\t\t"
5363 "operate on all sets specified in config file\n"
5364 "\t\t\t\tnote: not valid for single set operations. See\n"
5365 "\t\t\t\t%s(1RDC).\n"), program
);
5366 (void) fprintf(stderr
,
5367 gettext("\t<no arg>\t\toperate on all configured sets\n"));
5371 prompt_user(int flag
, int options
)
5376 case RDC_CMD_DISABLE
:
5377 (void) printf(gettext("Disable Remote Mirror? (Y/N) [N]: "));
5379 case RDC_CMD_ENABLE
:
5380 (void) printf(gettext("Enable Remote Mirror? (Y/N) [N]: "));
5382 case RDC_CMD_HEALTH
:
5383 (void) printf(gettext("Report Remote Mirror link health? (Y/N)"
5387 if (options
& RDC_OPT_FULL
) {
5388 if (options
& RDC_OPT_REVERSE
)
5389 (void) printf(gettext("Overwrite primary with"
5390 " secondary? (Y/N) [N]: "));
5392 (void) printf(gettext("Overwrite secondary with"
5393 " primary? (Y/N) [N]: "));
5395 if (options
& RDC_OPT_REVERSE
)
5396 (void) printf(gettext("Refresh primary with"
5397 " secondary? (Y/N) [N]: "));
5399 (void) printf(gettext("Refresh secondary with"
5400 " primary? (Y/N) [N]: "));
5403 case RDC_CMD_RECONFIG
:
5404 (void) printf(gettext(
5405 "Perform Remote Mirror reconfiguration? (Y/N) [N]: "));
5408 (void) printf(gettext("Perform Remote Mirror reset? (Y/N) "
5411 case RDC_CMD_TUNABLE
:
5412 (void) printf(gettext("Change Remote Mirror tunable? (Y/N) "
5416 (void) printf(gettext(
5417 "Put Remote Mirror into logging mode? (Y/N) [N]: "));
5420 (void) printf(gettext(
5421 "Wait for Remote Mirror sync completion? (Y/N) [N]: "));
5424 (void) printf(gettext("Perform Remote Mirror operation? (Y/N) "
5429 if ((c
!= 'y') && (c
!= 'Y')) {
5430 (void) printf("\n");
5437 load_rdc_vols(CFGFILE
*cfg
)
5440 char key
[ CFG_MAX_KEY
];
5441 char buf
[ CFG_MAX_BUF
];
5442 _sd_dual_pair_t pair
;
5444 char *host1
= pair
.fhost
, *host2
= pair
.thost
;
5445 char *diskqueue
= pair
.diskqueue
;
5446 volcount_t
*volcount
;
5447 char lghn
[ MAX_RDC_HOST_SIZE
];
5453 cfg_rewind(cfg
, CFG_SEC_CONF
);
5454 volhash
= nsc_create_hash();
5455 for (set
= 1; /*CSTYLED*/; set
++) {
5456 (void) snprintf(key
, CFG_MAX_KEY
, "sndr.set%d", set
);
5457 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
)) {
5461 if (parse_cfg_buf(buf
, &pair
, lghn
))
5466 /* use lghn if possible */
5468 if (strcmp(host2
, lghn
) == 0) {
5472 } else if (!self_check(host1
)) {
5473 /* next one had better be ours */
5477 if (!self_check(host2
)) {
5479 gettext("config error: neither %s nor %s"
5480 " is localhost"), host1
, host2
);
5485 /* primary vol may be used more than once */
5486 volcount
= (volcount_t
*)nsc_lookup(volhash
, vol
);
5490 volcount
= (volcount_t
*)malloc(sizeof (volcount_t
));
5491 volcount
->count
= 1;
5492 (void) nsc_insert_node(volhash
, volcount
, vol
);
5495 /* bitmap ought to be only used once */
5496 volcount
= (volcount_t
*)nsc_lookup(volhash
, bmp
);
5501 volcount
= (volcount_t
*)malloc(sizeof (volcount_t
));
5502 volcount
->count
= 1;
5503 (void) nsc_insert_node(volhash
, volcount
, bmp
);
5506 if (strcmp(diskqueue
, place_holder
) == 0)
5508 /* diskqueue vol may be used more than once */
5509 volcount
= (volcount_t
*)nsc_lookup(volhash
, diskqueue
);
5513 volcount
= (volcount_t
*)malloc(sizeof (volcount_t
));
5514 volcount
->count
= 1;
5515 (void) nsc_insert_node(volhash
, volcount
, diskqueue
);
5523 nsc_remove_all(volhash
, free
);
5533 return (cfg_issuncluster());
5538 * Check the user supplied fields against those in the dscfg for
5540 * Never returns on an error.
5543 checkgfields(CFGFILE
*cfg
, int setnumber
, char *fromhost
, char *fromfile
,
5544 char *frombitmap
, char *tobitmap
, char *type
, char *mode
, char *group
,
5545 char *ctag
, char *diskq
)
5548 checkgfield(cfg
, setnumber
, "phost",
5549 gettext("primary host"), fromhost
);
5551 checkgfield(cfg
, setnumber
, "primary",
5552 gettext("primary volume"), fromfile
);
5554 checkgfield(cfg
, setnumber
, "pbitmap",
5555 gettext("primary bitmap"), frombitmap
);
5557 checkgfield(cfg
, setnumber
, "sbitmap",
5558 gettext("secondary bitmap"), tobitmap
);
5560 checkgfield(cfg
, setnumber
, "type",
5561 gettext("type of connection"), type
);
5563 checkgfield(cfg
, setnumber
, "mode",
5564 gettext("mode of connection"), mode
);
5566 checkgfield(cfg
, setnumber
, "group",
5567 gettext("group"), group
);
5569 checkgfield(cfg
, setnumber
, "cnode",
5570 gettext("cluster tag"), ctag
);
5572 checkgfield(cfg
, setnumber
, "diskq",
5573 gettext("disk queue volume"), diskq
);
5577 * Check the 'fname' field in the dscfg file for set number 'setnumber'
5578 * If it does not match the user's data, 'data', then print the error
5579 * message using the friendly field name 'ufield'.
5580 * Never returns on an error.
5583 checkgfield(CFGFILE
*cfg
, int setnumber
, char *fname
, char *ufield
, char *data
)
5585 char buf
[CFG_MAX_BUF
];
5586 char key
[CFG_MAX_KEY
];
5588 (void) snprintf(key
, sizeof (key
), "sndr.set%d.%s", setnumber
, fname
);
5589 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
5590 rdc_err(NULL
, gettext("unable to fetch data for key %s"),
5593 if (strcmp(buf
, data
) != 0) {
5595 gettext("the value specified for the %s field is not\nthe "
5596 "same as that contained within the configuration storage "
5597 "file for this set.\nYou specified \"%s\" "
5598 "expected \"%s\"."),
5604 * load and send the contents of the bitmap file to the kernel.
5607 rdc_bitmapset(char *tohost
, char *tofile
, char *bitmap
, int op
,
5610 rdc_bitmap_op_t bmop
;
5618 * open bitmap file for reading.
5620 if ((fd
= open(bitmap
, O_RDONLY
)) < 0) {
5621 rdc_warn(NULL
, gettext("Unable to open bitmap file %s"),
5625 (void) fstat(fd
, &s
);
5627 if (S_ISREG(s
.st_mode
) == 0) {
5628 rdc_warn(NULL
, gettext("Bitmap %s is not a regular file"),
5638 * use the file size to allocate buffer. This
5639 * size should be a multiple of FBA, but don't check
5642 buffersz
= s
.st_size
;
5643 buffer
= malloc(buffersz
);
5644 if (buffer
== NULL
) {
5645 rdc_warn(NULL
, gettext("Unable to allocate %d bytes "
5646 "for bitmap file %s"), buffersz
, bitmap
);
5650 n
= read(fd
, buffer
, buffersz
);
5652 if (n
!= buffersz
) {
5653 rdc_warn(NULL
, gettext("Unable to read the bitmap file, "
5654 "read returned %d instead of %d"),
5659 bmop
.offset
= offset
;
5661 (void) strncpy(bmop
.sechost
, tohost
, MAX_RDC_HOST_SIZE
);
5662 (void) strncpy(bmop
.secfile
, tofile
, NSC_MAXPATH
);
5663 bmop
.len
= buffersz
;
5664 bmop
.addr
= (unsigned long)buffer
;
5665 ret
= rdc_ioctl_simple(RDC_BITMAPOP
, &bmop
);
5668 rdc_warn(NULL
, gettext("Setting bitmap ioctl failed for set "
5669 "%s:%s"), tohost
, tofile
);
5673 rdc_warn(NULL
, gettext("One of the sets is not "
5677 rdc_warn(NULL
, gettext("One of the sets is not "
5692 * verify_groupname: Check the group name for the following rules:
5693 * 1. The name does not start with a '-'
5694 * 2. The name does not contain any space characters as defined by
5697 * If either of these rules are broken, error immediately.
5700 verify_groupname(char *grp
)
5704 if (grp
[0] == '-') {
5705 rdc_err(NULL
, gettext("group name cannot start with a '-'"));
5708 for (i
= 0; grp
[i
] != '\0'; i
++) {
5709 if (isspace(grp
[i
])) {
5710 rdc_err(NULL
, gettext("group name cannot contain a "