4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/utsname.h>
28 #include <sys/mdb_modapi.h>
36 #include <sys/stream.h>
37 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
45 #include <sys/unistat/spcs_s.h>
46 #include <sys/unistat/spcs_s_u.h>
47 #include <sys/unistat/spcs_s_impl.h>
48 #include <sys/unistat/spcs_errors.h>
50 #include <sys/nsctl/rdc_io.h>
51 #include <sys/nsctl/rdc_ioctl.h>
52 #include <sys/nsctl/rdc_prot.h>
53 #include <sys/nsctl/librdc.h>
54 #include <sys/nsctl/rdcerr.h>
55 #include <sys/nsctl/cfg.h>
57 #include <sys/unistat/spcs_dtrinkets.h>
58 #include <sys/unistat/spcs_etrinkets.h>
60 #include <sys/socket.h>
61 #include <sys/mnttab.h>
62 #include <netinet/in.h>
63 #include <arpa/inet.h>
64 #include <netinet/tcp.h>
65 #include <rpc/rpc_com.h>
68 #define RDC_LOCAL_TAG "local"
73 * return 0 if not in use
78 bitmap_in_use(int cmd
, char *hostp
, char *bmp
)
82 char host
[CFG_MAX_BUF
];
83 char shost
[CFG_MAX_BUF
];
84 char pri
[CFG_MAX_BUF
]; /* rdc primary vol */
85 char sec
[CFG_MAX_BUF
]; /* rdc secondary vol */
86 char sbm
[CFG_MAX_BUF
]; /* rdc secondary bitmap */
87 char bit
[CFG_MAX_BUF
]; /* a bitmap */
88 char mas
[CFG_MAX_BUF
]; /* II master */
89 char sha
[CFG_MAX_BUF
]; /* II shadow */
90 char mod
[CFG_MAX_BUF
]; /* II mode */
91 char ovr
[CFG_MAX_BUF
]; /* II overflow */
92 char buf
[CFG_MAX_BUF
];
93 char key
[CFG_MAX_KEY
];
98 if ((cfg
= cfg_open(NULL
)) == NULL
) {
99 rdc_set_error(NULL
, RDC_DSCFG
, 0, NULL
);
102 if (!cfg_lock(cfg
, CFG_RDLOCK
)) {
103 rdc_set_error(NULL
, RDC_DSCFG
, 0, NULL
);
109 * look into II config to see if this is being used elsewhere
114 snprintf(key
, sizeof (key
), "ii.set%d", setnumber
);
115 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
118 rc
= sscanf(buf
, "%s %s %s %s %s", mas
, sha
, bit
, mod
, ovr
);
120 rdc_set_error(NULL
, RDC_OS
, 0, NULL
);
126 * got master shadow bitmap, now compare
128 if ((strcmp(bmp
, mas
) == 0) ||
129 (strcmp(bmp
, sha
) == 0) ||
130 (strcmp(bmp
, bit
) == 0) ||
131 (strcmp(bmp
, ovr
) == 0)) {
132 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
133 "bitmap %s is in use by"
134 "Point-in-Time Copy", bmp
);
140 * and last but not least, make sure sndr is not using vol for anything
145 snprintf(key
, sizeof (key
), "sndr.set%d", setnumber
);
146 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
149 * I think this is quicker than
150 * having to double dip into the config
152 (void) sscanf(buf
, "%s %s %s %s %s %s", host
, pri
, bit
,
154 if (cmd
== RDC_CMD_ENABLE
) {
155 if (self_check(host
)) {
156 if ((strcmp(bmp
, pri
) == 0) ||
157 (strcmp(bmp
, bit
) == 0)) {
158 rdc_set_error(NULL
, RDC_INTERNAL
,
159 RDC_NONFATAL
, dgettext("librdc",
160 "bitmap %s is in use by %s"),
161 bmp
, RDC_NAME_DU_JOUR
);
168 if ((strcmp(bmp
, sec
) == 0) ||
169 (strcmp(bmp
, sbm
) == 0)) {
170 rdc_set_error(NULL
, RDC_INTERNAL
,
171 RDC_NONFATAL
, dgettext("librdc",
172 "bitmap %s is in use by %s"),
173 bmp
, RDC_NAME_DU_JOUR
);
178 } else if (cmd
== RDC_CMD_RECONFIG
) {
181 * read this logic 1000 times and consider
182 * multi homed, one to many, many to one (marketing)
183 * etc, etc, before changing
185 if (self_check(hostp
)) {
186 if (self_check(host
)) {
187 if ((strcmp(bmp
, pri
) == 0) ||
188 (strcmp(bmp
, bit
) == 0)) {
190 RDC_INTERNAL
, RDC_NONFATAL
,
191 dgettext("librdc", "bitmap"
192 " %s is in use by %s"),
193 bmp
, RDC_NAME_DU_JOUR
);
198 if ((strcmp(hostp
, shost
) == 0) &&
199 (strcmp(bmp
, sec
) == 0) ||
200 (strcmp(bmp
, sbm
) == 0)) {
202 RDC_INTERNAL
, RDC_NONFATAL
,
203 dgettext("librdc", "bitmap"
204 " %s is in use by %s"),
205 bmp
, RDC_NAME_DU_JOUR
);
210 } else { /* self_check(hostp) failed */
211 if (self_check(host
)) {
212 if ((strcmp(shost
, hostp
) == 0) &&
213 (strcmp(bmp
, sec
) == 0) ||
214 (strcmp(bmp
, sbm
) == 0)) {
216 RDC_INTERNAL
, RDC_NONFATAL
,
217 dgettext("librdc", "bitmap"
218 " %s is in use by %s"),
219 bmp
, RDC_NAME_DU_JOUR
);
224 if ((strcmp(host
, hostp
) == 0) &&
225 (strcmp(bmp
, pri
) == 0) ||
226 (strcmp(bmp
, bit
) == 0)) {
228 RDC_INTERNAL
, RDC_NONFATAL
,
229 dgettext("librdc", "bitmap"
230 " %s is in use by %s"),
231 bmp
, RDC_NAME_DU_JOUR
);
248 check_dgislocal(char *dgname
)
254 * check where this disk service is mastered
257 rc
= cfg_dgname_islocal(dgname
, &othernode
);
259 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
260 gettext("unable to find "
261 "disk service, %s: %s"), dgname
, strerror(errno
));
266 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
267 gettext("disk service, %s, is "
268 "active on node \"%s\"\nPlease re-issue "
269 "the command on that node"), dgname
, othernode
);
276 ctag_check(rdcconfig_t
*rdc
)
280 char *fromhost
, *tohost
;
281 char *fromfile
, *tofile
;
282 char *frombitmap
, *tobitmap
;
285 char file_buf
[MAX_RDC_HOST_SIZE
];
286 char bmp_buf
[MAX_RDC_HOST_SIZE
];
290 char fromname
[MAXHOSTNAMELEN
], toname
[MAXHOSTNAMELEN
];
292 fromhost
= rdc
->phost
;
293 fromfile
= rdc
->pfile
;
294 frombitmap
= rdc
->pbmp
;
297 tobitmap
= rdc
->sbmp
;
301 * Check for the special (local) cluster tag
303 if (!cfg_iscluster())
306 if (ctag
!= NULL
&& strcmp(rdc
->ctag
, RDC_LOCAL_TAG
) == 0) {
307 strcpy(rdc
->ctag
, "-");
313 hp
= gethost_byname(fromhost
);
314 strncpy(fromname
, hp
->h_name
, MAXHOSTNAMELEN
);
315 hp
= gethost_byname(tohost
);
316 strncpy(toname
, hp
->h_name
, MAXHOSTNAMELEN
);
317 if (!self_check(fromname
) && !self_check(toname
)) {
319 * If we could get a list of logical hosts on this cluster
320 * then we could print something intelligent about where
321 * the volume is mastered. For now, just print some babble
322 * about the fact that we have no idea.
324 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
325 gettext("either %s:%s or %s:%s is not local"),
326 fromhost
, fromfile
, tohost
, tofile
);
330 is_primary
= self_check(fromname
);
333 * If implicit disk group name and no ctag specified by user,
334 * we set the ctag to it.
335 * If implicit disk group name, it must match any supplied ctag.
338 localfile
= fromfile
;
341 file_dgname
= cfg_dgname(localfile
, file_buf
, sizeof (file_buf
));
342 if (file_dgname
!= NULL
&& file_dgname
[0] != '\0')
343 if (check_dgislocal(file_dgname
) < 0) {
344 /* errors already set */
348 if (strlen(ctag
) == 0 && file_dgname
&& strlen(file_dgname
))
349 strncpy(ctag
, file_dgname
, MAX_RDC_HOST_SIZE
);
352 * making an exception here for users giving the "local"tag
353 * this overrides this error message. (rdc_islocal ! = 1)
355 if (strlen(ctag
) != 0 && file_dgname
&& islocal
!= 1 &&
356 strlen(file_dgname
) != 0 &&
357 strncmp(ctag
, file_dgname
, MAX_RDC_HOST_SIZE
) != 0) {
358 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
359 gettext("ctag \"%s\" does not "
360 "match disk group name \"%s\" of volume %s"), ctag
,
361 file_dgname
, localfile
);
364 if ((file_dgname
== NULL
) || ((strlen(ctag
) == 0) &&
365 (strlen(file_dgname
) == 0))) {
367 * we must have a non-volume managed disk here
368 * so ask for a tag and get out
370 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
371 gettext("volume \"%s\" is not part"
372 " of a disk group,\nplease specify resource ctag\n"),
378 * Local bitmap must also have same ctag.
381 localfile
= frombitmap
;
383 localfile
= tobitmap
;
384 bmp_dgname
= cfg_dgname(localfile
, bmp_buf
, sizeof (bmp_buf
));
385 if (bmp_dgname
!= NULL
&& bmp_dgname
[0] != '\0')
386 if (check_dgislocal(bmp_dgname
) < 0) {
387 /* error already set */
391 if (file_dgname
&& strlen(file_dgname
) != 0) {
392 /* File is in a real disk group */
393 if ((bmp_dgname
== NULL
) || (strlen(bmp_dgname
) == 0)) {
394 /* Bitmap is not in a real disk group */
395 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
396 gettext("bitmap %s is not in disk group \"%s\""),
397 localfile
, islocal
< 1?file_dgname
:ctag
);
401 if (strlen(ctag
) != 0 && bmp_dgname
&& islocal
!= 1 &&
402 strlen(bmp_dgname
) != 0 &&
403 strncmp(ctag
, bmp_dgname
, MAX_RDC_HOST_SIZE
) != 0) {
404 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
405 gettext("ctag \"%s\" does not "
406 "match disk group name \"%s\" of bitmap %s"),
407 ctag
, bmp_dgname
, localfile
);
414 mounted(char *device
)
416 char target
[NSC_MAXPATH
];
417 struct mnttab mntref
;
418 struct mnttab mntent
;
426 for (s
= target
; i
< NSC_MAXPATH
&& (*s
= *device
++); i
++) {
427 if (*s
== 'r' && rdsk
== 0 && strncmp(device
, "dsk/", 4) == 0)
434 mntref
.mnt_special
= target
;
435 mntref
.mnt_mountp
= NULL
;
436 mntref
.mnt_fstype
= NULL
;
437 mntref
.mnt_mntopts
= NULL
;
438 mntref
.mnt_time
= NULL
;
440 mntfp
= fopen(MNTTAB
, "r");
443 /* Assume the worst, that it is mounted */
447 if ((rc
= getmntany(mntfp
, &mntent
, &mntref
)) != -1) {
448 /* found something before EOF */
458 can_enable(rdcconfig_t
*rdc
)
462 if ((strcmp(rdc
->pfile
, rdc
->pbmp
) == 0) ||
463 (strcmp(rdc
->sfile
, rdc
->sbmp
) == 0)) {
464 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
465 dgettext("librdc", "volumes and bitmaps must not match"));
468 if (ctag_check(rdc
) < 0) {
469 /* rdc_error should already be set */
473 if (self_check(rdc
->phost
)) {
474 if (stat(rdc
->pfile
, &stb
) != 0) {
475 rdc_set_error(NULL
, RDC_OS
, RDC_FATAL
, NULL
);
478 if (!S_ISCHR(stb
.st_mode
)) {
479 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
480 dgettext("librdc", "%s is not a character device"),
484 return (rdc
->persist
?
485 !bitmap_in_use(RDC_CMD_ENABLE
, rdc
->phost
, rdc
->pbmp
) : 1);
486 } else { /* on the secondary */
487 if (stat(rdc
->sfile
, &stb
) != 0) {
488 rdc_set_error(NULL
, RDC_OS
, 0,
489 dgettext("librdc", "unable to access %s: %s"),
490 rdc
->sfile
, strerror(errno
));
492 if (!S_ISCHR(stb
.st_mode
)) {
493 rdc_set_error(NULL
, RDC_INTERNAL
, RDC_NONFATAL
,
495 "%s is not a character device"), rdc
->sfile
);
497 return (rdc
->persist
?
498 !bitmap_in_use(RDC_CMD_ENABLE
, rdc
->shost
, rdc
->sbmp
) : 1);
503 can_reconfig_pbmp(rdcconfig_t
*rdc
, char *bmp
)
508 return (!bitmap_in_use(RDC_CMD_RECONFIG
, rdc
->phost
, bmp
));
512 can_reconfig_sbmp(rdcconfig_t
*rdc
, char *bmp
)
517 return (!bitmap_in_use(RDC_CMD_RECONFIG
, rdc
->shost
, bmp
));
521 cant_rsync(rdcconfig_t
*rdc
)
525 if (mounted(rdc
->pfile
)) {
529 strncpy(rc
->set
.phost
, rdc
->phost
, MAX_RDC_HOST_SIZE
);
530 strncpy(rc
->set
.pfile
, rdc
->pfile
, NSC_MAXPATH
);
531 strncpy(rc
->set
.pbmp
, rdc
->pbmp
, NSC_MAXPATH
);
532 strncpy(rc
->set
.shost
, rdc
->shost
, MAX_RDC_HOST_SIZE
);
533 strncpy(rc
->set
.sfile
, rdc
->sfile
, NSC_MAXPATH
);
534 strncpy(rc
->set
.sbmp
, rdc
->sbmp
, NSC_MAXPATH
);
538 rdc_set_error(NULL
, RDC_INTERNAL
, 0, "unable to sync %s volume"
539 " is currently mounted", rdc
->pfile
);
540 strncpy(rc
->msg
, rdc_error(NULL
), RDC_ERR_SIZE
);