1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/utsname.h> 29 #include <sys/wait.h> 30 #include <stdio.h> 31 #include <errno.h> 32 #include <values.h> 33 #include <limits.h> 34 #include <fcntl.h> 35 #include <strings.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 #include <sys/stat.h> 39 40 #include <locale.h> 41 #include <langinfo.h> 42 #include <libintl.h> 43 #include <stdarg.h> 44 #include <netdb.h> 45 #include <ctype.h> 46 47 #include <sys/nsctl/rdc_io.h> 48 #include <sys/nsctl/rdc_ioctl.h> 49 #include <sys/nsctl/rdc_prot.h> 50 51 #include <sys/nsctl/cfg.h> 52 53 #include <sys/unistat/spcs_s.h> 54 #include <sys/unistat/spcs_s_u.h> 55 #include <sys/unistat/spcs_errors.h> 56 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> 62 #include <rpc/rpc.h> 63 64 #include <sys/nsctl/librdc.h> 65 #include <sys/nsctl/nsc_hash.h> 66 67 #include "rdcadm.h" 68 69 /* 70 * support for the special cluster tag "local" to be used with -C in a 71 * cluster for local volumes. 72 */ 73 74 #define RDC_LOCAL_TAG "local" 75 76 typedef struct volcount_s { 77 int count; 78 } volcount_t; 79 hash_node_t **volhash = NULL; 80 81 /* 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 91 */ 92 static int rdc_islocal = 0; 93 94 char *program; 95 96 #define min(a, b) ((a) > (b) ? (b) : (a)) 97 98 static char place_holder[] = "-"; /* cfg place holder value */ 99 100 /* 101 * config file user level Dual copy pair structure 102 */ 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 */ 117 } _sd_dual_pair_t; 118 119 #define EXTRA_ARGS 6 /* g grp C ctag q diskqueue */ 120 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); 130 void q_usage(int); 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 *); 146 147 int rdc_maxsets; 148 static _sd_dual_pair_t *pair_list; 149 150 struct netbuf svaddr; 151 struct netbuf *svp; 152 struct netconfig nconf; 153 struct netconfig *conf; 154 struct knetconfig knconf; 155 156 static char *reconfig_pbitmap = NULL; 157 static char *reconfig_sbitmap = NULL; 158 #ifdef _RDC_CAMPUS 159 static char *reconfig_direct = NULL; 160 #endif 161 static char *reconfig_group = NULL; 162 static char reconfig_ctag[MAX_RDC_HOST_SIZE]; 163 static int reconfig_doasync = -1; 164 165 static int clustered = 0; 166 static int proto_test = 0; 167 int allow_role = 0; 168 169 170 static char * 171 rdc_print_state(rdc_set_t *urdc) 172 { 173 if (!urdc) 174 return (""); 175 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")); 191 else 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")); 196 else 197 return (gettext("syncing")); 198 } else if (urdc->flags & RDC_SYNCING) { 199 if (urdc->flags & RDC_PRIMARY) 200 return (gettext("syncing")); 201 else 202 return (gettext("reverse syncing")); 203 } 204 205 return (gettext("replicating")); 206 } 207 208 209 static int 210 rdc_print(int file_format, int verbose, char *group_arg, char *ctag_arg, 211 char *user_shost, char *user_sdev, CFGFILE *cfgp) 212 { 213 rdc_status_t *rdc_status; 214 spcs_s_info_t ustatus; 215 rdc_set_t *urdc; 216 size_t size; 217 int i, rc, max; 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; 230 CFGFILE *cfg; 231 int j; 232 int setnumber; 233 char key[CFG_MAX_KEY]; 234 char buf[CFG_MAX_BUF]; 235 char sync[16]; 236 int match, found; 237 238 size = sizeof (rdc_status_t) + (sizeof (rdc_set_t) * (rdc_maxsets - 1)); 239 match = (user_shost != NULL || user_sdev != NULL); 240 found = 0; 241 242 if (user_shost == NULL && user_sdev != NULL) 243 user_shost = ""; 244 else if (user_shost != NULL && user_sdev == NULL) 245 user_sdev = ""; 246 247 rdc_status = malloc(size); 248 if (!rdc_status) { 249 rdc_err(NULL, 250 gettext("unable to allocate %ld bytes"), size); 251 } 252 253 rdc_status->nset = rdc_maxsets; 254 ustatus = spcs_s_ucreate(); 255 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")); 259 } 260 261 spcs_s_ufree(&ustatus); 262 263 max = min(rdc_status->nset, rdc_maxsets); 264 265 if (cfgp != NULL) { 266 cfg = cfgp; 267 cfg_rewind(cfg, CFG_SEC_CONF); 268 } else { 269 if ((cfg = cfg_open(NULL)) == NULL) 270 rdc_err(NULL, 271 gettext("unable to access configuration")); 272 273 if (!cfg_lock(cfg, CFG_RDLOCK)) 274 rdc_err(NULL, gettext("unable to lock configuration")); 275 } 276 277 for (i = 0; i < max; i++) { 278 urdc = &rdc_status->rdc_set[i]; 279 280 if (!(urdc->flags & RDC_ENABLED)) 281 continue; 282 283 if (match && 284 (strcmp(user_shost, urdc->secondary.intf) != 0 || 285 strcmp(user_sdev, urdc->secondary.file) != 0)) 286 continue; 287 288 tohost = urdc->secondary.intf; 289 tofile = urdc->secondary.file; 290 found = 1; 291 292 /* get sndr entries until shost, sfile match */ 293 for (j = 0; j < rdc_maxsets; j++) { 294 setnumber = j + 1; 295 (void) snprintf(key, sizeof (key), 296 "sndr.set%d", setnumber); 297 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { 298 break; 299 } 300 301 if (parse_cfg_buf(buf, &pair, NULL)) 302 rdc_err(NULL, gettext("cfg input error")); 303 304 if (strcmp(tmptofile, tofile) != 0) 305 continue; 306 if (strcmp(tmptohost, tohost) != 0) 307 continue; 308 309 if (pair.doasync == 0) 310 (void) strcpy(sync, "sync"); 311 else 312 (void) strcpy(sync, "async"); 313 314 /* Got the matching entry */ 315 316 break; 317 } 318 319 if (j == rdc_maxsets) 320 continue; /* not found in config */ 321 322 if (strcmp(group_arg, "") != 0 && 323 strncmp(group_arg, group, NSC_MAXPATH) != 0) 324 continue; 325 326 if (strcmp(ctag_arg, "") != 0 && 327 strncmp(ctag_arg, ctag, MAX_RDC_HOST_SIZE) != 0) 328 continue; 329 330 if (file_format) { 331 (void) printf("%s %s %s %s %s %s %s %s", 332 fromhost, fromfile, frombitmap, 333 tohost, tofile, tobitmap, 334 directfile, sync); 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); 341 (void) printf("\n"); 342 continue; 343 } 344 345 if (strcmp(group_arg, "") != 0 && 346 strncmp(group_arg, urdc->group_name, NSC_MAXPATH) != 0) 347 continue; 348 349 if (!(urdc->flags & RDC_PRIMARY)) { 350 (void) printf(gettext("%s\t<-\t%s:%s\n"), 351 urdc->secondary.file, urdc->primary.intf, 352 urdc->primary.file); 353 } else { 354 (void) printf(gettext("%s\t->\t%s:%s\n"), 355 urdc->primary.file, urdc->secondary.intf, 356 urdc->secondary.file); 357 } 358 if (!verbose) 359 continue; 360 361 if (urdc->autosync) 362 (void) printf(gettext("autosync: on")); 363 else 364 (void) printf(gettext("autosync: off")); 365 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"), 369 urdc->asyncthr); 370 (void) printf(gettext(", mode: %s"), 371 pair.doasync ? "async" : "sync"); 372 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); 381 } 382 383 (void) printf(gettext(", state: %s"), rdc_print_state(urdc)); 384 (void) printf(gettext("\n")); 385 386 } 387 388 if (!cfgp) 389 cfg_close(cfg); 390 391 free(rdc_status); 392 393 if (match && !found) { 394 rdc_warn(NULL, gettext("unable to find set %s:%s"), 395 user_shost, user_sdev); 396 } 397 398 return (0); 399 } 400 401 402 int 403 parse_extras(int argc, char *args[], int i) 404 { 405 int gflag = 0; 406 int Cflag = 0; 407 int qflag = 0; 408 int j; 409 410 (void) strcpy(pair_list[i].ctag, ""); 411 (void) strcpy(pair_list[i].group, ""); 412 (void) strcpy(pair_list[i].diskqueue, ""); 413 414 if (argc == 0) 415 return (0); 416 417 if (argc != 2 && argc != 4 && argc != 6) 418 return (-1); 419 420 for (j = 0; j < argc; j += 2) { 421 if (strcmp(args[j], "g") == 0) { 422 if (gflag) 423 return (-1); 424 (void) strncpy(pair_list[i].group, args[j + 1], 425 NSC_MAXPATH); 426 gflag = 1; 427 } 428 if (strcmp(args[j], "C") == 0) { 429 if (!clustered) 430 return (-1); 431 if (Cflag) 432 return (-1); 433 (void) strncpy(pair_list[i].ctag, args[j + 1], 434 MAX_RDC_HOST_SIZE); 435 process_clocal(pair_list[i].ctag); 436 Cflag = 1; 437 } 438 if (strcmp(args[j], "q") == 0) { 439 if (qflag) 440 return (-1); 441 (void) strncpy(pair_list[i].diskqueue, args[j + 1], 442 NSC_MAXPATH); 443 qflag = 1; 444 } 445 } 446 447 return (0); 448 } 449 450 static int 451 parse_cfg_buf(char *buf, _sd_dual_pair_t *pair, char *lghn) 452 { 453 int rc = 0; 454 char sync[16]; 455 char options[64], *p, *q; 456 int len; 457 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); 462 463 if (rc != 12) 464 rdc_err(NULL, gettext("cfg input error")); 465 466 if (strcmp(pair->diskqueue, place_holder) == 0) 467 (void) strcpy(pair->diskqueue, ""); 468 469 if (strcmp(pair->group, place_holder) == 0) 470 (void) strcpy(pair->group, ""); 471 472 if (strcmp(sync, "sync") == 0) 473 pair->doasync = 0; 474 else if (strcmp(sync, "async") == 0) 475 pair->doasync = 1; 476 else { 477 rdc_err(NULL, 478 gettext("set %s:%s neither sync nor async"), 479 pair->thost, pair->tfile); 480 } 481 482 if (lghn && (p = strstr(options, "lghn="))) { 483 p += 5; 484 q = strchr(p, ';'); 485 if (q) { 486 /* LINTED p & q limited to options[64] */ 487 len = q - p; 488 } else { 489 len = strlen(p); 490 } 491 (void) strncpy(lghn, p, len); 492 lghn[len] = '\0'; 493 } else if (lghn) { 494 *lghn = '\0'; 495 } 496 497 return (0); 498 } 499 500 static int 501 ctag_check(char *fromhost, char *fromfile, char *frombitmap, char *tohost, 502 char *tofile, char *tobitmap, char *ctag, char *diskq) 503 { 504 char *file_dgname; 505 char *bmp_dgname; 506 char *que_dgname; 507 char *localfile; 508 char file_buf[MAX_RDC_HOST_SIZE]; 509 char bmp_buf[MAX_RDC_HOST_SIZE]; 510 char que_buf[NSC_MAXPATH]; 511 int is_primary; 512 struct hostent *hp; 513 char fromname[MAXHOSTNAMELEN], toname[MAXHOSTNAMELEN]; 514 515 if (!clustered) 516 return (0); 517 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)) { 523 /* 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. 528 */ 529 rdc_err(NULL, 530 gettext("either %s:%s or %s:%s is not local"), 531 fromhost, fromfile, tohost, tofile); 532 } 533 534 is_primary = self_check(fromname); 535 536 /* 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. 540 */ 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); 545 546 /* 547 * Autogenerate a ctag, if not "-C local" or no "-C " specified 548 */ 549 if (!rdc_islocal && !strlen(ctag) && file_dgname && strlen(file_dgname)) 550 (void) strncpy(ctag, file_dgname, MAX_RDC_HOST_SIZE); 551 552 /* 553 * making an exception here for users giving the "local"tag 554 * this overrides this error message. (rdc_islocal ! = 1) 555 */ 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); 562 return (-1); 563 } 564 565 /* 566 * Do we have a non-volume managed disk without -C local specified? 567 */ 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"), 571 localfile); 572 } 573 574 /* 575 * Do we have a volume managed disk with -C local? 576 */ 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); 580 } 581 582 /* 583 * Local bitmap must also have same ctag. 584 */ 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); 589 590 /* 591 * Assure that if the primary has a device group, so must the bitmap 592 */ 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); 597 return (-1); 598 } 599 600 /* 601 * Assure that if the if there is a ctag, it must match the bitmap 602 */ 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); 609 return (-1); 610 } 611 612 /* 613 * If this is the SNDR primary and there is a local disk queue 614 */ 615 if (is_primary && diskq[0]) { 616 617 /* 618 * Local disk queue must also have same ctag. 619 */ 620 que_dgname = cfg_dgname(diskq, que_buf, sizeof (que_buf)); 621 if (que_dgname && strlen(que_dgname)) 622 rdc_check_dgislocal(que_dgname); 623 624 /* 625 * Assure that if the primary has a device group, so must 626 * the disk queue 627 */ 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); 633 return (-1); 634 } 635 636 /* 637 * Assure that if the if there is a ctag, it must match 638 * the disk queue 639 */ 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); 646 return (-1); 647 } 648 } 649 650 return (0); 651 } 652 653 #define DISKQ_OKAY 0 654 #define DISKQ_FAIL 1 655 #define DISKQ_REWRITEG 2 656 /* 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 659 * are different. 660 * 661 * if newq is not set but should be, it will be set to the correct value. 662 * returns: 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. 666 */ 667 static int 668 check_diskqueue(CFGFILE *cfg, char *newq, char *newgroup) 669 { 670 int i, setnumber; 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; 677 678 679 if (newgroup == NULL || *newgroup == '\0') { 680 if (*newq == '\0') 681 return (DISKQ_OKAY); /* okay, */ 682 newgroup = "--nomatch--"; 683 } 684 685 if (open_cfg) { 686 if ((cfg = cfg_open(NULL)) == NULL) 687 rdc_err(NULL, 688 gettext("unable to access configuration")); 689 if (!cfg_lock(cfg, CFG_RDLOCK)) 690 rdc_err(NULL, gettext("unable to lock configuration")); 691 } 692 693 /*CSTYLED*/ 694 for (i = 0; ; i++) { 695 setnumber = i + 1; 696 (void) snprintf(key, sizeof (key), "sndr.set%d", setnumber); 697 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 698 break; 699 /* 700 * I think this is quicker than 701 * having to double dip into the config 702 */ 703 if (parse_cfg_buf(buf, &pair, NULL)) 704 rdc_err(NULL, gettext("cfg input error")); 705 706 if (strncmp(group, newgroup, NSC_MAXPATH) != 0) { 707 if (((strncmp(diskqueue, newq, NSC_MAXPATH) == 0)) && 708 (diskqueue[0] != '\0')) { 709 if (open_cfg) 710 cfg_close(cfg); 711 return (DISKQ_FAIL); 712 } 713 continue; 714 } 715 if (*newq == '\0') { 716 if (diskqueue[0] != '\0') 717 (void) strncpy(newq, diskqueue, NSC_MAXPATH); 718 if (open_cfg) 719 cfg_close(cfg); 720 return (DISKQ_OKAY); /* okay, */ 721 } 722 723 if (open_cfg) 724 cfg_close(cfg); 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); 729 } 730 if (open_cfg) 731 cfg_close(cfg); 732 return (DISKQ_OKAY); 733 } 734 735 736 int 737 pair_diskqueue_check(int newpair) 738 { 739 int i, j; 740 int rc; 741 742 for (i = 0; i < newpair; i++) { 743 if (strcmp(pair_list[i].group, pair_list[newpair].group) != 0) 744 continue; 745 if (strcmp(pair_list[i].diskqueue, pair_list[newpair].diskqueue) 746 == 0) 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')) { 751 rdc_warn(NULL, 752 gettext("disk queue %s does not match %s " 753 "skipping set"), pair_list[newpair].diskqueue, 754 pair_list[i].diskqueue); 755 return (DISKQ_FAIL); 756 } 757 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 */ 763 } 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, 772 NSC_MAXPATH); 773 } 774 } 775 return (DISKQ_OKAY); 776 } 777 break; /* no problem with pair_list sets */ 778 779 } 780 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) 788 continue; 789 790 (void) strncpy(pair_list[i].diskqueue, 791 pair_list[newpair].diskqueue, NSC_MAXPATH); 792 } 793 } 794 return (rc); 795 } 796 797 int 798 ii_set_exists(CFGFILE *cfg, char *ma, char *sh, char *bm) 799 { 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]; 805 int i; 806 807 for (i = 1; ; i++) { 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) 813 break; 814 (void) sscanf(buf, "%s %s %s", master, shadow, bitmap); 815 if (strcmp(master, ma) != 0) 816 continue; 817 if (strcmp(shadow, sh) != 0) 818 continue; 819 if (strcmp(bitmap, bm) != 0) 820 continue; 821 return (1); 822 } 823 return (0); 824 } 825 826 void 827 rdc_ii_config(int argc, char **argv) 828 { 829 char *master; 830 char *shadow; 831 char *bitmap; 832 char c; 833 CFGFILE *cfg; 834 int i; 835 int setnumber; 836 char key[CFG_MAX_KEY]; 837 char buf[CFG_MAX_BUF]; 838 int found; 839 int sev; 840 841 /* Parse the rest of the arguments to see what to do */ 842 843 if (argc - optind != 4) { 844 usage(); 845 exit(1); 846 } 847 848 c = *argv[optind]; 849 switch (c) { 850 case 'd': 851 /* Delete an ndr_ii entry */ 852 853 master = argv[++optind]; 854 shadow = argv[++optind]; 855 bitmap = argv[++optind]; 856 857 if ((cfg = cfg_open(NULL)) == NULL) 858 rdc_err(NULL, 859 gettext("unable to access configuration")); 860 if (!cfg_lock(cfg, CFG_WRLOCK)) 861 rdc_err(NULL, gettext("unable to lock configuration")); 862 863 found = 0; 864 /* get ndr_ii entries until a match is found */ 865 /*CSTYLED*/ 866 for (i = 0; ; i++) { 867 setnumber = i + 1; 868 869 (void) snprintf(key, sizeof (key), 870 "ndr_ii.set%d.secondary", 871 setnumber); 872 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 873 break; 874 if (strcmp(buf, master) != 0) 875 continue; 876 877 /* Got a matching entry */ 878 879 (void) snprintf(key, sizeof (key), 880 "ndr_ii.set%d.shadow", 881 setnumber); 882 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 883 break; 884 if (strcmp(buf, shadow) != 0) 885 continue; 886 887 (void) snprintf(key, sizeof (key), 888 "ndr_ii.set%d.bitmap", 889 setnumber); 890 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 891 break; 892 if (strcmp(buf, bitmap) != 0) 893 continue; 894 895 (void) snprintf(key, sizeof (key), 896 "ndr_ii.set%d", setnumber); 897 if (cfg_put_cstring(cfg, key, NULL, 0) < 0) { 898 rdc_warn(NULL, 899 gettext("unable to remove \"%s\" " 900 "from configuration storage: %s"), 901 key, cfg_error(&sev)); 902 } else { 903 if (cfg_commit(cfg) < 0) 904 rdc_err(NULL, 905 gettext("ndr_ii set %s %s %s " 906 "not deconfigured."), 907 master, shadow, bitmap); 908 else 909 spcs_log("sndr", NULL, 910 gettext("ndr_ii set %s %s %s " 911 "has been deconfigured."), 912 master, shadow, bitmap); 913 } 914 found = 1; 915 break; 916 } 917 918 if (!found) { 919 rdc_err(NULL, 920 gettext("did not find matching ndr_ii " 921 "entry for %s %s %s"), master, shadow, bitmap); 922 } 923 924 cfg_close(cfg); 925 926 break; 927 928 case 'a': 929 /* Add an ndr_ii entry */ 930 931 master = argv[++optind]; 932 shadow = argv[++optind]; 933 bitmap = argv[++optind]; 934 935 if ((cfg = cfg_open(NULL)) == NULL) 936 rdc_err(NULL, 937 gettext("unable to access configuration")); 938 if (!cfg_lock(cfg, CFG_WRLOCK)) 939 rdc_err(NULL, gettext("unable to lock configuration")); 940 941 found = 0; 942 /* get ndr_ii entries in case a match is found */ 943 /*CSTYLED*/ 944 for (i = 0; ; i++) { 945 setnumber = i + 1; 946 947 (void) snprintf(key, sizeof (key), 948 "ndr_ii.set%d.secondary", 949 setnumber); 950 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 951 break; 952 if (strcmp(buf, master) == 0) { 953 rdc_err(NULL, 954 gettext("found matching ndr_ii " 955 "entry for %s"), master); 956 } 957 } 958 /* 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 963 * before we get here 964 */ 965 /*CSTYLED*/ 966 for (i = 0; ; i++) { 967 setnumber = i + 1; 968 969 /* 970 * Checking local bitmaps 971 */ 972 (void) snprintf(key, sizeof (key), "sndr.set%d.phost", 973 setnumber); 974 975 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 976 break; 977 if (self_check(buf)) { 978 (void) snprintf(key, sizeof (key), 979 "sndr.set%d.pbitmap", 980 setnumber); 981 } else { 982 (void) snprintf(key, sizeof (key), 983 "sndr.set%d.sbitmap", 984 setnumber); 985 } 986 987 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 988 break; 989 990 if ((strcmp(buf, bitmap) == 0) || 991 (strcmp(buf, master) == 0) || 992 (strcmp(buf, shadow) == 0)) { 993 rdc_err(NULL, 994 gettext("%s is already configured " 995 "as a Remote Mirror bitmap"), buf); 996 } 997 } 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); 1011 } else { 1012 spcs_log("sndr", NULL, gettext("ndr_ii set " 1013 "%s %s %s has been configured."), 1014 master, shadow, bitmap); 1015 } 1016 1017 /* 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 1020 */ 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}; 1025 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); 1037 else { 1038 cfg_resource(cfg, shd_dg); 1039 (void) snprintf(buf, sizeof (buf), 1040 "%s %s %s update %s", 1041 master, shadow, bitmap, shd_dg); 1042 } 1043 } else { 1044 (void) snprintf(buf, sizeof (buf), "%s %s %s update", 1045 master, shadow, bitmap); 1046 } 1047 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)); 1053 1054 cfg_close(cfg); 1055 1056 break; 1057 1058 default: 1059 usage(); 1060 exit(1); 1061 } 1062 } 1063 1064 void 1065 check_rdcbitmap(int cmd, char *hostp, char *bmp) 1066 { 1067 int i; 1068 CFGFILE *cfg; 1069 int entries; 1070 char **entry; 1071 char *host, *pri, *sec, *sbm, *bit, *mas, *sha, *ovr; 1072 char *shost, *buf, *que; 1073 1074 if ((cfg = cfg_open(NULL)) == NULL) 1075 rdc_err(NULL, 1076 gettext("unable to access configuration")); 1077 if (!cfg_lock(cfg, CFG_RDLOCK)) 1078 rdc_err(NULL, gettext("unable to lock configuration")); 1079 1080 /* 1081 * look into II config to see if this is being used elsewhere 1082 */ 1083 entry = NULL; 1084 entries = cfg_get_section(cfg, &entry, "ii"); 1085 for (i = 0; i < entries; i++) { 1086 buf = entry[i]; 1087 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 */ 1093 1094 /* 1095 * got master, shadow, overflow, and bitmap, now compare 1096 */ 1097 if ((strcmp(bmp, mas) == 0) || 1098 (strcmp(bmp, sha) == 0) || 1099 (strcmp(bmp, ovr) == 0) || 1100 (strcmp(bmp, bit) == 0)) { 1101 rdc_err(NULL, 1102 gettext("bitmap %s is in use by" 1103 " Point-in-Time Copy"), bmp); 1104 } 1105 free(buf); 1106 } 1107 if (entries) 1108 free(entry); 1109 1110 1111 /* 1112 * and last but not least, make sure sndr is not using vol for anything 1113 */ 1114 entry = NULL; 1115 entries = cfg_get_section(cfg, &entry, "sndr"); 1116 for (i = 0; i < entries; i++) { 1117 buf = entry[i]; 1118 1119 /* 1120 * I think this is quicker than 1121 * having to double dip into the config 1122 */ 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 */ 1135 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)) { 1141 rdc_err(NULL, 1142 gettext("bitmap %s is already " 1143 "in use by StorEdge Network Data " 1144 "Replicator"), bmp); 1145 } 1146 } else { 1147 if ((strcmp(bmp, sec) == 0) || 1148 (strcmp(bmp, sbm) == 0)) { 1149 rdc_err(NULL, 1150 gettext("bitmap %s is already " 1151 "in use by StorEdge Network Data " 1152 "Replicator"), bmp); 1153 } 1154 } 1155 } else if (cmd == RDC_CMD_RECONFIG) { 1156 1157 /* 1158 * read this logic 1000 times and consider 1159 * multi homed, one to many, many to one (marketing) 1160 * etc, etc, before changing 1161 */ 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)) { 1167 rdc_err(NULL, 1168 gettext("bitmap %s is already " 1169 "in use by StorEdge Network " 1170 "Data Replicator"), bmp); 1171 } 1172 } else { 1173 if ((strcmp(hostp, shost) == 0) && 1174 (strcmp(bmp, sec) == 0) || 1175 (strcmp(bmp, sbm) == 0)) { 1176 rdc_err(NULL, 1177 gettext("bitmap %s is already " 1178 "in use by StorEdge Network " 1179 "Data Replicator"), bmp); 1180 1181 } 1182 } 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)) { 1188 rdc_err(NULL, 1189 gettext("bitmap %s is already " 1190 "in use by StorEdge Network " 1191 "Data Replicator"), bmp); 1192 } 1193 } else { 1194 if ((strcmp(host, hostp) == 0) && 1195 (strcmp(bmp, pri) == 0) || 1196 (strcmp(bmp, que) == 0) || 1197 (strcmp(bmp, bit) == 0)) { 1198 rdc_err(NULL, 1199 gettext("bitmap %s is already " 1200 "in use by StorEdge Network " 1201 "Data Replicator"), bmp); 1202 } 1203 } 1204 } 1205 1206 } 1207 1208 free(buf); 1209 } 1210 cfg_close(cfg); 1211 1212 if (entries) 1213 free(entry); 1214 } 1215 int 1216 check_intrange(char *arg) { 1217 int i; 1218 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); 1223 return (0); 1224 } 1225 } 1226 errno = 0; 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); 1231 return (0); 1232 } 1233 return (1); 1234 } 1235 1236 void 1237 rewrite_group_diskqueue(CFGFILE *cfg, _sd_dual_pair_t *pair, char *diskqueue) 1238 { 1239 int set; 1240 char buf[CFG_MAX_BUF]; 1241 char key[CFG_MAX_KEY]; 1242 _sd_dual_pair_t tmpair; 1243 1244 for (set = 1; /*CSTYLED*/; set++) { 1245 bzero(buf, CFG_MAX_BUF); 1246 bzero(&tmpair, sizeof (tmpair)); 1247 1248 (void) snprintf(key, sizeof (key), "sndr.set%d", set); 1249 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { 1250 break; 1251 } 1252 if (parse_cfg_buf(buf, &tmpair, NULL)) 1253 continue; 1254 if (pair->group && pair->group[0]) { 1255 if (strcmp(pair->group, tmpair.group) != 0) 1256 continue; /* not the group we want */ 1257 1258 } else { /* no group specified */ 1259 if (strcmp(pair->thost, tmpair.thost) != 0) 1260 continue; 1261 if (strcmp(pair->tfile, tmpair.tfile) != 0) 1262 continue; 1263 } 1264 1265 (void) sprintf(key, "sndr.set%d.diskq", set); 1266 1267 if (cfg_put_cstring(cfg, key, diskqueue, 1268 strlen(diskqueue)) < 0) { 1269 perror(cfg_error(NULL)); 1270 } 1271 } 1272 } 1273 1274 void 1275 diskq_subcmd(int subcmd, char *qvol, char *group_arg, char *ctag_arg, 1276 char *tohost_arg, char *tofile_arg) 1277 { 1278 int found = 0; 1279 int setnumber = 0; 1280 char key[CFG_MAX_KEY]; 1281 char buf[CFG_MAX_BUF]; 1282 int i; 1283 int rc; 1284 int option = 0; 1285 _sd_dual_pair_t pair; 1286 CFGFILE *cfg; 1287 char *ctag = NULL; 1288 int resourced = 0; 1289 1290 if ((cfg = cfg_open(NULL)) == NULL) 1291 rdc_err(NULL, 1292 gettext("unable to access configuration")); 1293 1294 if (!cfg_lock(cfg, CFG_WRLOCK)) 1295 rdc_err(NULL, 1296 gettext("unable to lock configuration")); 1297 1298 redo: 1299 if (cfg_load_svols(cfg) < 0 || 1300 cfg_load_dsvols(cfg) < 0 || 1301 cfg_load_shadows(cfg) < 0) 1302 rdc_err(NULL, 1303 gettext("Unable to parse config filer")); 1304 load_rdc_vols(cfg); 1305 1306 /*CSTYLED*/ 1307 for (i = 0; i < rdc_maxsets;) { 1308 setnumber++; 1309 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); 1314 if (rc < 0) 1315 break; 1316 if (parse_cfg_buf(buf, &pair, NULL)) 1317 continue; 1318 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); 1323 found = 1; 1324 break; 1325 } 1326 1327 } else { 1328 if (strcmp(group_arg, pair.group) == 0) { 1329 found = 1; 1330 break; 1331 } 1332 } 1333 } 1334 1335 if (!found) { 1336 if (strlen(group_arg) == 0) { 1337 rdc_err(NULL, 1338 gettext("Unable to find %s:%s in " 1339 "configuration storage"), 1340 tohost_arg, tofile_arg); 1341 } else { 1342 rdc_err(NULL, 1343 gettext("Unable to find group %s in " 1344 "configuration storage"), group_arg); 1345 } 1346 } 1347 if (!resourced && strlen(pair.ctag)) { /* uh-oh... */ 1348 cfg_unload_svols(cfg); 1349 cfg_unload_dsvols(cfg); 1350 cfg_unload_shadows(cfg); 1351 unload_rdc_vols(); 1352 cfg_resource(cfg, pair.ctag); 1353 ctag = strdup(pair.ctag); 1354 resourced = 1; 1355 setnumber = 0; 1356 goto redo; 1357 } 1358 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); 1365 } 1366 switch (subcmd) { 1367 case RDC_CMD_ADDQ: 1368 if (clustered && (ctag_check(pair.fhost, pair.ffile, 1369 pair.fbitmap, pair.thost, pair.tfile, pair.tbitmap, 1370 pair.ctag, qvol) < 0)) 1371 exit(1); 1372 1373 if (strlen(pair.diskqueue) > 0) { 1374 rdc_err(NULL, gettext("Remote Mirror set already " 1375 "has a disk queue")); 1376 } 1377 if (check_diskqueue(cfg, qvol, group_arg) == DISKQ_FAIL) { 1378 rdc_err(NULL, 1379 gettext("diskqueue %s is incompatible"), qvol); 1380 } 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, 1384 0) < 0) { 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 " 1389 "failed")); 1390 } 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")); 1395 } 1396 } 1397 rewrite_group_diskqueue(cfg, &pair, qvol); 1398 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); 1402 break; 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")); 1407 } 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, 1413 0) < 0) { 1414 exit(1); 1415 } 1416 break; 1417 case RDC_CMD_INITQ: 1418 if (strlen(pair.diskqueue) == 0) { 1419 rdc_err(NULL, gettext("Remote Mirror set does not " 1420 "have a disk queue")); 1421 } 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, 1425 0) < 0) { 1426 exit(1); 1427 } 1428 break; 1429 case RDC_CMD_REMQ: 1430 if (strlen(pair.diskqueue) == 0) { 1431 rdc_err(NULL, gettext("Remote Mirror set does not " 1432 "have a disk queue")); 1433 } 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, 1437 0) < 0) { 1438 exit(1); 1439 } 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); 1444 1445 spcs_log("sndr", NULL, gettext("Remote Mirror: removed " 1446 "diskqueue from set %s:%s and its group"), pair.thost, 1447 pair.tfile); 1448 break; 1449 case RDC_CMD_KILLQ: 1450 if (strlen(pair.diskqueue) == 0) { 1451 rdc_err(NULL, gettext("Remote Mirror set does not " 1452 "have a disk queue")); 1453 } 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, 1457 0) < 0) { 1458 rdc_err(NULL, gettext("Failed to remove disk queue")); 1459 } 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); 1463 1464 rewrite_group_diskqueue(cfg, &pair, place_holder); 1465 1466 spcs_log("sndr", NULL, gettext("Remote Mirror: forcibly " 1467 "removed diskqueue from set %s:%s and its group "), 1468 pair.thost, pair.tfile); 1469 break; 1470 case RDC_CMD_REPQ: 1471 if (clustered && (ctag_check(pair.fhost, pair.ffile, 1472 pair.fbitmap, pair.thost, pair.tfile, pair.tbitmap, 1473 pair.ctag, qvol) < 0)) 1474 exit(1); 1475 1476 if (strlen(pair.diskqueue) == 0) { 1477 rdc_err(NULL, gettext("Remote Mirror set does not " 1478 "have a disk queue")); 1479 } 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, 1483 0) < 0) { 1484 rdc_err(NULL, gettext("Failed to remove disk queue")); 1485 } 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); 1489 1490 rewrite_group_diskqueue(cfg, &pair, place_holder); 1491 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); 1496 } 1497 1498 if (check_diskqueue(cfg, qvol, group_arg) == DISKQ_FAIL) { 1499 rdc_err(NULL, 1500 gettext("cannot replace disk queue %s with %s"), 1501 pair.diskqueue, qvol); 1502 } 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, 1506 0) < 0) { 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")); 1511 } 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")); 1516 } 1517 1518 rewrite_group_diskqueue(cfg, &pair, qvol); 1519 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); 1523 break; 1524 } 1525 1526 cfg_unload_svols(cfg); 1527 cfg_unload_dsvols(cfg); 1528 cfg_unload_shadows(cfg); 1529 unload_rdc_vols(); 1530 1531 if (cfg_commit(cfg) < 0) 1532 rdc_err(NULL, gettext("commit failed on disk queue operation")); 1533 1534 cfg_close(cfg); 1535 if (ctag) 1536 free(ctag); 1537 } 1538 void 1539 spcslog_sync(rdcconfig_t *sets, int start, int type) 1540 { 1541 rdcconfig_t *setp = sets; 1542 1543 while (setp) { 1544 if (start) { 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); 1550 } else { 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); 1556 } 1557 setp = setp->next; 1558 } 1559 } 1560 1561 void 1562 spcslog_tunable(char *shost, char *svol) 1563 { 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); 1572 1573 if (maxqfbas) 1574 spcs_log("sndr", NULL, gettext("maxqfbas set to %d for %s:%s"), 1575 maxqfbas, shost, svol); 1576 if (maxqitems) 1577 spcs_log("sndr", NULL, gettext("maxwrites set to %d for %s:%s"), 1578 maxqitems, shost, svol); 1579 if (asyncthr) 1580 spcs_log("sndr", NULL, gettext("%d async threads configured " 1581 "for %s:%s"), asyncthr, shost, svol); 1582 } 1583 1584 int 1585 set_qblock(char *blockarg) 1586 { 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; 1591 else 1592 return (1); 1593 1594 return (0); 1595 } 1596 1597 static void 1598 rdc_force_disable(CFGFILE *cfg, char *phost, char *pvol, char *pbmp, 1599 char *shost, char *svol, char *sbmp, char *ctag, char *lhname) 1600 { 1601 rdc_config_t parms; 1602 spcs_s_info_t ustatus; 1603 volcount_t *vc; 1604 char *datavol = NULL; 1605 char *bmpvol = NULL; 1606 int on_pri = 0; 1607 int on_sec = 0; 1608 1609 /* are we on the primary or secondary host? */ 1610 if (ctag && *ctag && *lhname) { 1611 if (strcmp(phost, lhname) == 0) { 1612 on_pri = 1; 1613 } else if (strcmp(shost, lhname) == 0) { 1614 on_sec = 1; 1615 } 1616 } else if (self_check(phost)) { 1617 on_pri = 1; 1618 } else if (self_check(shost)) { 1619 on_sec = 1; 1620 } 1621 1622 if (on_pri) { 1623 datavol = pvol; 1624 bmpvol = pbmp; 1625 } else if (on_sec) { 1626 datavol = svol; 1627 bmpvol = sbmp; 1628 } else { 1629 rdc_err(NULL, gettext("Unable to determine whether current " 1630 "node is primary or secondary")); 1631 } 1632 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; 1641 1642 /* 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. 1649 */ 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"), 1655 shost, svol); 1656 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); 1668 } 1669 1670 void 1671 check_rdcsecondary(char *secondary) 1672 { 1673 int i; 1674 CFGFILE *cfg; 1675 int entries; 1676 char **entry; 1677 char *sha; 1678 char *buf; 1679 1680 if ((cfg = cfg_open(NULL)) == NULL) 1681 rdc_err(NULL, 1682 gettext("error opening config")); 1683 if (!cfg_lock(cfg, CFG_RDLOCK)) 1684 rdc_err(NULL, gettext("error locking config")); 1685 1686 entry = NULL; 1687 entries = cfg_get_section(cfg, &entry, "ii"); 1688 for (i = 0; i < entries; i++) { 1689 buf = entry[i]; 1690 1691 (void) strtok(buf, " "); /* master */ 1692 sha = strtok(NULL, " "); /* shadow */ 1693 if (strcmp(secondary, sha) == 0) { 1694 rdc_err(NULL, 1695 gettext("secondary %s is in use by" 1696 " Point-in-Time Copy"), secondary); 1697 } 1698 free(buf); 1699 } 1700 if (entries) 1701 free(entry); 1702 cfg_close(cfg); 1703 } 1704 1705 int 1706 main(int argc, char *argv[]) 1707 { 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]; 1726 char mode[16]; 1727 rdc_version_t rdc_version; 1728 int pairs; 1729 int pid; 1730 int flag = 0; 1731 int fflag = 0; 1732 int reverse = 0; 1733 int nflag = 0; 1734 int iflag = 0; 1735 int doasync; 1736 int pflag = 0; 1737 int vflag = 0; 1738 int verbose = 0; 1739 int errflag = 0; 1740 int cfgflag = 0; 1741 int cfg_success; 1742 int Iflag = 0; 1743 char c; 1744 char inval = 0; 1745 int found; 1746 int rc; 1747 int geflag = 0; 1748 int qflag = 0; 1749 char *qarg; 1750 int Bflag = 0; 1751 char *bitfile; 1752 CFGFILE *cfg = NULL; 1753 int i; 1754 int setnumber; 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; 1760 int sev; 1761 int diskq_group = DISKQ_OKAY; 1762 int extra_argc; 1763 char *ctag_p, *group_p, *diskqueue_p; 1764 char *required; 1765 char *role_env; 1766 int checksetfields = -1; 1767 nsc_off_t boffset = 0; 1768 int oflag = 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; 1774 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) 1779 allow_role = 1; 1780 1781 program = basename(argv[0]); 1782 1783 rc = rdc_check_release(&required); 1784 if (rc < 0) { 1785 rdc_err(NULL, 1786 gettext("unable to determine the current " 1787 "Solaris release: %s\n"), strerror(errno)); 1788 } else if (rc == FALSE) { 1789 rdc_err(NULL, 1790 gettext("incorrect Solaris release (requires %s)\n"), 1791 required); 1792 } 1793 1794 if ((clustered = cfg_iscluster()) < 0) { 1795 rdc_err(NULL, gettext("unable to ascertain environment")); 1796 } 1797 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); 1803 1804 rdc_maxsets = rdc_get_maxsets(); 1805 if (rdc_maxsets == -1) { 1806 rdc_err(NULL, 1807 gettext("unable to get maxsets value from kernel")); 1808 } 1809 1810 pair_list = calloc(rdc_maxsets, sizeof (*pair_list)); 1811 if (pair_list == NULL) { 1812 rdc_err(NULL, 1813 gettext("unable to allocate pair_list array for %d sets"), 1814 rdc_maxsets); 1815 } 1816 1817 bzero(group, sizeof (group)); 1818 bzero(diskqueue, sizeof (diskqueue)); 1819 qblock = 0; 1820 1821 while ((c = 1822 #ifdef DEBUG 1823 getopt(argc, argv, "A:B:C:D:EF:HIO:PRUW:a:bdef:g:hilmno:pq:rsuvw")) 1824 #else 1825 getopt(argc, argv, "A:B:C:D:EF:HIO:PRUW:a:bdef:g:hilmno:pq:rsuvw")) 1826 #endif 1827 != -1) { 1828 switch (c) { 1829 case 'B': 1830 if (!allow_role || flag) { 1831 inval = 1; 1832 break; 1833 } 1834 bitfile = optarg; 1835 Bflag = 1; 1836 flag = RDC_BITMAPOP; 1837 break; 1838 case 'H': 1839 /* 'h' was already assigned */ 1840 if (flag) 1841 inval = 1; 1842 flag = RDC_CMD_HEALTH; 1843 break; 1844 case 'I': 1845 /* List or edit ndr_ii configuration entries */ 1846 Iflag = 1; 1847 break; 1848 case 'R': 1849 if (flag) 1850 inval = 1; 1851 flag = RDC_CMD_RECONFIG; 1852 break; 1853 #ifdef DEBUG 1854 case 'U': /* UDP support */ 1855 proto_test = 1; 1856 break; 1857 #endif 1858 case 'F': 1859 if (flag && flag != RDC_CMD_TUNABLE) 1860 inval = 1; 1861 flag = RDC_CMD_TUNABLE; 1862 1863 if (check_intrange(optarg)) 1864 maxqfbas = atoi(optarg); 1865 else 1866 exit(1); 1867 1868 break; 1869 case 'W': 1870 if (flag && flag != RDC_CMD_TUNABLE) 1871 inval = 1; 1872 flag = RDC_CMD_TUNABLE; 1873 1874 if (check_intrange(optarg)) 1875 maxqitems = atoi(optarg); 1876 else 1877 exit(1); 1878 1879 break; 1880 case 'A': 1881 if (flag && flag != RDC_CMD_TUNABLE) 1882 inval = 1; 1883 flag = RDC_CMD_TUNABLE; 1884 1885 if (check_intrange(optarg)) 1886 asyncthr = atoi(optarg); 1887 else 1888 exit(1); 1889 1890 break; 1891 case 'D': 1892 if (flag && flag != RDC_CMD_TUNABLE) 1893 inval = 1; 1894 flag = RDC_CMD_TUNABLE; 1895 1896 if (set_qblock(optarg)) { 1897 usage(); 1898 exit(1); 1899 } 1900 iflag |= qblock; 1901 break; 1902 case 'a': 1903 if (flag && flag != RDC_CMD_TUNABLE) 1904 inval = 1; 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; 1910 else 1911 inval = 1; 1912 break; 1913 case 'C': 1914 if (clustered) { 1915 (void) strncpy(ctag_arg, optarg, 1916 MAX_RDC_HOST_SIZE); 1917 process_clocal(ctag_arg); 1918 } else 1919 inval = 1; 1920 break; 1921 case 'g': 1922 if (flag == RDC_CMD_ENABLE) 1923 inval = 1; 1924 geflag = 1; 1925 (void) strncpy(group_arg, optarg, NSC_MAXPATH); 1926 verify_groupname(group_arg); 1927 break; 1928 case 'b': 1929 /* ignore */ 1930 break; 1931 case 'n': 1932 nflag = 1; 1933 break; 1934 case 'd': 1935 if (flag) 1936 inval = 1; 1937 flag = RDC_CMD_DISABLE; 1938 break; 1939 case 'e': 1940 if (flag || geflag) 1941 inval = 1; 1942 flag = RDC_CMD_ENABLE; 1943 iflag |= RDC_OPT_SETBMP; 1944 break; 1945 case 'E': 1946 if (flag) 1947 inval = 1; 1948 flag = RDC_CMD_ENABLE; 1949 iflag |= RDC_OPT_CLRBMP; 1950 break; 1951 case 'f': 1952 fflag = 1; 1953 (void) strcpy(config_file, optarg); 1954 break; 1955 case 'h': 1956 usage(); 1957 exit(0); 1958 break; 1959 case 'l': 1960 if (flag) 1961 inval = 1; 1962 flag = RDC_CMD_LOG; 1963 break; 1964 case 'm': 1965 if (flag) 1966 inval = 1; 1967 flag = RDC_CMD_COPY; 1968 iflag |= RDC_OPT_FULL; 1969 break; 1970 case 'O': 1971 case 'o': 1972 1973 if (!allow_role || oflag) { 1974 inval = 1; 1975 break; 1976 } 1977 if (c == 'o') { 1978 oflag = RDC_BITMAPOR; 1979 } else { 1980 oflag = RDC_BITMAPSET; 1981 } 1982 boffset = strtoull(optarg, NULL, 0); 1983 break; 1984 case 'P': 1985 if (flag) 1986 inval = 1; 1987 pflag = 1; 1988 verbose = 1; 1989 break; 1990 case 'p': 1991 if (flag) 1992 inval = 1; 1993 pflag = 1; 1994 break; 1995 case 'q': 1996 if (flag) 1997 inval = 1; 1998 flag = RDC_CMD_INITQ; 1999 qflag = optind; 2000 qarg = optarg; 2001 break; 2002 case 'i': 2003 if (flag) 2004 inval = 1; 2005 pflag = 1; 2006 file_format = 1; 2007 break; 2008 case 'r': 2009 reverse = 1; 2010 iflag |= RDC_OPT_REVERSE; 2011 break; 2012 case 's': 2013 if (flag) 2014 inval = 1; 2015 flag = RDC_CMD_STATUS; 2016 nflag = 1; /* No prompt for a status */ 2017 break; 2018 case 'u': 2019 if (flag) 2020 inval = 1; 2021 flag = RDC_CMD_COPY; 2022 iflag |= RDC_OPT_UPDATE; 2023 break; 2024 case 'v': 2025 if (flag) 2026 inval = 1; 2027 pflag = 1; 2028 vflag = 1; 2029 break; 2030 case 'w': 2031 if (flag) 2032 inval = 1; 2033 flag = RDC_CMD_WAIT; 2034 break; 2035 case '?': 2036 errflag++; 2037 } 2038 } 2039 2040 if (inval || ((flag != RDC_BITMAPOP) && oflag)) { 2041 rdc_warn(NULL, gettext("invalid argument combination")); 2042 errflag = 1; 2043 } 2044 2045 if (flag && Iflag) { 2046 /* Mutually incompatible */ 2047 usage(); 2048 exit(1); 2049 } 2050 2051 if (Iflag) { 2052 rdc_ii_config(argc, argv); 2053 exit(0); 2054 } 2055 2056 if (vflag) { 2057 spcs_s_info_t ustatus; 2058 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")); 2063 } 2064 spcs_s_ufree(&ustatus); 2065 #ifdef DEBUG 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); 2069 #else 2070 if (rdc_version.micro) { 2071 (void) printf(gettext( 2072 "Remote Mirror version %d.%d.%d\n"), 2073 rdc_version.major, 2074 rdc_version.minor, 2075 rdc_version.micro); 2076 } else { 2077 (void) printf(gettext("Remote Mirror version %d.%d\n"), 2078 rdc_version.major, rdc_version.minor); 2079 } 2080 #endif 2081 exit(0); 2082 } 2083 2084 if (!(flag || pflag) || errflag) { 2085 usage(); 2086 exit(1); 2087 } 2088 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)); 2093 } 2094 2095 if (qflag) { /* change disk queue setting */ 2096 int subcmd = 0; 2097 int offset = 0; 2098 char *ptr; 2099 char *qvol; 2100 char tohost_arg[MAX_RDC_HOST_SIZE]; 2101 char tofile_arg[NSC_MAXPATH]; 2102 2103 if (strcmp("a", qarg) == 0) { 2104 subcmd = RDC_CMD_ADDQ; 2105 offset = 1; 2106 } else if (strcmp("d", qarg) == 0) { 2107 subcmd = RDC_CMD_REMQ; 2108 offset = 0; 2109 } else if (strcmp("r", qarg) == 0) { 2110 subcmd = RDC_CMD_REPQ; 2111 offset = 1; 2112 } else { 2113 rdc_warn(NULL, " %s Invalid qopt", qarg); 2114 q_usage(1); 2115 exit(1); 2116 } 2117 if (strlen(group_arg) == 0) { 2118 /* pick out single set as shost:svol */ 2119 ptr = strtok(argv[qflag + offset], ":"); 2120 if (ptr) 2121 (void) strncpy(tohost_arg, ptr, 2122 MAX_RDC_HOST_SIZE); 2123 else { 2124 rdc_warn(NULL, gettext("Bad host specified")); 2125 q_usage(1); 2126 exit(1); 2127 } 2128 ptr = strtok(NULL, ":"); 2129 if (ptr) 2130 (void) strncpy(tofile_arg, ptr, NSC_MAXPATH); 2131 else { 2132 rdc_warn(NULL, gettext("Bad set specified")); 2133 q_usage(1); 2134 exit(1); 2135 } 2136 } 2137 2138 qvol = argv[qflag]; 2139 if ((qvol == NULL) && (subcmd != RDC_CMD_REMQ)) { 2140 rdc_warn(NULL, gettext("missing queue volume")); 2141 q_usage(1); 2142 exit(1); 2143 } 2144 diskq_subcmd(subcmd, qvol, group_arg, ctag_arg, 2145 tohost_arg, tofile_arg); 2146 exit(0); 2147 } 2148 2149 if (flag == RDC_CMD_RECONFIG && !fflag) { 2150 /* See what is to be reconfigured */ 2151 if (argc - optind == 0) 2152 flag = RDC_CMD_RESET; 2153 else { 2154 if (argc - optind < 2) { 2155 usage(); 2156 exit(1); 2157 } 2158 c = *argv[optind++]; 2159 if (argv[optind -1][1] != '\0') { 2160 usage(); 2161 exit(2); 2162 } 2163 switch (c) { 2164 case 'b': 2165 if (argc - optind < 2) { 2166 usage(); 2167 exit(1); 2168 } 2169 if (*argv[optind] == 'p') 2170 reconfig_pbitmap = argv[++optind]; 2171 else if (*argv[optind] == 's') 2172 reconfig_sbitmap = argv[++optind]; 2173 else { 2174 usage(); 2175 exit(1); 2176 } 2177 optind++; 2178 break; 2179 #ifdef _RDC_CAMPUS 2180 case 'd': 2181 reconfig_direct = argv[optind++]; 2182 break; 2183 #endif 2184 case 'g': 2185 reconfig_group = argv[optind++]; 2186 verify_groupname(reconfig_group); 2187 break; 2188 case 'C': 2189 if (clustered) { 2190 (void) strncpy(reconfig_ctag, 2191 argv[optind++], MAX_RDC_HOST_SIZE); 2192 process_clocal(reconfig_ctag); 2193 } else { 2194 usage(); 2195 exit(1); 2196 } 2197 break; 2198 case 'm': 2199 if (strcmp(argv[optind], "sync") == 0) 2200 reconfig_doasync = 0; 2201 else if (strcmp(argv[optind], "async") == 0) 2202 reconfig_doasync = 1; 2203 else { 2204 usage(); 2205 exit(1); 2206 } 2207 optind++; 2208 break; 2209 case 'r': 2210 if (allow_role) { 2211 iflag |= RDC_OPT_REVERSE_ROLE; 2212 break; 2213 } 2214 /* FALLTHROUGH */ 2215 default: 2216 usage(); 2217 exit(1); 2218 } 2219 } 2220 } 2221 if (fflag) { 2222 checksetfields = 1; 2223 if ((argc - optind) != 0) { 2224 usage(); 2225 exit(1); 2226 } 2227 } else { 2228 if ((argc - optind) == 0) { 2229 /* Use libcfg to figure out what to operate on */ 2230 cfgflag = 1; 2231 #ifdef DEBUG 2232 rdc_warn(NULL, gettext("using current config")); 2233 #endif 2234 checksetfields = 0; 2235 } else { 2236 if ((argc - optind) < 8 && (argc - optind) != 1) { 2237 usage(); 2238 exit(1); 2239 } 2240 } 2241 } 2242 2243 if (cfgflag) { 2244 if (flag == RDC_CMD_ADDQ || 2245 flag == RDC_CMD_REMQ || 2246 flag == RDC_CMD_KILLQ || 2247 flag == RDC_CMD_INITQ) { 2248 rdc_err(NULL, gettext("can not use current config " 2249 "for disk queue operations")); 2250 } 2251 } else if (fflag) { 2252 if (flag == RDC_CMD_ADDQ || 2253 flag == RDC_CMD_REMQ || 2254 flag == RDC_CMD_KILLQ || 2255 flag == RDC_CMD_INITQ) { 2256 rdc_err(NULL, gettext("can not use a config file " 2257 "for disk queue operations")); 2258 } 2259 } 2260 if (cfgflag) { 2261 if (flag == RDC_CMD_ENABLE) { 2262 rdc_err(NULL, gettext("can not use current config " 2263 "for enable command")); 2264 } 2265 if ((flag == RDC_CMD_RECONFIG) && (reconfig_pbitmap || 2266 reconfig_sbitmap)) { 2267 rdc_err(NULL, gettext("can not use current config " 2268 "for bitmap reconfiguration")); 2269 } 2270 if (flag == RDC_BITMAPOP) { 2271 rdc_err(NULL, gettext("can not use current config " 2272 "for bitmap set command")); 2273 } 2274 pairs = read_libcfg(flag, group_arg, ctag_arg); 2275 if (pairs == 0) { 2276 (void) fprintf(stderr, 2277 gettext("no matching Remote Mirror sets found " 2278 "in config\n")); 2279 exit(1); 2280 } 2281 } else if (!fflag) { 2282 /* 2283 * Format is either: 2284 * 2285 * tohost:tofile 2286 * 2287 * or something like this for example: 2288 * 2289 * fromhost fromfile frombitmap tohost tofile tobitmap ip sync 2290 * g group C ctag 2291 */ 2292 2293 if (argc - optind == 1) { 2294 char tohost_arg[MAX_RDC_HOST_SIZE]; 2295 char tofile_arg[NSC_MAXPATH]; 2296 char *ptr; 2297 2298 checksetfields = 0; 2299 if (flag == RDC_CMD_ENABLE) { 2300 rdc_err(NULL, 2301 gettext("must specify full set details for " 2302 "enable command")); 2303 } 2304 ptr = strtok(argv[optind], ":"); 2305 if (ptr) 2306 (void) strncpy(tohost_arg, ptr, 2307 MAX_RDC_HOST_SIZE); 2308 else { 2309 rdc_err(NULL, gettext("Bad host specified")); 2310 } 2311 ptr = strtok(NULL, ":"); 2312 if (ptr) 2313 (void) strncpy(tofile_arg, ptr, NSC_MAXPATH); 2314 else { 2315 rdc_err(NULL, gettext("Bad set specified")); 2316 } 2317 2318 /* Now look up tohost:tofile via libcfg */ 2319 2320 if ((cfg = cfg_open(NULL)) == NULL) 2321 rdc_err(NULL, 2322 gettext("unable to access configuration")); 2323 2324 if (!cfg_lock(cfg, CFG_RDLOCK)) 2325 rdc_err(NULL, 2326 gettext("unable to lock configuration")); 2327 2328 setnumber = 0; 2329 found = 0; 2330 /*CSTYLED*/ 2331 for (i = 0; i < rdc_maxsets;) { 2332 setnumber++; 2333 2334 bzero(buf, CFG_MAX_BUF); 2335 (void) snprintf(key, sizeof (key), 2336 "sndr.set%d", setnumber); 2337 rc = cfg_get_cstring(cfg, key, buf, 2338 CFG_MAX_BUF); 2339 if (rc < 0) 2340 break; 2341 2342 (void) snprintf(key, sizeof (key), 2343 "sndr.set%d.shost", setnumber); 2344 (void) cfg_get_cstring(cfg, key, tohost, 2345 sizeof (tohost)); 2346 if (strncmp(tohost, tohost_arg, NSC_MAXPATH)) 2347 continue; 2348 2349 (void) snprintf(key, sizeof (key), 2350 "sndr.set%d.secondary", setnumber); 2351 (void) cfg_get_cstring(cfg, key, tofile, 2352 sizeof (tofile)); 2353 if (strncmp(tofile, tofile_arg, NSC_MAXPATH)) 2354 continue; 2355 2356 found = 1; 2357 2358 (void) snprintf(key, sizeof (key), 2359 "sndr.set%d.phost", setnumber); 2360 (void) cfg_get_cstring(cfg, key, fromhost, 2361 sizeof (fromhost)); 2362 2363 (void) snprintf(key, sizeof (key), 2364 "sndr.set%d.primary", setnumber); 2365 (void) cfg_get_cstring(cfg, key, fromfile, 2366 sizeof (fromfile)); 2367 2368 (void) snprintf(key, sizeof (key), 2369 "sndr.set%d.pbitmap", setnumber); 2370 (void) cfg_get_cstring(cfg, key, frombitmap, 2371 sizeof (frombitmap)); 2372 2373 (void) snprintf(key, sizeof (key), 2374 "sndr.set%d.sbitmap", setnumber); 2375 (void) cfg_get_cstring(cfg, key, tobitmap, 2376 sizeof (tobitmap)); 2377 2378 (void) snprintf(key, sizeof (key), 2379 "sndr.set%d.type", setnumber); 2380 (void) cfg_get_cstring(cfg, key, directfile, 2381 sizeof (directfile)); 2382 if (strcmp(directfile, "ip") == 0) 2383 (void) strcpy(directfile, ""); 2384 2385 (void) snprintf(key, sizeof (key), 2386 "sndr.set%d.mode", setnumber); 2387 (void) cfg_get_cstring( 2388 cfg, key, mode, sizeof (mode)); 2389 2390 (void) snprintf(key, sizeof (key), 2391 "sndr.set%d.group", setnumber); 2392 (void) cfg_get_cstring(cfg, key, group, 2393 sizeof (group)); 2394 if (strcmp(group_arg, "") && 2395 strncmp(group_arg, group, NSC_MAXPATH)) 2396 continue; 2397 (void) snprintf(key, sizeof (key), 2398 "sndr.set%d.cnode", setnumber); 2399 (void) cfg_get_cstring( 2400 cfg, key, ctag, sizeof (ctag)); 2401 if ((strlen(ctag_arg) > 0) && 2402 (strcmp(ctag_arg, ctag) != 0)) 2403 rdc_err(NULL, 2404 gettext("ctags %s and %s " 2405 "do not match"), ctag_arg, ctag); 2406 2407 if (strcmp(mode, "sync") == 0) 2408 doasync = 0; 2409 else if (strcmp(mode, "async") == 0) 2410 doasync = 1; 2411 else { 2412 rdc_err(NULL, 2413 gettext("set %s:%s neither sync " 2414 "nor async"), tohost, tofile); 2415 } 2416 break; 2417 } 2418 cfg_close(cfg); 2419 if (!found) { 2420 rdc_err(NULL, 2421 gettext("set %s:%s not found in config"), 2422 tohost_arg, tofile_arg); 2423 } 2424 } else { 2425 checksetfields = 1; 2426 (void) strncpy(fromhost, argv[optind], 2427 MAX_RDC_HOST_SIZE); 2428 (void) strncpy(fromfile, argv[optind+1], NSC_MAXPATH); 2429 (void) strncpy(frombitmap, argv[optind+2], NSC_MAXPATH); 2430 (void) strncpy(tohost, argv[optind+3], 2431 MAX_RDC_HOST_SIZE); 2432 (void) strncpy(tofile, argv[optind+4], NSC_MAXPATH); 2433 (void) strncpy(tobitmap, argv[optind+5], NSC_MAXPATH); 2434 2435 /* Check the length of entries from the command line */ 2436 if ((fromhost[MAX_RDC_HOST_SIZE - 1] != '\0') || 2437 (tohost[MAX_RDC_HOST_SIZE - 1] != '\0')) { 2438 rdc_err(NULL, 2439 gettext("hostname is longer than %d " 2440 "characters\n"), (MAX_RDC_HOST_SIZE - 1)); 2441 } 2442 2443 /* Check if it's ip address -- not allowed */ 2444 if ((inet_addr(fromhost) != (in_addr_t)(-1)) || 2445 (inet_addr(tohost) != (in_addr_t)(-1))) { 2446 rdc_err(NULL, gettext( 2447 "The hostname specified is invalid.\n" 2448 "See 'man inet(3SOCKET)'")); 2449 } 2450 2451 if ((fromfile[NSC_MAXPATH - 1] != '\0') || 2452 (tofile[NSC_MAXPATH - 1] != '\0') || 2453 (frombitmap[NSC_MAXPATH - 1] != '\0') || 2454 (tobitmap[NSC_MAXPATH - 1] != '\0')) { 2455 rdc_err(NULL, gettext("device name is longer " 2456 "than %d characters\n"), (NSC_MAXPATH - 1)); 2457 } 2458 #ifdef _RDC_CAMPUS 2459 if (argv[optind+6][0] == '/') { 2460 /* FCAL directio */ 2461 (void) strncpy(directfile, argv[optind+6], 2462 NSC_MAXPATH); 2463 } else if (strcmp(argv[optind+6], "ip") != 0) { 2464 #else 2465 if (strcmp(argv[optind+6], "ip") != 0) { 2466 #endif 2467 usage(); 2468 exit(1); 2469 } else 2470 (void) strcpy(directfile, "ip"); 2471 2472 if (strcmp(argv[optind+7], "sync") == 0) 2473 doasync = 0; 2474 else if (strcmp(argv[optind+7], "async") == 0) 2475 doasync = 1; 2476 else { 2477 usage(); 2478 exit(1); 2479 } 2480 2481 /* 2482 * At this point, we could have a set which is 2483 * clustered, but neither a 'C ctag' or '-C ctag' has 2484 * been specified. To avoid clobbering the ctag if a 2485 * dscfg operation is done in the future, we should get 2486 * the ctag out of the config at this point. To do this, 2487 * set the cluster resource filter to NULL to look at 2488 * all sets in the config, pulling out the ctag for the 2489 * set matching shost:svol. If the set is not found, 2490 * fail here. Note, we skip this set on an enable as the 2491 * set is not yet in the config, so no need to waste 2492 * time. 2493 */ 2494 if ((argc - optind == 8) && clustered && 2495 (flag != RDC_CMD_ENABLE)) { 2496 int setnumber; 2497 char key[CFG_MAX_KEY]; 2498 2499 if ((cfg = cfg_open(NULL)) == NULL) { 2500 rdc_err(NULL, 2501 gettext("unable to access configuration")); 2502 } 2503 if (!cfg_lock(cfg, CFG_RDLOCK)) { 2504 rdc_err(NULL, 2505 gettext("unable to lock configuration")); 2506 } 2507 2508 cfg_resource(cfg, NULL); 2509 2510 if ((setnumber = 2511 find_setnumber_in_libcfg(cfg, NULL, tohost, 2512 tofile)) < 0) { 2513 cfg_close(cfg); 2514 rdc_err(NULL, 2515 gettext("unable to find Remote " 2516 "Mirror set " 2517 "%s:%s in config"), 2518 tohost, tofile); 2519 } 2520 2521 (void) snprintf(key, sizeof (key), 2522 "sndr.set%d.cnode", setnumber); 2523 if (cfg_get_cstring(cfg, key, ctag_arg, 2524 MAX_RDC_HOST_SIZE) < 0) { 2525 cfg_close(cfg); 2526 rdc_err(NULL, 2527 gettext("unable to determine ctag " 2528 "for Remote Mirror set %s:%s"), 2529 tohost, tofile); 2530 } 2531 2532 rdc_islocal = strcmp(ctag_arg, "-") ? 0 : 1; 2533 2534 cfg_close(cfg); 2535 } 2536 2537 extra_argc = argc - optind; 2538 if (extra_argc < 8 || extra_argc > 14 || 2539 extra_argc % 2 != 0) { 2540 usage(); 2541 exit(1); 2542 } 2543 2544 /* 2545 * Loop through all of the extra arguments specified 2546 * on the command line, setting the appropriate values 2547 * for valid entries. If an unrecognized argument is 2548 * detected, abort with error. Note: This hack should be 2549 * removed and we should not accept these entries as 2550 * arguments, they should be passed in as switches. 2551 */ 2552 for (i = (8 + optind); i < argc; i += 2) { 2553 /* string case statement */ 2554 if (strcmp(argv[i], "g") == 0) { 2555 (void) strncpy(group, argv[i + 1], 2556 NSC_MAXPATH); 2557 if (group[NSC_MAXPATH - 1] != '\0') { 2558 rdc_err(NULL, gettext("group name is " 2559 "longer than %d characters\n"), 2560 (NSC_MAXPATH - 1)); 2561 } 2562 } else if (strcmp(argv[i], "C") == 0) { 2563 if (!clustered) { 2564 usage(); 2565 exit(1); 2566 } 2567 (void) strncpy(ctag, argv[i + 1], 2568 MAX_RDC_HOST_SIZE); 2569 2570 if (ctag[MAX_RDC_HOST_SIZE - 1] != '\0') { 2571 rdc_err(NULL, gettext("cluster name " 2572 "is longer than %d characters\n"), 2573 (MAX_RDC_HOST_SIZE - 1)); 2574 } 2575 process_clocal(ctag); 2576 2577 /* 2578 * well here is something. 2579 * what if they went sndradm -C local 2580 * host a b host a b ip sync C foobar? 2581 * they might be confused 2582 * lets stop them if ctag_arg and ctag 2583 * don't match and forgive if they are 2584 * the same, below also. 2585 */ 2586 if ((strlen(ctag_arg) > 0) && 2587 (strcmp(ctag_arg, ctag) != 0)) { 2588 rdc_err(NULL, gettext("ctags " 2589 "%s and %s do not match "), 2590 ctag_arg, ctag); 2591 2592 } 2593 } else if (strcmp(argv[i], "q") == 0) { 2594 (void) strncpy(diskqueue, argv[i + 1], 2595 NSC_MAXPATH); 2596 if (diskqueue[NSC_MAXPATH - 1] != '\0') { 2597 rdc_err(NULL, gettext("diskq name is " 2598 "longer than %d characters\n"), 2599 (NSC_MAXPATH - 1)); 2600 } 2601 } else { 2602 /* Unrecognized argument */ 2603 usage(); 2604 exit(1); 2605 } 2606 } 2607 } 2608 2609 /* 2610 * Are we able to determine the existance of either 2611 * of these host addresses? 2612 */ 2613 if (gethost_netaddrs(fromhost, tohost, 2614 (char *)&fromnetaddr, (char *)&tonetaddr) < 0) { 2615 (void) fprintf(stderr, "\n"); 2616 rdc_warn(NULL, gettext("unable to determine IP " 2617 "addresses for either host %s or host %s"), 2618 fromhost, tohost); 2619 2620 if (flag != RDC_CMD_DISABLE) 2621 exit(1); 2622 else 2623 host_not_found = 1; 2624 } 2625 2626 /* 2627 * Are we running on neither host? 2628 */ 2629 if (!self_check(fromhost) && !self_check(tohost)) { 2630 if (flag == RDC_CMD_DISABLE) { 2631 (void) fprintf(stderr, "\n"); 2632 rdc_warn(NULL, gettext("Not running on either host " 2633 "%s or host %s"), fromhost, tohost); 2634 host_not_found = 1; 2635 } 2636 } 2637 2638 /* 2639 * at this point, hopfully it is safe to say that 2640 * if a ctag was supplied via -C tag it is safe to 2641 * move it from ctag_arg to ctag. If it was passed in 2642 * at the end and the beginning of the cli, it must 2643 * match, as per checks above. if it was not passed 2644 * in at the end, but at the beginning, we can deal. 2645 * this should handle the case of shost:svol. 2646 * which is the main reason for this. 2647 * 2648 * there are 3 cases: passed in by cli, checked just above. 2649 * using libdscfg, you must pass in -C tag to have 2650 * ctag_check pass. 2651 * finally a file. same rules as libdscfg. 2652 */ 2653 if ((strlen(ctag) == 0) && (strlen(ctag_arg) > 0)) 2654 (void) strcpy(ctag, ctag_arg); 2655 2656 if (flag == RDC_CMD_RECONFIG) { 2657 if (reconfig_pbitmap) { 2658 (void) strncpy(frombitmap, reconfig_pbitmap, 2659 NSC_MAXPATH); 2660 check_rdcbitmap(flag, fromhost, frombitmap); 2661 } 2662 if (reconfig_sbitmap) { 2663 (void) strncpy(tobitmap, reconfig_sbitmap, 2664 NSC_MAXPATH); 2665 check_rdcbitmap(flag, tohost, tobitmap); 2666 } 2667 #ifdef _RDC_CAMPUS 2668 if (reconfig_direct) 2669 (void) strncpy(directfile, reconfig_direct, 2670 NSC_MAXPATH); 2671 #endif 2672 if (reconfig_group) 2673 (void) strncpy(group, reconfig_group, 2674 NSC_MAXPATH); 2675 2676 if (strlen(reconfig_ctag) > 0) 2677 (void) strncpy(ctag, reconfig_ctag, 2678 MAX_RDC_HOST_SIZE); 2679 if (reconfig_doasync != -1) 2680 doasync = reconfig_doasync; 2681 } 2682 2683 if (flag == RDC_CMD_ENABLE || flag == RDC_CMD_RECONFIG) { 2684 if (ctag_check(fromhost, fromfile, frombitmap, 2685 tohost, tofile, tobitmap, ctag, diskqueue) < 0) 2686 exit(1); 2687 if ((diskq_group = check_diskqueue(NULL, diskqueue, 2688 group)) == DISKQ_FAIL) { 2689 rdc_err(NULL, gettext("disk queue %s is " 2690 "incompatible with existing queue"), 2691 diskqueue); 2692 } 2693 2694 } 2695 pairs = 1; 2696 } else { 2697 pairs = read_config(flag, config_file, group_arg, ctag_arg); 2698 if (pairs == 0) { 2699 rdc_err(NULL, gettext("%s contains no " 2700 "matching Remote Mirror sets"), config_file); 2701 } 2702 } 2703 2704 if (!nflag && !pflag && prompt_user(flag, iflag) == -1) 2705 exit(1); 2706 2707 while (pairs--) { 2708 2709 if (cfgflag || fflag) { 2710 (void) strncpy(fromfile, pair_list[pairs].ffile, 2711 NSC_MAXPATH); 2712 (void) strncpy(tofile, pair_list[pairs].tfile, 2713 NSC_MAXPATH); 2714 (void) strncpy(frombitmap, pair_list[pairs].fbitmap, 2715 NSC_MAXPATH); 2716 (void) strncpy(fromhost, 2717 pair_list[pairs].fhost, MAX_RDC_HOST_SIZE); 2718 (void) strncpy(tohost, pair_list[pairs].thost, 2719 MAX_RDC_HOST_SIZE); 2720 (void) strncpy(tobitmap, pair_list[pairs].tbitmap, 2721 NSC_MAXPATH); 2722 (void) strncpy(directfile, pair_list[pairs].directfile, 2723 NSC_MAXPATH); 2724 (void) strncpy(group, pair_list[pairs].group, 2725 NSC_MAXPATH); 2726 (void) strncpy(ctag, pair_list[pairs].ctag, 2727 MAX_RDC_HOST_SIZE); 2728 (void) strncpy(diskqueue, pair_list[pairs].diskqueue, 2729 NSC_MAXPATH); 2730 2731 bcopy(pair_list[pairs].fnetaddr, fromnetaddr, 2732 RDC_MAXADDR); 2733 bcopy(pair_list[pairs].tnetaddr, tonetaddr, 2734 RDC_MAXADDR); 2735 2736 doasync = pair_list[pairs].doasync; 2737 } 2738 2739 if (pflag) { 2740 static int first = 1; 2741 2742 if (first) { 2743 if ((cfg = cfg_open(NULL)) == NULL) 2744 rdc_err(NULL, 2745 gettext("unable to access configuration")); 2746 2747 if (!cfg_lock(cfg, CFG_RDLOCK)) 2748 rdc_err(NULL, 2749 gettext("unable to lock configuration")); 2750 2751 first = 0; 2752 } 2753 2754 (void) rdc_print(file_format, verbose, 2755 group_arg, ctag_arg, tohost, tofile, cfg); 2756 2757 if (pairs == 0) { 2758 cfg_close(cfg); 2759 exit(0); 2760 } 2761 2762 /* short circuit the rest of the command loop */ 2763 continue; 2764 } 2765 if (Bflag) { 2766 int ret; 2767 ret = rdc_bitmapset(tohost, tofile, bitfile, oflag, 2768 boffset); 2769 exit(ret); 2770 } 2771 if ((fflag || cfgflag) && flag == RDC_CMD_RECONFIG) { 2772 char orig_fbmp[MAXHOSTNAMELEN]; 2773 char orig_tbmp[MAXHOSTNAMELEN]; 2774 int ret; 2775 rdc_config_t parms; 2776 spcs_s_info_t ustatus; 2777 2778 parms.command = RDC_CMD_STATUS; 2779 parms.rdc_set->netconfig = NULL; 2780 (void) strncpy(parms.rdc_set->primary.intf, fromhost, 2781 MAX_RDC_HOST_SIZE); 2782 (void) strncpy(parms.rdc_set->secondary.intf, tohost, 2783 MAX_RDC_HOST_SIZE); 2784 (void) strncpy(parms.rdc_set->primary.file, fromfile, 2785 NSC_MAXPATH); 2786 (void) strncpy(parms.rdc_set->secondary.file, tofile, 2787 NSC_MAXPATH); 2788 ustatus = spcs_s_ucreate(); 2789 ret = RDC_IOCTL(RDC_CONFIG, &parms, 2790 NULL, 0, 0, 0, ustatus); 2791 if (ret != SPCS_S_OK) { 2792 rdc_err(NULL, gettext("unable to get set status" 2793 " before reconfig operation")); 2794 } 2795 (void) strncpy(orig_fbmp, parms.rdc_set->primary.bitmap, 2796 NSC_MAXPATH); 2797 (void) strncpy(orig_tbmp, 2798 parms.rdc_set->secondary.bitmap, NSC_MAXPATH); 2799 2800 if (strncmp(orig_fbmp, frombitmap, NSC_MAXPATH) != 0) 2801 check_rdcbitmap(flag, fromhost, frombitmap); 2802 if (strncmp(orig_tbmp, tobitmap, NSC_MAXPATH) != 0) 2803 check_rdcbitmap(flag, tohost, tobitmap); 2804 spcs_s_ufree(&ustatus); 2805 2806 } 2807 /* 2808 * take a peek in the config to see if 2809 * the bitmap is being used elsewhere 2810 */ 2811 if (flag == RDC_CMD_ENABLE) { 2812 struct stat stb; 2813 /* 2814 * just for fun, lets see if some silly person 2815 * specified the same vol and bitmap 2816 */ 2817 if ((strcmp(fromfile, frombitmap) == 0) || 2818 (strcmp(tofile, tobitmap) == 0)) 2819 rdc_err(NULL, gettext("volumes and bitmaps" 2820 " must not match")); 2821 if (self_check(fromhost)) { 2822 check_rdcbitmap(flag, fromhost, frombitmap); 2823 if (stat(fromfile, &stb) != 0) { 2824 rdc_err(NULL, 2825 gettext("unable to access %s: %s"), 2826 fromfile, strerror(errno)); 2827 } 2828 if (!S_ISCHR(stb.st_mode)) { 2829 rdc_err(NULL, 2830 gettext("%s is not a character device"), 2831 fromfile); 2832 } 2833 } else { /* on the secondary */ 2834 check_rdcbitmap(flag, tohost, tobitmap); 2835 /* extra check for secondary vol */ 2836 check_rdcsecondary(tofile); 2837 if (stat(tofile, &stb) != 0) { 2838 rdc_err(NULL, 2839 gettext("unable to access %s: %s"), 2840 tofile, strerror(errno)); 2841 } 2842 if (!S_ISCHR(stb.st_mode)) { 2843 rdc_err(NULL, 2844 gettext("%s is not a character device"), 2845 tofile); 2846 } 2847 } 2848 2849 } 2850 2851 if (flag == RDC_CMD_ENABLE || flag == RDC_CMD_DISABLE || 2852 flag == RDC_CMD_RECONFIG) { 2853 if ((cfg = cfg_open(NULL)) == NULL) 2854 rdc_err(NULL, 2855 gettext("unable to access configuration")); 2856 2857 if (!cfg_lock(cfg, CFG_WRLOCK)) 2858 rdc_err(NULL, 2859 gettext("unable to lock configuration")); 2860 2861 cfg_resource(cfg, clustered ? ctag : NULL); 2862 } else 2863 cfg = NULL; 2864 2865 if (cfg && perform_autosv() && 2866 (flag == RDC_CMD_ENABLE || flag == RDC_CMD_DISABLE || 2867 flag == RDC_CMD_RECONFIG)) { 2868 if (cfg_load_svols(cfg) < 0 || 2869 cfg_load_dsvols(cfg) < 0 || 2870 cfg_load_shadows(cfg) < 0) 2871 rdc_err(NULL, 2872 gettext("Unable to parse config filer")); 2873 load_rdc_vols(cfg); 2874 } 2875 cfg_success = (cfg == NULL); 2876 if (cfg && flag == RDC_CMD_ENABLE) { 2877 /* Enabled, so add the set via libcfg */ 2878 2879 /* Build a new sndr entry and put it */ 2880 group_p = *group? group : place_holder; 2881 diskqueue_p = *diskqueue? diskqueue : place_holder; 2882 2883 if ((diskqueue_p == place_holder) && 2884 (group_p != place_holder)) { 2885 get_group_diskq(cfg, group_p, diskqueue); 2886 if (*diskqueue) 2887 diskqueue_p = diskqueue; 2888 } 2889 2890 /* 2891 * format in pconfig is: 2892 * phost.primary.pbitmap.shost.secondary. 2893 * sbitmap.type.mode.group.cnode.options.diskq 2894 */ 2895 (void) snprintf(buf, sizeof (buf), 2896 "%s %s %s %s %s %s %s %s %s %s - %s", 2897 fromhost, fromfile, frombitmap, tohost, tofile, 2898 tobitmap, directfile, 2899 doasync? "async" : "sync", group_p, 2900 clustered? ctag : "-", diskqueue_p); 2901 2902 if (cfg_put_cstring(cfg, "sndr", buf, strlen(buf)) < 0) 2903 rdc_warn(NULL, 2904 gettext("unable to add \"%s\" to " 2905 "configuration storage: %s"), 2906 buf, cfg_error(&sev)); 2907 setnumber = find_setnumber_in_libcfg(cfg, clustered? 2908 ctag : NULL, tohost, tofile); 2909 if (setnumber < 0) 2910 rdc_warn(NULL, 2911 gettext("unable to add \"%s\" to " 2912 "configuration storage: %s"), 2913 diskqueue_p, cfg_error(&sev)); 2914 2915 else 2916 cfg_success = 1; 2917 2918 /* Add cluster aware info */ 2919 if (clustered && !rdc_islocal) { 2920 (void) snprintf(key, sizeof (key), 2921 "sndr.set%d.options", setnumber); 2922 if (self_check(fromhost)) { 2923 if (cfg_put_options(cfg, CFG_SEC_CONF, 2924 key, "lghn", fromhost) < 0) { 2925 rdc_err(NULL, 2926 gettext("unable to add " 2927 "\"%s\" to configuration " 2928 "storage: %s"), 2929 fromhost, cfg_error(&sev)); 2930 } 2931 } else if (self_check(tohost)) { 2932 if (cfg_put_options(cfg, CFG_SEC_CONF, 2933 key, "lghn", tohost) < 0) { 2934 rdc_err(NULL, 2935 gettext("unable to add " 2936 "\"%s\" to configuration " 2937 "storage: %s"), 2938 fromhost, cfg_error(&sev)); 2939 } 2940 } 2941 } 2942 } else if (cfg && flag == RDC_CMD_DISABLE) { 2943 found = 0; 2944 /* Disabled, so delete the set via libcfg */ 2945 2946 /* get sndr entries until shost, sfile match */ 2947 for (i = 0; i < rdc_maxsets; i++) { 2948 setnumber = i + 1; 2949 (void) snprintf(key, sizeof (key), "sndr.set%d", 2950 setnumber); 2951 if (cfg_get_cstring(cfg, key, buf, 2952 CFG_MAX_BUF) < 0) { 2953 break; 2954 } 2955 (void) snprintf(key, sizeof (key), 2956 "sndr.set%d.secondary", setnumber); 2957 if (cfg_get_cstring(cfg, key, buf, 2958 CFG_MAX_BUF) < 0) 2959 break; 2960 if (strcmp(buf, tofile) != 0) 2961 continue; 2962 (void) snprintf(key, sizeof (key), 2963 "sndr.set%d.shost", 2964 setnumber); 2965 if (cfg_get_cstring(cfg, key, buf, 2966 CFG_MAX_BUF) < 0) 2967 break; 2968 if (strcmp(buf, tohost) != 0) 2969 continue; 2970 found = 1; 2971 #ifdef DEBUG 2972 if (checksetfields == -1) { 2973 rdc_err(NULL, 2974 gettext("checksetfields not set")); 2975 } 2976 #endif 2977 if (checksetfields) { 2978 checkgfields(cfg, setnumber, fromhost, 2979 fromfile, frombitmap, tobitmap, 2980 directfile, (doasync == 1) 2981 ? "async" : "sync", group, ctag, 2982 diskqueue); 2983 } 2984 2985 /* perform cluster specific options */ 2986 if (clustered) { 2987 /* get the logical host, if set */ 2988 (void) snprintf(key, sizeof (key), 2989 "sndr.set%d.options", setnumber); 2990 (void) cfg_get_single_option(cfg, 2991 CFG_SEC_CONF, key, "lghn", 2992 lhname, MAX_RDC_HOST_SIZE); 2993 2994 /* figure out the cluster tag, if any */ 2995 (void) snprintf(key, sizeof (key), 2996 "sndr.set%d.cnode", setnumber); 2997 if (cfg_get_cstring(cfg, key, buf, 2998 CFG_MAX_BUF) < 0) 2999 break; 3000 if (strcmp(buf, ctag)) 3001 rdc_err(NULL, gettext("ctags %s" 3002 " and %s do not match"), 3003 buf, ctag); 3004 } else { 3005 *lhname = '\0'; 3006 *ctag = '\0'; 3007 } 3008 3009 /* figure out the disk queue, if any */ 3010 (void) snprintf(key, sizeof (key), 3011 "sndr.set%d.diskq", 3012 setnumber); 3013 if (cfg_get_cstring(cfg, key, buf, 3014 CFG_MAX_BUF) < 0) 3015 break; 3016 if (strlen(buf) > 0) { 3017 (void) strncpy(diskqueue, buf, 3018 NSC_MAXPATH); 3019 } else { 3020 *diskqueue = '\0'; 3021 } 3022 (void) snprintf(key, sizeof (key), "sndr.set%d", 3023 setnumber); 3024 if (cfg_put_cstring(cfg, key, NULL, 0) < 0) 3025 rdc_warn(NULL, 3026 gettext("unable to remove \"%s\" " 3027 "from configuration storage: %s"), 3028 buf, cfg_error(&sev)); 3029 else 3030 cfg_success = 1; 3031 break; 3032 } 3033 if (found == 0) { 3034 rdc_err(NULL, 3035 gettext("Unable to find %s:%s in " 3036 "configuration storage"), 3037 tohost, tofile); 3038 } 3039 if (host_not_found) { 3040 rdc_force_disable(cfg, fromhost, fromfile, 3041 frombitmap, tohost, tofile, tobitmap, ctag, 3042 lhname); 3043 if (cfg_commit(cfg) < 0) 3044 rdc_err(NULL, gettext("commit on " 3045 "force disable failed")); 3046 cfg_close(cfg); 3047 return (0); 3048 } 3049 } else if (cfg && flag == RDC_CMD_RECONFIG) { 3050 /* Update relevant cfg record */ 3051 3052 cfg_resource(cfg, NULL); 3053 3054 /* get sndr entries until shost, sfile match */ 3055 for (i = 0; i < rdc_maxsets; i++) { 3056 setnumber = i + 1; 3057 (void) snprintf(key, sizeof (key), "sndr.set%d", 3058 setnumber); 3059 if (cfg_get_cstring(cfg, key, buf, 3060 CFG_MAX_BUF) < 0) { 3061 break; 3062 } 3063 (void) snprintf(key, sizeof (key), 3064 "sndr.set%d.secondary", setnumber); 3065 if (cfg_get_cstring(cfg, key, buf, 3066 CFG_MAX_BUF) < 0) 3067 break; 3068 if (strcmp(buf, tofile) != 0) 3069 continue; 3070 (void) snprintf(key, sizeof (key), 3071 "sndr.set%d.shost", 3072 setnumber); 3073 if (cfg_get_cstring(cfg, key, buf, 3074 CFG_MAX_BUF) < 0) 3075 break; 3076 if (strcmp(buf, tohost) != 0) 3077 continue; 3078 (void) snprintf(key, sizeof (key), 3079 "sndr.set%d.cnode", 3080 setnumber); 3081 if (cfg_get_cstring(cfg, key, buf, 3082 CFG_MAX_BUF) < 0) 3083 break; 3084 if (reconfig_ctag[0] == '\0') 3085 (void) strncpy(ctag, buf, 3086 sizeof (ctag)); 3087 if (doasync) 3088 (void) strcpy(mode, "async"); 3089 else 3090 (void) strcpy(mode, "sync"); 3091 if (strcmp(directfile, "") == 0) 3092 (void) strcpy(directfile, "ip"); 3093 3094 group_p = strlen(group) > 0 ? group : 3095 place_holder; 3096 3097 /* 3098 * if we are reconfigging out altogether, 3099 * get rid of the diskqueue 3100 */ 3101 if (group_p == place_holder) 3102 diskqueue_p = place_holder; 3103 else 3104 diskqueue_p = strlen(diskqueue) > 0 ? 3105 diskqueue : place_holder; 3106 3107 /* 3108 * do a little diskq dance here for reconfigs 3109 * that did not specify the diskqueue whilst 3110 * reconfigging ... 3111 */ 3112 if ((diskqueue_p == place_holder) && 3113 (group_p != place_holder)) { 3114 get_group_diskq(cfg, group_p, 3115 diskqueue); 3116 diskqueue_p = strlen(diskqueue) > 0 ? 3117 diskqueue : place_holder; 3118 } 3119 3120 (void) snprintf(key, sizeof (key), 3121 "sndr.set%d.options", setnumber); 3122 if (cfg_get_cstring(cfg, key, options_cfg, 3123 CFG_MAX_BUF) < 0) { 3124 break; 3125 } 3126 3127 ctag_p = strlen(ctag) > 0 ? 3128 ctag : place_holder; 3129 (void) snprintf(buf, sizeof (buf), 3130 "%s %s %s %s %s %s %s %s %s %s %s %s", 3131 fromhost, fromfile, frombitmap, 3132 tohost, tofile, tobitmap, 3133 directfile, mode, group_p, 3134 ctag_p, options_cfg, diskqueue_p); 3135 3136 (void) snprintf(key, sizeof (key), "sndr.set%d", 3137 setnumber); 3138 if (cfg_put_cstring(cfg, key, buf, 3139 strlen(buf)) < 0) 3140 rdc_warn(NULL, 3141 gettext("unable to update \"%s\" " 3142 "in configuration storage: %s"), 3143 buf, cfg_error(&sev)); 3144 else 3145 cfg_success = 1; 3146 break; 3147 } 3148 } 3149 3150 if (cfg_success) { 3151 if (cfg && perform_autosv()) { 3152 if (self_check(fromhost)) { 3153 if (diskqueue[0] && 3154 (strcmp(diskqueue, fromfile) == 0) || 3155 (strcmp(diskqueue, frombitmap) == 0)) { 3156 rdc_err(NULL, gettext("disk " 3157 "queue volume %s must not " 3158 "match any primary Remote " 3159 "Mirror volume or bitmap"), 3160 diskqueue); 3161 } 3162 3163 if (diskqueue[0]) { 3164 different_devs(fromfile, diskqueue); 3165 different_devs(frombitmap, diskqueue); 3166 validate_name(cfg, diskqueue); 3167 } 3168 different_devs(fromfile, frombitmap); 3169 validate_name(cfg, fromfile); 3170 validate_name(cfg, frombitmap); 3171 } else { 3172 different_devs(tofile, tobitmap); 3173 validate_name(cfg, tofile); 3174 validate_name(cfg, tobitmap); 3175 } 3176 } 3177 /* 3178 * okay, if the command is sync, just build 3179 * a list of rdcconfig_t's after the pairs-- 3180 * loop is done, we will pass this list to 3181 * librdc to multithread the syncs (after 3182 * forking off a daemonish type process 3183 * that waits for the libcall to complete 3184 * ints of interest: 3185 * flag ie RDC_CMD_COPY, iflag RDC_OPT_UPDATE, 3186 * reverse RDC_OPT_REVERSE, RDC_OPT_FORWARD 3187 * if necessary, turn autosync back on 3188 */ 3189 if (flag == RDC_CMD_COPY) { 3190 if (autosync_is_on(tohost, tofile) == 3191 AUTOSYNC_ON) 3192 enable_autosync(fromhost, fromfile, 3193 tohost, tofile); 3194 3195 if (sets == NULL) { 3196 sets_p = sets = 3197 rdc_alloc_config(fromhost, fromfile, 3198 frombitmap, tohost, tofile, 3199 tobitmap, "mode", "group", "ctag", 3200 "options", 0); 3201 3202 if (sets_p == NULL) { 3203 rdc_err(NULL, 3204 gettext("rdc config alloc" 3205 "failed %s"), rdc_error(NULL)); 3206 } 3207 continue; 3208 } 3209 3210 sets_p = sets_p->next = 3211 rdc_alloc_config(fromhost, fromfile, 3212 frombitmap, tohost, tofile, tobitmap, 3213 "mode", "group", "ctag", "options", 0); 3214 3215 if (sets_p == NULL) { 3216 rdc_err(NULL, gettext("rdc config alloc" 3217 "failed %s"), rdc_error(NULL)); 3218 } 3219 continue; 3220 } 3221 3222 /* 3223 * block incoming signals until after the possible 3224 * cfg_commit is done 3225 */ 3226 block_sigs(); 3227 if (rdc_operation(cfg, fromhost, fromfile, frombitmap, 3228 tohost, tofile, tobitmap, flag, iflag, directfile, 3229 group, ctag, diskqueue, &doasync, reverse) < 0) { 3230 ; 3231 /*EMPTY*/ 3232 } else if (cfg) { 3233 if (diskq_group == DISKQ_REWRITEG) { 3234 rewrite_group_diskqueue(cfg, 3235 &pair_list[pairs], diskqueue); 3236 } 3237 if (perform_autosv() && 3238 (flag == RDC_CMD_ENABLE || 3239 flag == RDC_CMD_DISABLE || 3240 flag == RDC_CMD_RECONFIG)) { 3241 unload_rdc_vols(); 3242 cfg_unload_shadows(); 3243 cfg_unload_dsvols(); 3244 cfg_unload_svols(); 3245 } 3246 if ((iflag & RDC_OPT_REVERSE_ROLE) != 0 && 3247 allow_role) { 3248 bzero(tmphost, MAX_RDC_HOST_SIZE); 3249 bzero(tmpfile, NSC_MAXPATH); 3250 bzero(tmpbitmap, NSC_MAXPATH); 3251 (void) strncpy(tmphost, fromhost, 3252 MAX_RDC_HOST_SIZE); 3253 (void) strncpy(tmpfile, fromfile, 3254 NSC_MAXPATH); 3255 (void) strncpy(tmpbitmap, frombitmap, 3256 NSC_MAXPATH); 3257 3258 (void) strncpy(fromhost, tohost, 3259 MAX_RDC_HOST_SIZE); 3260 (void) strncpy(fromfile, tofile, 3261 NSC_MAXPATH); 3262 (void) strncpy(frombitmap, tobitmap, 3263 NSC_MAXPATH); 3264 3265 (void) strncpy(tohost, tmphost, 3266 MAX_RDC_HOST_SIZE); 3267 (void) strncpy(tofile, tmpfile, 3268 NSC_MAXPATH); 3269 (void) strncpy(tobitmap, tmpbitmap, 3270 NSC_MAXPATH); 3271 group_p = strlen(group) > 0 ? group : 3272 place_holder; 3273 diskqueue_p = strlen(diskqueue) > 0 ? 3274 diskqueue : place_holder; 3275 ctag_p = strlen(ctag) > 0 ? 3276 ctag : place_holder; 3277 (void) snprintf(buf, sizeof (buf), "%s " 3278 "%s %s %s %s %s %s %s %s %s %s %s", 3279 fromhost, fromfile, frombitmap, 3280 tohost, tofile, tobitmap, 3281 directfile, mode, group_p, 3282 ctag_p, options_cfg, diskqueue_p); 3283 3284 (void) snprintf(key, sizeof (key), 3285 "sndr.set%d", setnumber); 3286 if (cfg_put_cstring(cfg, key, buf, 3287 strlen(buf)) < 0) 3288 rdc_err(NULL, 3289 gettext("unable to update \"%s\" " 3290 "in configuration storage: %s"), 3291 buf, cfg_error(&sev)); 3292 } 3293 if (cfg_commit(cfg) < 0) { 3294 rdc_err(NULL, gettext("commit on role " 3295 "reversal failed")); 3296 } 3297 } 3298 unblock_sigs(); 3299 } 3300 3301 if (cfg) { 3302 cfg_close(cfg); 3303 } 3304 3305 } 3306 if (flag == RDC_CMD_COPY) { 3307 pid = fork(); 3308 if (pid == -1) { /* error forking */ 3309 perror("fork"); 3310 exit(1); 3311 } 3312 } else { 3313 exit(0); 3314 } 3315 if (pid > 0) /* parent process */ 3316 exit(0); 3317 3318 spcslog_sync(sets, 1, iflag); 3319 if (iflag & RDC_OPT_REVERSE) { 3320 if (iflag & RDC_OPT_UPDATE) 3321 rclist = rdc_ursync(sets); 3322 else 3323 rclist = rdc_rsync(sets); 3324 } else if (iflag & RDC_OPT_UPDATE) { 3325 rclist = rdc_usync(sets); 3326 } else 3327 rclist = rdc_fsync(sets); 3328 3329 rcp = rclist; 3330 while (rcp) { 3331 if (rcp->rc < 0) { 3332 /* rclist->msg has already been gettext'd */ 3333 (void) fprintf(stderr, 3334 gettext("Remote Mirror: %s %s %s %s %s %s\n"), 3335 rcp->set.phost, rcp->set.pfile, rcp->set.pbmp, 3336 rcp->set.shost, rcp->set.sfile, rcp->set.sbmp); 3337 rdc_warn(NULL, "%s", rcp->msg); 3338 spcs_log("sndr", NULL, "%s", rcp->msg); 3339 } 3340 rcp = rcp->next; 3341 } 3342 3343 spcslog_sync(sets, 0, iflag); 3344 3345 if (sets) 3346 rdc_free_config(sets, RDC_FREEALL); 3347 if (rclist) 3348 rdc_free_rclist(rclist); 3349 3350 return (0); 3351 } 3352 /* 3353 * process_clocal() 3354 * pre: a non null string 3355 * post: if the string is "local" 3356 * then it is converted to "-" 3357 * and rdc_islocal is set to 1 3358 * if not rdc_islocal set to 0 3359 */ 3360 void 3361 process_clocal(char *ctag) 3362 { 3363 /* 3364 * Check for the special cluster tag and convert into the 3365 * internal representation. 3366 */ 3367 3368 if (ctag != NULL && strcmp(ctag, RDC_LOCAL_TAG) == 0) { 3369 (void) strcpy(ctag, "-"); 3370 rdc_islocal = 1; 3371 } else { 3372 rdc_islocal = 0; 3373 } 3374 } 3375 3376 static void 3377 rdc_check_dgislocal(char *dgname) 3378 { 3379 char *othernode; 3380 int rc; 3381 3382 /* 3383 * check where this disk service is mastered 3384 */ 3385 3386 rc = cfg_dgname_islocal(dgname, &othernode); 3387 if (rc < 0) { 3388 rdc_err(NULL, gettext("unable to find " 3389 "disk service, %s: %s"), dgname, strerror(errno)); 3390 } 3391 3392 if (rc == 0) { 3393 rdc_err(NULL, gettext("disk service, %s, is " 3394 "active on node \"%s\"\nPlease re-issue " 3395 "the command on that node"), dgname, othernode); 3396 } 3397 } 3398 3399 static void 3400 different_devs(char *dev1, char *dev2) 3401 { 3402 struct stat buf1, buf2; 3403 3404 if (stat(dev1, &buf1) < 0) { 3405 spcs_log("sndr", NULL, gettext("Remote Mirror: can't stat %s"), 3406 dev1); 3407 rdc_err(NULL, gettext("Remote Mirror: can't stat %s"), dev1); 3408 } 3409 if (stat(dev2, &buf2) < 0) { 3410 spcs_log("sndr", NULL, gettext("Remote Mirror: can't stat %s"), 3411 dev2); 3412 rdc_err(NULL, gettext("Remote Mirror: can't stat %s"), dev2); 3413 } 3414 if (buf1.st_rdev == buf2.st_rdev) { 3415 spcs_log("sndr", NULL, gettext("Remote Mirror: '%s' and '%s' " 3416 "refer to the same device"), dev1, dev2); 3417 rdc_err(NULL, gettext("Remote Mirror: '%s' and '%s' refer to " 3418 "the same device"), dev1, dev2); 3419 } 3420 } 3421 3422 static void 3423 validate_name(CFGFILE *cfg, char *vol) 3424 { 3425 char *altname; 3426 int rc; 3427 3428 if (!cfg) { 3429 rdc_err(NULL, gettext("Remote Mirror: null cfg ptr in " 3430 "validate_name")); 3431 } 3432 3433 rc = cfg_get_canonical_name(cfg, vol, &altname); 3434 if (rc < 0) { 3435 spcs_log("sndr", NULL, gettext("Remote Mirror: unable to parse " 3436 "config file\n")); 3437 rdc_err(NULL, gettext("Remote Mirror: unable to parse config " 3438 "file\n")); 3439 } 3440 if (rc) { 3441 spcs_log("sndr", NULL, gettext("Remote Mirror: '%s': already " 3442 "configured as '%s'"), vol, altname); 3443 rdc_err(NULL, gettext("Remote Mirror: The volume '%s' has been " 3444 "configured previously as '%s'. Re-enter command with " 3445 "the latter name."), vol, altname); 3446 } 3447 } 3448 3449 /* 3450 * Add the autosync value to the option field for the sndr set specified by 3451 * tohost:tofile. 3452 * 3453 * ASSUMPTIONS: 3454 * - cfg file is available to take a write lock. 3455 * - set is already configured in dscfg 3456 * 3457 * INPUTS: 3458 * autosync_val - value to set autosync to 3459 * tohost - secondary host 3460 * tofile - secondary volume 3461 * 3462 * OUTPUTS: 3463 * none. 3464 * 3465 */ 3466 static void 3467 set_autosync(int autosync_val, char *tohost, char *tofile, char *ctag) 3468 { 3469 CFGFILE *cfg; 3470 char key[CFG_MAX_KEY], buf[CFG_MAX_BUF]; 3471 char tag[CFG_MAX_BUF], val[CFG_MAX_BUF]; 3472 char auto_tag[CFG_MAX_BUF]; 3473 _sd_dual_pair_t pair; 3474 _sd_dual_pair_t tmpair; 3475 int setnumber, options = 0, already_set = 0, cfg_success = 0; 3476 int set; 3477 3478 /* verify valid autosync request */ 3479 if ((autosync_val != AUTOSYNC_ON) && (autosync_val != AUTOSYNC_OFF)) { 3480 #ifdef DEBUG 3481 rdc_warn(NULL, 3482 gettext("set_autosync called with improper value")); 3483 #endif 3484 return; 3485 } 3486 3487 if ((cfg = cfg_open(NULL)) == NULL) { 3488 rdc_err(NULL, gettext("unable to access configuration")); 3489 } 3490 if (!cfg_lock(cfg, CFG_WRLOCK)) { 3491 rdc_err(NULL, gettext("unable to lock configuration")); 3492 } 3493 3494 if (clustered) { 3495 cfg_resource(cfg, ctag); 3496 } else { 3497 cfg_resource(cfg, NULL); 3498 } 3499 3500 /* find set number in config */ 3501 if ((setnumber = find_setnumber_in_libcfg(cfg, clustered? ctag : NULL, 3502 tohost, tofile)) < 0) { 3503 cfg_close(cfg); 3504 rdc_err(NULL, gettext("unable to find Remote Mirror set %s:%s: " 3505 "in config"), tohost, tofile); 3506 } 3507 (void) snprintf(key, sizeof (key), "sndr.set%d.options", setnumber); 3508 (void) snprintf(auto_tag, sizeof (auto_tag), "auto"); 3509 3510 /* Check if there are any options already set, including ours */ 3511 if (cfg_get_options(cfg, CFG_SEC_CONF, key, tag, CFG_MAX_BUF, val, 3512 CFG_MAX_BUF) >= 0) { 3513 options = 1; 3514 3515 do { 3516 if (strcmp(tag, auto_tag) == 0) { 3517 already_set = 1; 3518 } 3519 } while (cfg_get_options(cfg, CFG_SEC_CONF, NULL, tag, 3520 CFG_MAX_BUF, val, CFG_MAX_BUF) >= 0); 3521 } 3522 3523 /* options already exist, edit ours out */ 3524 if (options && already_set) { 3525 char *p, *q; 3526 int need_to_clear_buf = 1; 3527 3528 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { 3529 rdc_err(NULL, gettext("unable to get options field " 3530 "for Remote Mirror set %s:%s"), tohost, tofile); 3531 } 3532 3533 /* parse out our options, all of the form "auto=" */ 3534 p = strdup(buf); 3535 bzero(buf, sizeof (buf)); 3536 3537 q = strtok(p, ";"); 3538 do { 3539 /* if another tag/value exists, keep it */ 3540 if (strncmp(auto_tag, q, 4) != 0) { 3541 (void) strcat(buf, q); 3542 (void) strcat(buf, ";"); 3543 need_to_clear_buf = 0; 3544 } 3545 } while (q = strtok(NULL, ";")); 3546 free(p); 3547 3548 /* if we were the only option, clear the field */ 3549 if (need_to_clear_buf) { 3550 (void) strcat(buf, "-"); 3551 } 3552 3553 if (cfg_put_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { 3554 rdc_err(NULL, gettext("unable to clear autosync value " 3555 "in config for Remote Mirror set %s:%s"), tohost, 3556 tofile); 3557 } else { 3558 cfg_success = 1; 3559 } 3560 } 3561 3562 /* autosync is not present in options field, add if on is requested */ 3563 if (autosync_val == AUTOSYNC_ON) { 3564 if (cfg_put_options(cfg, CFG_SEC_CONF, key, auto_tag, "on") 3565 < 0) { 3566 rdc_err(NULL, gettext("unable to update autosync value " 3567 "in config for Remote Mirror set %s:%s"), tohost, 3568 tofile); 3569 } else { 3570 cfg_success = 1; 3571 } 3572 } 3573 /* if we are in a group, update any other sets in the same group */ 3574 do { 3575 bzero(&pair, sizeof (pair)); 3576 bzero(buf, CFG_MAX_BUF); 3577 3578 (void) snprintf(key, sizeof (key), "sndr.set%d", setnumber); 3579 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { 3580 break; 3581 } 3582 if (parse_cfg_buf(buf, &pair, NULL)) 3583 break; 3584 if (pair.group == NULL) /* not in a group */ 3585 break; 3586 if (!pair.group[0]) 3587 break; /* not in a group */ 3588 for (set = 1; /*CSTYLED*/; set++) { 3589 if (set == setnumber) 3590 continue; 3591 bzero(buf, CFG_MAX_BUF); 3592 options = 0; 3593 already_set = 0; 3594 3595 (void) snprintf(key, sizeof (key), "sndr.set%d", set); 3596 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { 3597 break; /* last set processed */ 3598 } 3599 bzero(&tmpair, sizeof (tmpair)); 3600 if (parse_cfg_buf(buf, &tmpair, NULL)) 3601 break; 3602 if (strcmp(pair.group, tmpair.group) != 0) 3603 continue; /* not the group we want */ 3604 3605 (void) snprintf(key, sizeof (key), "sndr.set%d.options", 3606 set); 3607 /* 3608 * Check if there are any options already set, 3609 * including ours 3610 */ 3611 if (cfg_get_options(cfg, CFG_SEC_CONF, key, tag, 3612 CFG_MAX_BUF, val, CFG_MAX_BUF) >= 0) { 3613 options = 1; 3614 3615 do { 3616 if (strcmp(tag, auto_tag) == 0) { 3617 already_set = 1; 3618 } 3619 } while (cfg_get_options(cfg, CFG_SEC_CONF, 3620 NULL, tag, CFG_MAX_BUF, val, 3621 CFG_MAX_BUF) >= 0); 3622 } 3623 3624 /* options already exist, edit ours out */ 3625 if (options && already_set) { 3626 char *p, *q; 3627 int need_to_clear_buf = 1; 3628 3629 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) 3630 < 0) { 3631 rdc_err(NULL, gettext("unable to get " 3632 "options field for Remote Mirror set " 3633 "%s:%s"), tmpair.thost, tmpair.tfile); 3634 } 3635 3636 /* 3637 * parse out our options, all of the 3638 * form "auto=" 3639 */ 3640 p = strdup(buf); 3641 bzero(buf, sizeof (buf)); 3642 3643 q = strtok(p, ";"); 3644 do { 3645 /* 3646 * if another tag/value exists, 3647 * keep it 3648 */ 3649 if (strncmp(auto_tag, q, 4) != 0) { 3650 (void) strcat(buf, q); 3651 (void) strcat(buf, ";"); 3652 need_to_clear_buf = 0; 3653 } 3654 } while (q = strtok(NULL, ";")); 3655 free(p); 3656 3657 /* 3658 * if we were the only option, 3659 * clear the field 3660 */ 3661 if (need_to_clear_buf) { 3662 (void) strcat(buf, "-"); 3663 } 3664 3665 if (cfg_put_cstring(cfg, key, buf, CFG_MAX_BUF) 3666 < 0) { 3667 rdc_err(NULL, gettext("unable to clear " 3668 "autosync value in config for " 3669 "Remote Mirror set %s:%s"), 3670 tmpair.thost, tmpair.tfile); 3671 cfg_success = 0; 3672 } 3673 } 3674 3675 /* 3676 * autosync is not present in options field, 3677 * add if on is requested 3678 */ 3679 if (autosync_val == AUTOSYNC_ON) { 3680 if (cfg_put_options(cfg, CFG_SEC_CONF, key, 3681 auto_tag, "on") < 0) { 3682 rdc_err(NULL, gettext("unable to update" 3683 " autosync value in config for " 3684 "Remote Mirror set %s:%s"), 3685 tmpair.thost, 3686 tmpair.tfile); 3687 cfg_success = 0; 3688 } 3689 } 3690 } 3691 3692 /* CONSTCOND */ 3693 } while (0); 3694 if (cfg_success) { 3695 if (cfg_commit(cfg) < 0) { 3696 rdc_err(NULL, gettext("commit on role reversal failed")); 3697 } 3698 } 3699 3700 cfg_close(cfg); 3701 } 3702 3703 /* 3704 * Check to see if autosync is on for set specified by tohost:tofile. 3705 * 3706 * ASSUMPTIONS: 3707 * config is available to take a read lock against it. 3708 * 3709 * INPUTS: 3710 * tohost - secondary host 3711 * tofile - secondary volume 3712 * 3713 * OUTPUTS: 3714 * -1 error 3715 * AUTOSYNC_ON if autosync is on 3716 * AUTOSYNC_OFF if autosync is off 3717 */ 3718 static int 3719 autosync_is_on(char *tohost, char *tofile) 3720 { 3721 CFGFILE *cfg; 3722 int setnumber, autosync_val = AUTOSYNC_OFF; 3723 char key[CFG_MAX_KEY]; 3724 char tag[CFG_MAX_BUF], val[CFG_MAX_BUF]; 3725 3726 if ((cfg = cfg_open(NULL)) == NULL) { 3727 rdc_err(NULL, gettext("unable to access configuration")); 3728 } 3729 3730 if (!cfg_lock(cfg, CFG_RDLOCK)) { 3731 cfg_close(cfg); 3732 rdc_err(NULL, gettext("unable to lock configuration")); 3733 } 3734 3735 if ((setnumber = find_setnumber_in_libcfg(cfg, NULL, tohost, tofile)) < 3736 0) { 3737 cfg_close(cfg); 3738 rdc_err(NULL, gettext("cannot find Remote Mirror set %s:%s in " 3739 "config"), tohost, tofile); 3740 } 3741 3742 (void) snprintf(key, CFG_MAX_KEY, "sndr.set%d.options", setnumber); 3743 if (cfg_get_options(cfg, CFG_SEC_CONF, key, tag, CFG_MAX_BUF, val, 3744 CFG_MAX_BUF) >= 0) { 3745 do { 3746 if (strcmp(tag, "auto") == 0) { 3747 if (strcmp(val, "on") == 0) { 3748 autosync_val = AUTOSYNC_ON; 3749 } 3750 break; 3751 } 3752 } while (cfg_get_options(cfg, CFG_SEC_CONF, NULL, tag, 3753 CFG_MAX_BUF, val, CFG_MAX_BUF) >= 0); 3754 } 3755 3756 cfg_close(cfg); 3757 return (autosync_val); 3758 } 3759 3760 void 3761 enable_autosync(char *fhost, char *ffile, char *thost, char *tfile) 3762 { 3763 rdc_config_t parms; 3764 spcs_s_info_t ustat; 3765 rdc_addr_t *p; 3766 3767 ustat = spcs_s_ucreate(); 3768 parms.command = RDC_CMD_TUNABLE; 3769 3770 p = &parms.rdc_set[0].primary; 3771 (void) strncpy(p->intf, fhost, MAX_RDC_HOST_SIZE); 3772 (void) strncpy(p->file, ffile, MAX_RDC_HOST_SIZE); 3773 3774 p = &parms.rdc_set[0].secondary; 3775 (void) strncpy(p->intf, thost, NSC_MAXPATH); 3776 (void) strncpy(p->file, tfile, NSC_MAXPATH); 3777 3778 parms.rdc_set[0].autosync = 1; 3779 parms.rdc_set[0].maxqfbas = -1; 3780 parms.rdc_set[0].maxqitems = -1; 3781 parms.rdc_set[0].asyncthr = -1; 3782 parms.rdc_set[0].netconfig = NULL; 3783 3784 if ((RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustat)) != 3785 SPCS_S_OK) { 3786 rdc_warn(&ustat, gettext("failed to update autosync for" 3787 " Remote Mirror set %s:%s"), thost, tfile); 3788 spcs_log("sndr", &ustat, gettext("failed to update autosync for" 3789 " Remote Mirror set %s:%s"), thost, tfile); 3790 } 3791 spcs_s_ufree(&ustat); 3792 } 3793 3794 static int 3795 rdc_operation(CFGFILE *cfg, char *fromhost, char *fromfile, char *frombitmap, 3796 char *tohost, char *tofile, char *tobitmap, 3797 int flag, int iflag, 3798 char *directfile, char *group, char *ctag, char *diskqueue, 3799 int *doasync, int reverse) 3800 { 3801 const int getaddr = (flag == RDC_CMD_ENABLE); 3802 const int rpcbind = !getaddr; 3803 rdc_config_t parms; 3804 int ret; 3805 spcs_s_info_t ustatus; 3806 struct hostent *hp; 3807 char fromname[MAXHOSTNAMELEN], toname[MAXHOSTNAMELEN]; 3808 char orig_fbmp[MAXHOSTNAMELEN], orig_tbmp[MAXHOSTNAMELEN]; 3809 char orig_diskq[NSC_MAXPATH]; 3810 struct t_info tinfo; 3811 int success = 1; 3812 int autosync_toggle_needed = 0; 3813 char *vol1, *vol2, *vol3; 3814 3815 conf = &nconf; 3816 3817 hp = gethost_byname(fromhost); 3818 (void) strncpy(fromname, hp->h_name, MAXHOSTNAMELEN); 3819 hp = gethost_byname(tohost); 3820 (void) strncpy(toname, hp->h_name, MAXHOSTNAMELEN); 3821 3822 if (self_check(fromname) && self_check(toname)) { 3823 rdc_err(NULL, gettext("both %s and %s are local"), 3824 fromhost, tohost); 3825 } 3826 3827 /* we have to find out what to sv disable after reconfig */ 3828 if (flag == RDC_CMD_RECONFIG) { 3829 3830 parms.command = RDC_CMD_STATUS; 3831 parms.rdc_set->netconfig = NULL; 3832 (void) strncpy(parms.rdc_set->primary.intf, fromhost, 3833 MAX_RDC_HOST_SIZE); 3834 (void) strncpy(parms.rdc_set->secondary.intf, tohost, 3835 MAX_RDC_HOST_SIZE); 3836 (void) strncpy(parms.rdc_set->primary.file, fromfile, 3837 NSC_MAXPATH); 3838 (void) strncpy(parms.rdc_set->secondary.file, tofile, 3839 NSC_MAXPATH); 3840 ustatus = spcs_s_ucreate(); 3841 ret = RDC_IOCTL(RDC_CONFIG, &parms, 3842 NULL, 0, 0, 0, ustatus); 3843 if (ret != SPCS_S_OK) { 3844 rdc_err(NULL, gettext("unable to get set status" 3845 " before reconfig operation")); 3846 } 3847 (void) strncpy(orig_fbmp, parms.rdc_set->primary.bitmap, 3848 NSC_MAXPATH); 3849 (void) strncpy(orig_tbmp, parms.rdc_set->secondary.bitmap, 3850 NSC_MAXPATH); 3851 (void) strncpy(orig_diskq, parms.rdc_set->disk_queue, 3852 NSC_MAXPATH); 3853 } 3854 3855 /* 3856 * another terrible addition, if we are reconfigging mode 3857 * and not logging, just give up. 3858 */ 3859 if ((reconfig_doasync != -1) && 3860 (!(parms.rdc_set->flags & RDC_LOGGING))) { 3861 rdc_err(NULL, gettext("cannot reconfigure sync/async, " 3862 "Remote Mirror set not logging")); 3863 spcs_log("sndr", NULL, gettext("cannot reconfigure sync/async, " 3864 "Remote Mirror set not logging")); 3865 } 3866 3867 /* 3868 * Now build up the address for each host including port and transport 3869 */ 3870 if (getaddr) { 3871 svp = get_addr(toname, RDC_PROGRAM, RDC_VERS_MIN, 3872 &conf, proto_test ? NC_UDP:NULL, "rdc", &tinfo, 3873 rpcbind); 3874 3875 if (svp == NULL) { 3876 rdc_warn(NULL, gettext("unable to determine network " 3877 "information for %s"), toname); 3878 #ifdef DEBUG 3879 (void) printf("get_addr failed for Ver 4 %s\n", toname); 3880 #endif 3881 return (-1); 3882 } 3883 svaddr = *svp; 3884 } else { 3885 bzero(&svaddr, sizeof (svaddr)); 3886 } 3887 3888 parms.rdc_set->secondary.addr.len = svaddr.len; 3889 parms.rdc_set->secondary.addr.maxlen = 3890 svaddr.maxlen; 3891 parms.rdc_set->secondary.addr.buf = 3892 (void *)svaddr.buf; 3893 3894 #ifdef DEBUG_ADDR 3895 (void) fprintf(stderr, "secondary buf %x len %d\n", 3896 svaddr.buf, svaddr.len); 3897 3898 for (i = 0; i < svaddr.len; i++) 3899 (void) printf("%u ", svaddr.buf[i]); 3900 (void) printf("\n"); 3901 #endif 3902 3903 if (getaddr) { 3904 svp = get_addr(fromname, RDC_PROGRAM, RDC_VERS_MIN, 3905 &conf, proto_test ? NC_UDP: NULL, "rdc", &tinfo, 3906 rpcbind); 3907 if (svp == NULL) { 3908 #ifdef DEBUG 3909 (void) printf("get_addr failed for Ver 4 %s\n", 3910 fromname); 3911 #endif 3912 return (-1); 3913 } 3914 svaddr = *svp; 3915 } 3916 3917 parms.rdc_set->primary.addr.len = svaddr.len; 3918 parms.rdc_set->primary.addr.maxlen = svaddr.maxlen; 3919 parms.rdc_set->primary.addr.buf = (void *)svaddr.buf; 3920 3921 #ifdef DEBUG_ADDR 3922 (void) fprintf(stderr, "primary buf %x len %d\n", 3923 svaddr.buf, svaddr.len); 3924 for (i = 0; i < svaddr.len; i++) 3925 (void) printf("%u ", svaddr.buf[i]); 3926 (void) printf("\n"); 3927 #endif 3928 3929 if (getaddr) { 3930 (void) convert_nconf_to_knconf(conf, &knconf); 3931 #ifdef DEBUG_ADDR 3932 (void) printf("knconf %x %s %s %x\n", knconf.knc_semantics, 3933 knconf.knc_protofmly, knconf.knc_proto, knconf.knc_rdev); 3934 #endif 3935 parms.rdc_set->netconfig = &knconf; 3936 } else { 3937 parms.rdc_set->netconfig = NULL; 3938 } 3939 3940 if (!self_check(fromname) && !self_check(toname)) { 3941 if (!clustered) 3942 rdc_err(NULL, gettext("neither %s nor %s is local"), 3943 fromhost, tohost); 3944 else { 3945 /* 3946 * IF we could get a list of logical hosts on this cluster 3947 * Then we could print something intelligent about where 3948 * the volume is mastered. For now, just print some babble 3949 * about the fact that we have no idea. 3950 */ 3951 rdc_err(NULL, 3952 gettext("either %s:%s or %s:%s is not local"), 3953 fromhost, fromfile, tohost, tofile); 3954 } 3955 } 3956 3957 (void) strncpy(parms.rdc_set->primary.intf, fromhost, 3958 MAX_RDC_HOST_SIZE); 3959 (void) strncpy(parms.rdc_set->primary.file, fromfile, NSC_MAXPATH); 3960 (void) strncpy(parms.rdc_set->primary.bitmap, frombitmap, NSC_MAXPATH); 3961 3962 (void) strncpy(parms.rdc_set->secondary.intf, tohost, 3963 MAX_RDC_HOST_SIZE); 3964 (void) strncpy(parms.rdc_set->secondary.file, tofile, NSC_MAXPATH); 3965 (void) strncpy(parms.rdc_set->secondary.bitmap, tobitmap, NSC_MAXPATH); 3966 3967 if ((group == NULL) || ((strcmp(group, "-")) == 0)) 3968 parms.rdc_set->group_name[0] = 0; 3969 else 3970 (void) strncpy(parms.rdc_set->group_name, group, NSC_MAXPATH); 3971 3972 if (self_check(tohost) && 3973 (strlen(diskqueue) > 0) && (diskqueue[0] != '-')) 3974 if ((flag == RDC_CMD_ENABLE) || (flag == RDC_CMD_ADDQ)) 3975 rdc_err(NULL, gettext("enabling disk queue on a Remote" 3976 " Mirror secondary is not allowed (%s)"), 3977 diskqueue); 3978 3979 if ((diskqueue == NULL) || ((strcmp(diskqueue, "-")) == 0)) 3980 parms.rdc_set->disk_queue[0] = 0; 3981 else 3982 (void) strncpy(parms.rdc_set->disk_queue, diskqueue, 3983 NSC_MAXPATH); 3984 3985 parms.rdc_set->maxqfbas = maxqfbas; 3986 parms.rdc_set->maxqitems = maxqitems; 3987 parms.rdc_set->asyncthr = asyncthr; 3988 /* set up the permanent set id for this set */ 3989 if (flag == RDC_CMD_ENABLE) { 3990 char key[CFG_MAX_KEY]; 3991 char setid[64]; 3992 int set; 3993 parms.rdc_set->setid = get_new_cfg_setid(cfg); 3994 if (parms.rdc_set->setid <= 0) { 3995 rdc_err(NULL, gettext("unable to obtain unique set id " 3996 "for %s:%s"), tohost, tofile); 3997 } 3998 if ((set = find_setnumber_in_libcfg(cfg, clustered? ctag : NULL, 3999 tohost, tofile)) < 0) { 4000 rdc_err(NULL, gettext("unable to store unique set id" 4001 " for %s:%s"), tohost, tofile); 4002 } 4003 (void) snprintf(key, sizeof (key), "sndr.set%d.options", set); 4004 (void) snprintf(setid, sizeof (setid), "%d", 4005 parms.rdc_set->setid); 4006 4007 if (cfg_put_options(cfg, CFG_SEC_CONF, key, "setid", 4008 setid) < 0) { 4009 rdc_err(NULL, gettext("unable to store unique set " 4010 "id for %s:%s: %s"), tohost, tofile, 4011 gettext(cfg_error(NULL))); 4012 } 4013 } else if (flag != RDC_CMD_DISABLE) { /* set already gone from cfg */ 4014 parms.rdc_set->setid = get_cfg_setid(cfg, ctag, tohost, tofile); 4015 if (parms.rdc_set->setid <= 0) { 4016 rdc_err(NULL, gettext("unable to obtain unique set id " 4017 "for %s:%s"), tohost, tofile); 4018 } 4019 } 4020 4021 /* 4022 * Always set autosync flag to default so nothing gets messed up. If 4023 * we are doing an autosync operation, it'll all get taken care of 4024 * then. 4025 */ 4026 parms.rdc_set->autosync = AUTOSYNC; 4027 4028 4029 /* gethostid(3c) is defined to return a 32bit value */ 4030 parms.rdc_set->syshostid = (int32_t)gethostid(); 4031 4032 parms.command = 0; 4033 parms.options = iflag; 4034 parms.command = flag; 4035 if (flag == RDC_CMD_ENABLE || flag == RDC_CMD_RECONFIG) { 4036 if (*doasync) 4037 parms.options |= RDC_OPT_ASYNC; 4038 else 4039 parms.options |= RDC_OPT_SYNC; 4040 } else if (flag == RDC_CMD_COPY) { 4041 if (reverse) 4042 parms.options |= RDC_OPT_REVERSE; 4043 else 4044 parms.options |= RDC_OPT_FORWARD; 4045 } 4046 4047 if (self_check(fromname)) { 4048 if (flag == RDC_CMD_COPY && reverse && mounted(fromfile)) 4049 rdc_err(NULL, gettext("can not start reverse sync" 4050 " as a file system is mounted on %s"), 4051 fromfile); 4052 parms.options |= RDC_OPT_PRIMARY; 4053 if (strcmp(directfile, "ip") == 0) 4054 parms.rdc_set->direct_file[0] = 0; /* no directfile */ 4055 else 4056 (void) strncpy(parms.rdc_set->direct_file, directfile, 4057 NSC_MAXPATH); 4058 } else { 4059 parms.options |= RDC_OPT_SECONDARY; 4060 parms.rdc_set->direct_file[0] = 0; /* no fcal directio */ 4061 } 4062 4063 if ((asyncthr || maxqitems || maxqfbas || qblock) && 4064 (parms.options & RDC_OPT_SECONDARY)) { 4065 rdc_err(NULL, gettext("changing queue parameters may " 4066 " only be done on a primary Remote Mirror host")); 4067 spcs_log("sndr", NULL, gettext("changing queue parameters may " 4068 " only be done on a primary Remote Mirror host")); 4069 4070 } 4071 4072 ustatus = spcs_s_ucreate(); 4073 4074 if (flag == RDC_CMD_COPY) { 4075 parms.command = RDC_CMD_STATUS; 4076 ret = RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus); 4077 if ((ret != SPCS_S_OK) || 4078 !(parms.rdc_set->flags & RDC_LOGGING)) { 4079 rdc_err(NULL, gettext("can not start sync" 4080 " as Remote Mirror set %s:%s is not logging"), 4081 tohost, tofile); 4082 } 4083 spcs_log("sndr", NULL, 4084 gettext("%s %s %s %s %s %s %s %s\nStarting"), 4085 program, rdc_decode_flag(flag, parms.options), 4086 fromhost, fromfile, frombitmap, 4087 tohost, tofile, tobitmap); 4088 parms.command = RDC_CMD_COPY; 4089 } 4090 4091 if ((flag == RDC_CMD_COPY) && 4092 (autosync_is_on(tohost, tofile) == AUTOSYNC_ON)) { 4093 /* check if autosync needs to be turned on when doing a copy/update */ 4094 parms.rdc_set->autosync = AUTOSYNC_ON; 4095 autosync_toggle_needed = 1; 4096 } else if ((flag == RDC_CMD_LOG) && 4097 (autosync_is_on(tohost, tofile) == AUTOSYNC_ON)) { 4098 /* check if autosync needs to be turned off when going to logging */ 4099 parms.rdc_set->autosync = AUTOSYNC_OFF; 4100 autosync_toggle_needed = 1; 4101 } else if (((autosync == AUTOSYNC_ON) || (autosync == AUTOSYNC_OFF)) && 4102 (flag == RDC_CMD_TUNABLE)) { 4103 /* 4104 * Request to change the autosync value. cfg file will be 4105 * available at this point. If autosync request is to turn off, 4106 * mark off in both the config and the kernel regardless of 4107 * the state of the set. If the request is to turn autosync on, 4108 * set in the kernel if the set is not in logging mode. 4109 * 4110 * XXX 4111 * If the set is in logging mode because of a network 4112 * failure, we will not know. Therefore, a manual update 4113 * will have to be issued to enable autosync in the 4114 * kernel. 4115 * XXX 4116 */ 4117 set_autosync(autosync, tohost, tofile, ctag); 4118 4119 if (autosync == AUTOSYNC_OFF) { 4120 parms.rdc_set->autosync = AUTOSYNC_OFF; 4121 } else if (autosync == AUTOSYNC_ON) { 4122 parms.command = RDC_CMD_STATUS; 4123 ret = RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, 4124 ustatus); 4125 if (ret != SPCS_S_OK) { 4126 rdc_err(NULL, gettext("can not determine " 4127 "status of Remote Mirror set %s:%s"), 4128 tohost, tofile); 4129 } 4130 4131 /* need to reset the tunables after a status ioctl */ 4132 parms.rdc_set->autosync = autosync; 4133 parms.rdc_set->maxqfbas = maxqfbas; 4134 parms.rdc_set->maxqitems = maxqitems; 4135 parms.rdc_set->asyncthr = asyncthr; 4136 4137 /* 4138 * if in logging mode, just update config, kernel will 4139 * be updated with the next copy/update request. 4140 */ 4141 if (parms.rdc_set->flags & RDC_LOGGING) { 4142 parms.rdc_set->autosync = AUTOSYNC; 4143 } else { 4144 parms.rdc_set->autosync = AUTOSYNC_ON; 4145 } 4146 4147 parms.command = flag; 4148 } 4149 } 4150 4151 if (autosync_toggle_needed) { 4152 parms.command = RDC_CMD_TUNABLE; 4153 ret = RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus); 4154 if (ret != SPCS_S_OK) { 4155 spcs_log("sndr", NULL, gettext("failed to update " 4156 "autosync for Remote Mirror set %s:%s"), tohost, 4157 tofile); 4158 rdc_err(NULL, gettext("failed to update autosync for " 4159 "Remote Mirror set %s:%s"), tohost, tofile); 4160 } 4161 /* reset command and default autosync flags */ 4162 parms.rdc_set->autosync = AUTOSYNC; 4163 parms.command = flag; 4164 } 4165 4166 errno = 0; 4167 ret = RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus); 4168 if ((ret != SPCS_S_OK) && (flag != RDC_CMD_HEALTH)) { 4169 (void) fprintf(stderr, 4170 gettext("Remote Mirror: %s %s %s %s %s %s\n"), 4171 fromhost, fromfile, 4172 frombitmap, tohost, tofile, tobitmap); 4173 4174 if (errno == RDC_EEINVAL) { 4175 spcs_log("sndr", NULL, 4176 "%s %s %s %s %s %s %s %s\n%s", 4177 program, rdc_decode_flag(flag, parms.options), 4178 fromhost, fromfile, frombitmap, 4179 tohost, tofile, tobitmap, 4180 gettext("invalid command option")); 4181 rdc_err(&ustatus, 4182 gettext("Remote Mirror: invalid command option " 4183 "'%s'"), rdc_decode_flag(flag, 4184 parms.options)); 4185 } else { 4186 spcs_log("sndr", &ustatus, 4187 "%s %s %s %s %s %s %s %s", 4188 program, rdc_decode_flag(flag, parms.options), 4189 fromhost, fromfile, frombitmap, 4190 tohost, tofile, tobitmap); 4191 if ((flag == RDC_CMD_RECONFIG) && 4192 (!(iflag & RDC_OPT_REVERSE_ROLE))) { 4193 success = 0; 4194 rdc_warn(&ustatus, 0); 4195 } else 4196 rdc_err(&ustatus, 0); 4197 } 4198 } 4199 if ((flag == RDC_CMD_RECONFIG) && (iflag & RDC_OPT_REVERSE_ROLE) == 0) { 4200 parms.command = RDC_CMD_STATUS; 4201 if (RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus) == 4202 SPCS_S_OK) { 4203 char shostbuf[CFG_MAX_BUF]; 4204 char svolbuf[CFG_MAX_BUF]; 4205 char key[CFG_MAX_KEY]; 4206 int i, numels; 4207 int cfgsuccess = 1; 4208 4209 /* 4210 * okeydoke, at this point we could have a reconfig 4211 * gone bad. libdscfg does not know about this. 4212 * parms contains the kernel picture, and we know 4213 * what we tried to reconfig. find out where it went 4214 * wrong, find the set in libdscfg, update it. We'll 4215 * issue a warning, then return 0 (eventually). 4216 * this will allow libdscfg to be committed with the 4217 * good info. got it? 4218 * BTW: the only time we can run into this multiple 4219 * reconfig attempt failure is IF we reconfig from file 4220 * and some thing goes wrong with one of the reconfigs 4221 */ 4222 4223 /* find the set in libdscfg */ 4224 4225 numels = cfg_get_num_entries(cfg, "sndr"); 4226 /* yes, numels could be -1 */ 4227 for (i = 1; i < numels; i++) { 4228 bzero(shostbuf, sizeof (shostbuf)); 4229 bzero(svolbuf, sizeof (svolbuf)); 4230 bzero(key, sizeof (key)); 4231 4232 (void) snprintf(key, sizeof (key), 4233 "sndr.set%d.shost", i); 4234 4235 (void) cfg_get_cstring(cfg, key, &shostbuf, 4236 sizeof (shostbuf)); 4237 if (strncmp(shostbuf, tohost, sizeof (tohost))) 4238 continue; 4239 4240 bzero(key, sizeof (key)); 4241 (void) snprintf(key, sizeof (key), 4242 "sndr.set%d.secondary", i); 4243 (void) cfg_get_cstring(cfg, key, &svolbuf, 4244 sizeof (svolbuf)); 4245 if (strncmp(svolbuf, tofile, NSC_MAXPATH)) 4246 continue; 4247 break; 4248 4249 /* 4250 * found it, now i contains the set offset. 4251 * i, being the variable, not bad english. 4252 */ 4253 4254 } 4255 /* shouldn't happen */ 4256 if ((numels < 1) || (i > numels)) { 4257 rdc_warn(NULL, gettext("unable to retrieve " 4258 "set from configuration database")); 4259 /* 4260 * yuck. but indents are pushing the envelope 4261 * we should not be updating config 4262 * if we did not find the entry 4263 * the error will have to do 4264 */ 4265 cfgsuccess = 0; 4266 goto notfound; 4267 } 4268 4269 /* 4270 * now, put all the correct names back for errors etc. 4271 * also, sock them into dscfg, if the the config was a 4272 * success for one, it will be a redundant but harmless 4273 */ 4274 4275 /* 4276 * we could not have reconfigged mode if we 4277 * are not logging, AND the kernel CAN return 4278 * sync as the status of an async set if it is 4279 * currently syncing.. Hence the flags & RDC_LOGGING 4280 */ 4281 if (parms.rdc_set->flags & RDC_LOGGING) { 4282 bzero(key, sizeof (key)); 4283 (void) snprintf(key, sizeof (key), 4284 "sndr.set%d.mode", i); 4285 if (parms.rdc_set->flags & RDC_ASYNC) { 4286 *doasync = 1; 4287 if (cfg_put_cstring(cfg, key, "async", 4288 strlen("async")) < 0) { 4289 cfgsuccess = 0; 4290 } 4291 4292 } else { 4293 *doasync = 0; 4294 if (cfg_put_cstring(cfg, key, "sync", 4295 strlen("sync")) < 0) { 4296 cfgsuccess = 0; 4297 } 4298 } 4299 } 4300 #ifdef _RDC_CAMPUS 4301 if (*parms.rdc_set->direct_file) { 4302 (void) strncpy(directfile, 4303 parms.rdc_set->direct_file, NSC_MAXPATH); 4304 bzero(key, sizeof (key)); 4305 (void) snprintf(key, sizeof (key), 4306 "sndr.set%d.type", i); 4307 if (cfg_put_cstring(cfg, key, directfile, 4308 strlen(directfile)) < 0) 4309 cfgsuccess = 0; 4310 } else { 4311 (void) strncpy(directfile, "-", NSC_MAXPATH); 4312 bzero(key, sizeof (key)); 4313 (void) snprintf(key, sizeof (key), 4314 "sndr.set%d.type", i); 4315 if (cfg_put_cstring(cfg, key, directfile, 4316 strlen(directfile)) < 0) 4317 cfgsuccess = 0; 4318 } 4319 #endif 4320 4321 if (*parms.rdc_set->group_name) { 4322 (void) strncpy(group, parms.rdc_set->group_name, 4323 NSC_MAXPATH); 4324 bzero(key, sizeof (key)); 4325 (void) snprintf(key, sizeof (key), 4326 "sndr.set%d.group", i); 4327 if (cfg_put_cstring(cfg, key, group, 4328 strlen(group)) < 0) 4329 cfgsuccess = 0; 4330 4331 } else { 4332 (void) strncpy(group, "-", NSC_MAXPATH); 4333 bzero(key, sizeof (key)); 4334 (void) snprintf(key, sizeof (key), 4335 "sndr.set%d.group", i); 4336 if (cfg_put_cstring(cfg, key, group, 4337 strlen(group)) < 0) 4338 cfgsuccess = 0; 4339 } 4340 4341 if (*parms.rdc_set->disk_queue) { 4342 (void) strncpy(diskqueue, 4343 parms.rdc_set->disk_queue, NSC_MAXPATH); 4344 } else { 4345 (void) strncpy(diskqueue, "-", NSC_MAXPATH); 4346 } 4347 bzero(key, sizeof (key)); 4348 (void) snprintf(key, sizeof (key), 4349 "sndr.set%d.diskq", i); 4350 if (cfg_put_cstring(cfg, key, diskqueue, 4351 strlen(diskqueue)) < 0) 4352 cfgsuccess = 0; 4353 4354 (void) strncpy(frombitmap, 4355 parms.rdc_set->primary.bitmap, NSC_MAXPATH); 4356 bzero(key, sizeof (key)); 4357 (void) snprintf(key, sizeof (key), 4358 "sndr.set%d.pbitmap", i); 4359 if (cfg_put_cstring(cfg, key, frombitmap, 4360 strlen(frombitmap)) < 0) 4361 cfgsuccess = 0; 4362 4363 (void) strncpy(tobitmap, 4364 parms.rdc_set->secondary.bitmap, NSC_MAXPATH); 4365 bzero(key, sizeof (key)); 4366 (void) snprintf(key, sizeof (key), 4367 "sndr.set%d.sbitmap", i); 4368 if (cfg_put_cstring(cfg, key, tobitmap, 4369 strlen(tobitmap)) < 0) 4370 cfgsuccess = 0; 4371 4372 bzero(key, sizeof (key)); 4373 (void) snprintf(key, sizeof (key), 4374 "sndr.set%d.cnode", i); 4375 if (clustered) 4376 if (cfg_put_cstring(cfg, key, ctag, 4377 strlen(ctag)) < 0) 4378 cfgsuccess = 0; 4379 notfound: 4380 if (cfgsuccess == 0) { 4381 rdc_warn(NULL, gettext("unable to update " 4382 "configuration storage")); 4383 } 4384 } else { 4385 spcs_log("sndr", NULL, 4386 "%s %s %s %s %s %s %s %s\n%s", 4387 program, rdc_decode_flag(flag, parms.options), 4388 fromhost, fromfile, frombitmap, 4389 tohost, tofile, tobitmap, 4390 gettext("unable to update config file")); 4391 rdc_err(&ustatus, 4392 gettext("Remote Mirror: unable to update " 4393 "config file")); 4394 4395 } 4396 } 4397 4398 if (flag == RDC_CMD_HEALTH && errno == 0) { 4399 (void) fprintf(stderr, 4400 gettext("Remote Mirror: %s %s %s %s %s %s\n"), 4401 fromhost, fromfile, 4402 frombitmap, tohost, tofile, tobitmap); 4403 4404 if (ret == RDC_ACTIVE) 4405 (void) fprintf(stderr, "Active\n"); 4406 else if (ret == RDC_INACTIVE) 4407 (void) fprintf(stderr, "Inactive\n"); 4408 else 4409 (void) fprintf(stderr, "Unknown\n"); 4410 } else if (ret != SPCS_S_OK) { 4411 if (errno == RDC_EEINVAL) { 4412 spcs_log("sndr", NULL, 4413 "%s %s %s %s %s %s %s %s\n%s", 4414 program, rdc_decode_flag(flag, parms.options), 4415 fromhost, fromfile, frombitmap, 4416 tohost, tofile, tobitmap, 4417 gettext("invalid command option")); 4418 rdc_err(&ustatus, 4419 gettext("Remote Mirror: invalid command option " 4420 "'%s'"), 4421 rdc_decode_flag(flag, parms.options)); 4422 } 4423 } 4424 if (flag == RDC_CMD_STATUS) { 4425 (void) fprintf(stderr, 4426 gettext("Remote Mirror: %s %s %s %s %s %s\n"), 4427 fromhost, fromfile, 4428 frombitmap, tohost, tofile, tobitmap); 4429 (void) fprintf(stderr, "flags 0x%x\n", parms.rdc_set->flags | 4430 parms.rdc_set->sync_flags | parms.rdc_set->bmap_flags); 4431 } else if (success) { 4432 spcs_log("sndr", NULL, 4433 gettext("%s %s %s %s %s %s %s %s\nSuccessful"), 4434 program, rdc_decode_flag(flag, parms.options), 4435 fromhost, fromfile, frombitmap, 4436 tohost, tofile, tobitmap); 4437 if (flag == RDC_CMD_TUNABLE) 4438 spcslog_tunable(tohost, tofile); 4439 } 4440 4441 if (cfg && perform_autosv()) { 4442 spcs_s_ufree(&ustatus); 4443 /* figure out which are the local volumes */ 4444 if (parms.options & RDC_OPT_PRIMARY) { 4445 vol1 = fromfile; 4446 vol2 = frombitmap; 4447 if ((diskqueue && diskqueue[0]) && 4448 (strncmp(diskqueue, "-", 1) != 0)) 4449 vol3 = diskqueue; 4450 else 4451 vol3 = NULL; 4452 } else { 4453 vol1 = tofile; 4454 vol2 = tobitmap; 4455 vol3 = NULL; 4456 if ((flag == RDC_CMD_ENABLE) && 4457 (strlen(diskqueue) > 0) && 4458 (strncmp(diskqueue, "-", 1)) != 0) { 4459 rdc_warn(NULL, 4460 gettext("enabling a disk queue on a " 4461 "Remote Mirror secondary is not allowed. " 4462 "(%s) ignored"), diskqueue); 4463 } 4464 } 4465 4466 if (flag == RDC_CMD_ENABLE) { 4467 ustatus = spcs_s_ucreate(); 4468 /* 4469 * SV-enable all local volumes 4470 * if the sv_enables fail, disable the sndr vols 4471 * that we just enabled 4472 * and return -1 so the cfg_commit() won't happen 4473 */ 4474 4475 if (nsc_lookup(volhash, vol1) == NULL) { 4476 if (cfg_vol_enable(cfg, vol1, ctag, "sndr") 4477 < 0) { 4478 spcs_log("sndr", NULL, 4479 "sv enable failed for %s, " 4480 "disabling Remote Mirror set %s:%s", 4481 vol1, tohost, tofile); 4482 /* 4483 * warn here, but we are going to exit 4484 * we want to catch any errors on the 4485 * way down, then exit 4486 */ 4487 4488 rdc_warn(NULL, 4489 "unable to sv enable %s\n" 4490 "disabling Remote Mirror set %s:%s", 4491 vol1, tohost, tofile); 4492 4493 parms.command = RDC_CMD_DISABLE; 4494 ret = RDC_IOCTL(RDC_CONFIG, &parms, 4495 NULL, 0, 0, 0, ustatus); 4496 if (ret != SPCS_S_OK) { 4497 (void) fprintf(stderr, 4498 gettext("Remote Mirror:" 4499 " %s %s %s %s %s %s\n"), 4500 fromhost, fromfile, 4501 frombitmap, tohost, tofile, 4502 tobitmap); 4503 spcs_log("sndr", &ustatus, 4504 "%s %s %s %s %s %s %s %s", 4505 program, 4506 rdc_decode_flag(parms.command, 4507 parms.options), 4508 fromhost, 4509 fromfile, frombitmap, 4510 tohost, tofile, tobitmap); 4511 rdc_err(&ustatus, 0); 4512 } 4513 /* 4514 * ok, we should've reported any errs 4515 * exit explictly 4516 */ 4517 exit(1); 4518 4519 } 4520 } 4521 if (vol2 && nsc_lookup(volhash, vol2) == NULL) { 4522 if (cfg_vol_enable(cfg, vol2, ctag, "sndr") 4523 < 0) { 4524 spcs_log("sndr", NULL, 4525 "sv enable failed for %s, " 4526 "disabling Remote Mirror set %s:%s", 4527 vol1, tohost, tofile); 4528 /* 4529 * warn here, but we are going to exit 4530 * we want to catch any errors on the 4531 * way down, then exit 4532 */ 4533 4534 rdc_warn(NULL, 4535 "unable to sv enable %s\n" 4536 "disabling Remote Mirror set %s:%s", 4537 vol2, tohost, tofile); 4538 4539 parms.command = RDC_CMD_DISABLE; 4540 ret = RDC_IOCTL(RDC_CONFIG, &parms, 4541 NULL, 0, 0, 0, ustatus); 4542 if (ret != SPCS_S_OK) { 4543 (void) fprintf(stderr, 4544 gettext("Remote Mirror:" 4545 " %s %s %s %s %s %s\n"), 4546 fromhost, fromfile, 4547 frombitmap, tohost, tofile, 4548 tobitmap); 4549 spcs_log("sndr", &ustatus, 4550 "%s %s %s %s %s %s %s %s", 4551 program, 4552 rdc_decode_flag(parms.command, 4553 parms.options), 4554 fromhost, 4555 fromfile, frombitmap, 4556 tohost, tofile, tobitmap); 4557 rdc_err(&ustatus, 0); 4558 } 4559 /* 4560 * ok, we should've reported any errs 4561 * exit explictly 4562 */ 4563 exit(1); 4564 4565 } 4566 } 4567 4568 if (vol3 && nsc_lookup(volhash, diskqueue) == NULL) { 4569 if (cfg_vol_enable(cfg, diskqueue, ctag, "sndr") 4570 < 0) { 4571 spcs_log("sndr", NULL, 4572 "sv enable failed for %s, " 4573 "disabling Remote Mirror set %s:%s", 4574 diskqueue, tohost, tofile); 4575 if (cfg_vol_disable(cfg, vol1, ctag, 4576 "sndr") < 0) 4577 rdc_warn(NULL, gettext("Failed to " 4578 "remove volume [%s] from " 4579 "configuration"), vol1); 4580 if (cfg_vol_disable(cfg, vol2, ctag, 4581 "sndr") < 0) 4582 rdc_warn(NULL, gettext("Failed to " 4583 "remove volume [%s] from " 4584 "configuration"), vol2); 4585 4586 /* 4587 * warn here, but we are going to exit 4588 * we want to catch any errors on the 4589 * way down, then exit 4590 */ 4591 4592 rdc_warn(NULL, 4593 "unable to sv enable %s\n" 4594 "disabling Remote Mirror set %s:%s", 4595 diskqueue, tohost, tofile); 4596 4597 parms.command = RDC_CMD_DISABLE; 4598 ret = RDC_IOCTL(RDC_CONFIG, &parms, 4599 NULL, 0, 0, 0, ustatus); 4600 if (ret != SPCS_S_OK) { 4601 (void) fprintf(stderr, 4602 gettext("Remote Mirror:" 4603 " %s %s %s %s %s %s\n"), 4604 fromhost, fromfile, 4605 frombitmap, tohost, tofile, 4606 tobitmap); 4607 spcs_log("sndr", &ustatus, 4608 "%s %s %s %s %s %s %s %s", 4609 program, 4610 rdc_decode_flag(parms.command, 4611 parms.options), 4612 fromhost, 4613 fromfile, frombitmap, 4614 tohost, tofile, tobitmap); 4615 rdc_err(&ustatus, 0); 4616 } 4617 /* 4618 * ok, we should've reported any errs 4619 * exit explictly 4620 */ 4621 exit(1); 4622 4623 } 4624 } 4625 } else if (flag == RDC_CMD_DISABLE) { 4626 /* 4627 * If we're no longer using a volume, SV-disable it 4628 */ 4629 volcount_t *vc; 4630 4631 vc = nsc_lookup(volhash, vol1); 4632 if (vc && (1 == vc->count)) { 4633 if (cfg_vol_disable(cfg, vol1, ctag, "sndr") 4634 < 0) 4635 rdc_warn(NULL, gettext("Failed to " 4636 "remove volume [%s] from " 4637 "configuration"), vol1); 4638 4639 } else if (!vc) { 4640 rdc_warn(NULL, 4641 gettext("Unable to find %s in config"), 4642 vol1); 4643 } 4644 4645 if (vol2) { 4646 vc = nsc_lookup(volhash, vol2); 4647 if (vc && (1 == vc->count)) { 4648 if (cfg_vol_disable(cfg, vol2, ctag, 4649 "sndr") < 0) 4650 rdc_warn(NULL, gettext("Failed to " 4651 "remove volume [%s] from " 4652 "configuration"), vol2); 4653 } else if (!vc) { 4654 rdc_warn(NULL, gettext("Unable to find" 4655 " %s in config"), vol2); 4656 } 4657 } 4658 4659 if (diskqueue != NULL && strlen(diskqueue) > 0) { 4660 vc = nsc_lookup(volhash, diskqueue); 4661 if (vc && (1 == vc->count)) { 4662 if (cfg_vol_disable(cfg, diskqueue, ctag, 4663 "sndr") < 0) 4664 rdc_warn(NULL, gettext("Failed to " 4665 "remove disk queue [%s] from " 4666 "configuration"), diskqueue); 4667 } else if (!vc) { 4668 rdc_warn(NULL, gettext("Unable to find" 4669 " %s in config"), diskqueue); 4670 } 4671 } 4672 /* WARNING about to go to 4 space indenting */ 4673 } else if (flag == RDC_CMD_RECONFIG) { 4674 volcount_t *vc; 4675 /* disable ex-bitmaps, enable new bitmaps */ 4676 if (parms.options & RDC_OPT_PRIMARY) { 4677 if (strcmp(orig_fbmp, frombitmap) != 0) { 4678 vc = nsc_lookup(volhash, orig_fbmp); 4679 if (vc && (vc->count == 1)) { 4680 if (cfg_vol_disable(cfg, orig_fbmp, ctag, 4681 "sndr") < 0) 4682 rdc_warn(NULL, gettext("Failed to " 4683 "remove bitmap [%s] from " 4684 "configuration"), orig_fbmp); 4685 } else if (!vc) { 4686 rdc_warn(NULL, gettext("Unable to find " 4687 "%s in config"), orig_fbmp); 4688 } 4689 if (nsc_lookup(volhash, frombitmap) == NULL) { 4690 if (cfg_vol_enable(cfg, frombitmap, ctag, 4691 "sndr") < 0) { 4692 spcs_log("sndr", NULL, 4693 "reconfig sv enable failed for %s, " 4694 "disabling Remote Mirror set %s:%s", 4695 frombitmap, tohost, tofile); 4696 rdc_warn(NULL, 4697 "unable to sv enable %s\n" 4698 "disabling Remote Mirror set %s:%s", 4699 frombitmap, tohost, tofile); 4700 parms.command = RDC_CMD_DISABLE; 4701 ret = RDC_IOCTL(RDC_CONFIG, &parms, 4702 NULL, 0, 0, 0, ustatus); 4703 if (ret != SPCS_S_OK) { 4704 (void) fprintf(stderr, 4705 gettext("Remote Mirror:" 4706 " %s %s %s %s %s %s\n"), 4707 fromhost, fromfile, 4708 frombitmap, tohost, tofile, 4709 tobitmap); 4710 spcs_log("sndr", &ustatus, 4711 "%s %s %s %s %s %s %s %s", 4712 program, 4713 rdc_decode_flag(parms.command, 4714 parms.options), 4715 fromhost, 4716 fromfile, frombitmap, 4717 tohost, tofile, tobitmap); 4718 rdc_warn(&ustatus, 0); 4719 } 4720 exit(1); 4721 } 4722 } 4723 } else if ((orig_diskq[0] != '\0') && 4724 (strcmp(orig_diskq, diskqueue) != 0)) { 4725 vc = nsc_lookup(volhash, orig_diskq); 4726 if (vc && (vc->count == 1)) { 4727 if (cfg_vol_disable(cfg, orig_diskq, ctag, 4728 "sndr") < 0) 4729 rdc_warn(NULL, gettext("Failed to " 4730 "remove disk queue [%s] from " 4731 "configuration"), orig_diskq); 4732 } else if (!vc) { 4733 rdc_warn(NULL, gettext("Unable to find " 4734 "%s in config"), orig_diskq); 4735 } 4736 if (vol3 && 4737 (nsc_lookup(volhash, diskqueue) == NULL)) { 4738 if (cfg_vol_enable(cfg, diskqueue, ctag, 4739 "sndr") < 0) { 4740 spcs_log("sndr", NULL, "reconfig sv " 4741 "enable of diskqueue %s failed, " 4742 "disabling Remote Mirror set %s:%s", 4743 diskqueue, tohost, tofile); 4744 rdc_warn(NULL, "reconfig sv " 4745 "enable of diskqueue %s failed." 4746 "disabling Remote Mirror set %s:%s", 4747 diskqueue, tohost, tofile); 4748 parms.command = RDC_CMD_DISABLE; 4749 ret = RDC_IOCTL(RDC_CONFIG, &parms, 4750 NULL, 0, 0, 0, ustatus); 4751 if (ret != SPCS_S_OK) { 4752 (void) fprintf(stderr, 4753 gettext("Remote Mirror:" 4754 " %s %s %s %s %s %s\n"), 4755 fromhost, fromfile, 4756 frombitmap, tohost, tofile, 4757 tobitmap); 4758 spcs_log("sndr", &ustatus, 4759 "%s %s %s %s %s %s %s %s", 4760 program, 4761 rdc_decode_flag(parms.command, 4762 parms.options), 4763 fromhost, 4764 fromfile, frombitmap, 4765 tohost, tofile, tobitmap); 4766 rdc_warn(&ustatus, 0); 4767 } 4768 exit(1); 4769 } 4770 } 4771 } 4772 } else if (flag != RDC_OPT_PRIMARY) { 4773 if (strcmp(orig_tbmp, tobitmap) != 0) { 4774 vc = nsc_lookup(volhash, orig_tbmp); 4775 if (vc && (vc->count == 1)) { 4776 if (cfg_vol_disable(cfg, orig_tbmp, ctag, 4777 "sndr") < 0) 4778 rdc_warn(NULL, gettext("Failed to " 4779 "remove bitmap [%s] from " 4780 "configuration"), orig_tbmp); 4781 } else if (!vc) { 4782 rdc_warn(NULL, 4783 gettext("Unable to find %s in config"), 4784 orig_tbmp); 4785 } 4786 if (nsc_lookup(volhash, tobitmap) == NULL) { 4787 if (cfg_vol_enable(cfg, tobitmap, ctag, 4788 "sndr") < 0) { 4789 spcs_log("sndr", NULL, 4790 "reconfig sv enable failed for %s, " 4791 "disabling Remote Mirror set %s:%s", 4792 tobitmap, tohost, tofile); 4793 rdc_warn(NULL, 4794 "unable to sv enable %s\n" 4795 "disabling Remote Mirror set %s:%s", 4796 tobitmap, tohost, tofile); 4797 parms.command = RDC_CMD_DISABLE; 4798 ret = RDC_IOCTL(RDC_CONFIG, &parms, 4799 NULL, 0, 0, 0, ustatus); 4800 if (ret != SPCS_S_OK) { 4801 (void) fprintf(stderr, 4802 gettext("Remote Mirror:" 4803 " %s %s %s %s %s %s\n"), 4804 fromhost, fromfile, 4805 frombitmap, tohost, tofile, 4806 tobitmap); 4807 spcs_log("sndr", &ustatus, 4808 "%s %s %s %s %s %s %s %s", 4809 program, 4810 rdc_decode_flag(parms.command, 4811 parms.options), 4812 fromhost, fromfile, frombitmap, 4813 tohost, tofile, tobitmap); 4814 rdc_warn(&ustatus, 0); 4815 } 4816 exit(1); 4817 } 4818 } 4819 } 4820 } 4821 /* END 4 space indenting */ 4822 } 4823 } 4824 spcs_s_ufree(&ustatus); 4825 4826 return (0); 4827 } 4828 4829 4830 /* 4831 * read_config() 4832 * 4833 * DESCRIPTION: Read the lines in a configuration file and return the 4834 * pairs of devices to be mirrored/enabled/disabled/updated. 4835 * The format for the configuration file is as follows: 4836 * 4837 * fromhost fromfile frombitmap tohost tofile tobitmap 4838 * 4839 * where fromfile is the primary device which is local to the 4840 * fromhost subsystem, tofile is the secondary device which is 4841 * local to the tohost subsystem, and type is 1 if the device 4842 * a simckd device or 0 otherwise. Any line preceeded by a '#' 4843 * is considered to be a comment. 4844 * 4845 * Inputs: 4846 * char *config_file Name of configuration file for rdcadm 4847 * 4848 * Outputs: 4849 * int i Number of pairs of devices 4850 * 4851 * Side Effects: The 0 to i-1 entries in the pair_list are filled. 4852 * 4853 */ 4854 4855 int 4856 read_config(int flag, char *config_file, char *group_arg, char *ctag_arg) 4857 { 4858 int ret; 4859 char dsk_flagstr[NSC_MAXPATH]; 4860 char line[1024], tmp_line[1024]; 4861 char fromhost[MAX_RDC_HOST_SIZE]; 4862 char fromfile[NSC_MAXPATH]; 4863 char frombitmap[NSC_MAXPATH]; 4864 char tohost[MAX_RDC_HOST_SIZE]; 4865 char tofile[NSC_MAXPATH]; 4866 char tobitmap[NSC_MAXPATH]; 4867 char directfile[NSC_MAXPATH]; 4868 char sync[16]; 4869 int doasync; 4870 FILE *fp; 4871 int i, j; 4872 char *extra_args[EXTRA_ARGS]; 4873 char *tmp, *split_str = " \t\n"; 4874 4875 for (j = 0; j < EXTRA_ARGS; j++) 4876 extra_args[j] = malloc(NSC_MAXPATH); 4877 4878 if (!(fp = fopen(config_file, "r"))) { 4879 rdc_err(NULL, gettext("error opening %s"), config_file); 4880 } 4881 4882 i = 0; 4883 while (fgets(line, sizeof (line), fp)) { 4884 if (line[0] == '#') /* this is a comment */ 4885 continue; 4886 4887 ret = 0; 4888 (void) strcpy(tmp_line, line); 4889 4890 if ((tmp = strtok(tmp_line, split_str)) != NULL) { 4891 if (strlen(tmp) >= MAX_RDC_HOST_SIZE) { 4892 (void) printf(gettext("hostname is longer than %d " 4893 "characters\n"), (MAX_RDC_HOST_SIZE - 1)); 4894 continue; 4895 } 4896 (void) strncpy(fromhost, tmp, (MAX_RDC_HOST_SIZE - 1)); 4897 fromhost[(MAX_RDC_HOST_SIZE - 1)] = '\0'; 4898 ret++; 4899 } 4900 if ((tmp = strtok(NULL, split_str)) != NULL) { 4901 if (strlen(tmp) >= NSC_MAXPATH) { 4902 (void) printf(gettext( 4903 "device name is longer than %d " 4904 "characters\n"), (NSC_MAXPATH - 1)); 4905 continue; 4906 } 4907 (void) strncpy(fromfile, tmp, (NSC_MAXPATH - 1)); 4908 fromfile[(NSC_MAXPATH - 1)] = '\0'; 4909 ret++; 4910 } 4911 if ((tmp = strtok(NULL, split_str)) != NULL) { 4912 if (strlen(tmp) >= NSC_MAXPATH) { 4913 (void) printf(gettext( 4914 "device name is longer than %d " 4915 "characters\n"), (NSC_MAXPATH - 1)); 4916 continue; 4917 } 4918 (void) strncpy(frombitmap, tmp, (NSC_MAXPATH - 1)); 4919 frombitmap[(NSC_MAXPATH - 1)] = '\0'; 4920 ret++; 4921 } 4922 if ((tmp = strtok(NULL, split_str)) != NULL) { 4923 if (strlen(tmp) >= MAX_RDC_HOST_SIZE) { 4924 (void) printf(gettext( 4925 "hostname is longer than %d " 4926 "characters\n"), (MAX_RDC_HOST_SIZE - 1)); 4927 continue; 4928 } 4929 (void) strncpy(tohost, tmp, (MAX_RDC_HOST_SIZE - 1)); 4930 tohost[(MAX_RDC_HOST_SIZE - 1)] = '\0'; 4931 ret++; 4932 } 4933 if ((tmp = strtok(NULL, split_str)) != NULL) { 4934 if (strlen(tmp) >= NSC_MAXPATH) { 4935 (void) printf(gettext( 4936 "device name is longer than %d " 4937 "characters\n"), (NSC_MAXPATH - 1)); 4938 continue; 4939 } 4940 (void) strncpy(tofile, tmp, (NSC_MAXPATH - 1)); 4941 tofile[(NSC_MAXPATH - 1)] = '\0'; 4942 ret++; 4943 } 4944 if ((tmp = strtok(NULL, split_str)) != NULL) { 4945 if (strlen(tmp) >= NSC_MAXPATH) { 4946 (void) printf(gettext( 4947 "device name is longer than %d " 4948 "characters\n"), (NSC_MAXPATH - 1)); 4949 continue; 4950 } 4951 (void) strncpy(tobitmap, tmp, (NSC_MAXPATH - 1)); 4952 tobitmap[(NSC_MAXPATH - 1)] = '\0'; 4953 ret++; 4954 } 4955 if ((tmp = strtok(NULL, split_str)) != NULL) { 4956 (void) strncpy(dsk_flagstr, tmp, 15); 4957 dsk_flagstr[15] = '\0'; 4958 ret++; 4959 } 4960 if ((tmp = strtok(NULL, split_str)) != NULL) { 4961 (void) strncpy(sync, tmp, 15); 4962 sync[15] = '\0'; 4963 ret++; 4964 } 4965 for (j = 0; j < EXTRA_ARGS; j++) { 4966 if ((tmp = strtok(NULL, split_str)) != NULL) { 4967 (void) strncpy(extra_args[j], tmp, 4968 (NSC_MAXPATH - 1)); 4969 extra_args[j][(NSC_MAXPATH - 1)] = '\0'; 4970 ret++; 4971 } 4972 } 4973 4974 if (ret == 0) /* this is a blank line */ 4975 continue; 4976 4977 if (ret < 8) { 4978 (void) fclose(fp); 4979 rdc_warn(NULL, 4980 gettext("invalid format in %s"), config_file); 4981 rdc_err(NULL, "%s", line); 4982 } 4983 4984 if (i >= rdc_maxsets) { 4985 (void) fclose(fp); 4986 rdc_err(NULL, 4987 gettext("number of Remote Mirror sets exceeds %d"), 4988 rdc_maxsets); 4989 } 4990 4991 #ifdef _RDC_CAMPUS 4992 if (dsk_flagstr[0] == '/') { 4993 /* fcal directio */ 4994 (void) strncpy(directfile, dsk_flagstr, NSC_MAXPATH); 4995 } else if (strcmp(dsk_flagstr, "ip") != 0) { 4996 #else 4997 if (strcmp(dsk_flagstr, "ip") != 0) { 4998 #endif 4999 (void) fclose(fp); 5000 rdc_err(NULL, 5001 #ifdef _RDC_CAMPUS 5002 gettext("ip/fcal specification missing")); 5003 #else 5004 gettext("ip specification missing")); 5005 #endif 5006 } else 5007 (void) strcpy(directfile, "ip"); 5008 5009 if (strcmp(sync, "sync") == 0) 5010 doasync = 0; 5011 else if (strcmp(sync, "async") == 0) 5012 doasync = 1; 5013 else { 5014 (void) fclose(fp); 5015 rdc_err(NULL, 5016 gettext("sync/async specification missing")); 5017 } 5018 (void) strncpy(pair_list[i].fhost, fromhost, MAX_RDC_HOST_SIZE); 5019 (void) strncpy(pair_list[i].ffile, fromfile, NSC_MAXPATH); 5020 (void) strncpy(pair_list[i].fbitmap, frombitmap, NSC_MAXPATH); 5021 (void) strncpy(pair_list[i].thost, tohost, MAX_RDC_HOST_SIZE); 5022 (void) strncpy(pair_list[i].tfile, tofile, NSC_MAXPATH); 5023 (void) strncpy(pair_list[i].tbitmap, tobitmap, NSC_MAXPATH); 5024 (void) strncpy(pair_list[i].directfile, directfile, 5025 NSC_MAXPATH); 5026 pair_list[i].doasync = doasync; 5027 5028 if (gethost_netaddrs(fromhost, tohost, 5029 (char *)pair_list[i].fnetaddr, 5030 (char *)pair_list[i].tnetaddr) < 0) { 5031 (void) fclose(fp); 5032 rdc_err(NULL, gettext("unable to determine IP " 5033 "addresses for hosts %s, %s"), fromhost, tohost); 5034 } 5035 5036 if (parse_extras(ret - 8, extra_args, i) < 0) { 5037 (void) fclose(fp); 5038 rdc_err(NULL, gettext("illegal option in:\n%s"), 5039 line); 5040 } 5041 5042 if (flag == RDC_CMD_ENABLE || flag == RDC_CMD_RECONFIG) { 5043 if (ctag_check(fromhost, fromfile, frombitmap, 5044 tohost, tofile, tobitmap, pair_list[i].ctag, 5045 pair_list[i].diskqueue) < 0) 5046 continue; /* Ignore illegal sets */ 5047 if (pair_diskqueue_check(i)) 5048 continue; /* ignore sets with incorrect diskq */ 5049 } 5050 5051 /* Filter according to ctag and group arguments */ 5052 if (strcmp(ctag_arg, "") && 5053 strncmp(ctag_arg, pair_list[i].ctag, 5054 MAX_RDC_HOST_SIZE)) 5055 continue; 5056 if (strcmp(group_arg, "") && 5057 strncmp(group_arg, pair_list[i].group, NSC_MAXPATH)) 5058 continue; 5059 5060 i++; 5061 } 5062 (void) fclose(fp); 5063 for (j = 0; j < EXTRA_ARGS; j++) 5064 free(extra_args[j]); 5065 return (i); 5066 } 5067 5068 5069 /* 5070 * read_libcfg() 5071 * 5072 * DESCRIPTION: Read the relevant config info via libcfg 5073 * 5074 * Outputs: 5075 * int i Number of pairs of devices 5076 * 5077 * Side Effects: The 0 to i-1 entries in the pair_list are filled. 5078 * 5079 */ 5080 static int 5081 read_libcfg(int flag, char *group_arg, char *ctag_arg) 5082 { 5083 int rc; 5084 CFGFILE *cfg; 5085 int i; 5086 _sd_dual_pair_t *pairp; 5087 char buf[CFG_MAX_BUF]; 5088 char key[CFG_MAX_KEY]; 5089 int setnumber; 5090 5091 if ((cfg = cfg_open(NULL)) == NULL) 5092 rdc_err(NULL, gettext("unable to access configuration")); 5093 5094 if (!cfg_lock(cfg, CFG_RDLOCK)) 5095 rdc_err(NULL, gettext("unable to lock configuration")); 5096 5097 if (strcmp(ctag_arg, "")) 5098 cfg_resource(cfg, ctag_arg); 5099 else { 5100 cfg_resource(cfg, NULL); 5101 } 5102 5103 setnumber = 0; 5104 /*CSTYLED*/ 5105 for (i = 0; i < rdc_maxsets;) { 5106 setnumber++; 5107 5108 bzero(buf, CFG_MAX_BUF); 5109 (void) snprintf(key, sizeof (key), "sndr.set%d", setnumber); 5110 rc = cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF); 5111 if (rc < 0) 5112 break; 5113 5114 pairp = &pair_list[i]; 5115 if (parse_cfg_buf(buf, pairp, NULL)) 5116 continue; 5117 5118 if (strcmp(group_arg, "") && 5119 strncmp(group_arg, pairp->group, NSC_MAXPATH)) 5120 continue; 5121 5122 if (flag == RDC_CMD_RECONFIG) { 5123 if (reconfig_pbitmap) 5124 (void) strncpy(pairp->fbitmap, reconfig_pbitmap, 5125 NSC_MAXPATH); 5126 if (reconfig_sbitmap) 5127 (void) strncpy(pairp->tbitmap, reconfig_sbitmap, 5128 NSC_MAXPATH); 5129 #ifdef _RDC_CAMPUS 5130 if (reconfig_direct) 5131 (void) strncpy(directfile, reconfig_direct, 5132 NSC_MAXPATH); 5133 #endif 5134 if (reconfig_group) 5135 (void) strncpy(pairp->group, reconfig_group, 5136 NSC_MAXPATH); 5137 5138 if (strlen(reconfig_ctag) > 0) 5139 (void) strncpy(pairp->ctag, reconfig_ctag, 5140 MAX_RDC_HOST_SIZE); 5141 5142 if (reconfig_doasync != -1) 5143 pairp->doasync = reconfig_doasync; 5144 } 5145 5146 5147 if (ctag_check(pairp->fhost, pairp->ffile, 5148 pairp->fbitmap, pairp->thost, pairp->tfile, 5149 pairp->tbitmap, pairp->ctag, pairp->diskqueue) < 0) 5150 continue; /* Ignore illegal sets */ 5151 5152 if (gethost_netaddrs(pairp->fhost, pairp->thost, 5153 (char *)pairp->fnetaddr, 5154 (char *)pairp->tnetaddr) < 0) { 5155 rdc_err(NULL, gettext("unable to determine IP " 5156 "addresses for hosts %s, %s"), pairp->fhost, 5157 pairp->thost); 5158 } 5159 5160 i++; 5161 } 5162 5163 cfg_close(cfg); 5164 return (i); 5165 } 5166 5167 void 5168 q_usage(int prhdr) 5169 { 5170 if (prhdr) 5171 (void) fprintf(stderr, gettext("disk queue usage:\n")); 5172 5173 (void) fprintf(stderr, 5174 gettext("\t%s -g <group> -q a <vol>\t\tadd disk queue to " 5175 "group\n"), program); 5176 (void) fprintf(stderr, 5177 gettext("\t%s -g <group> -q d \t\tremove disk queue from" 5178 " group\n"), program); 5179 (void) fprintf(stderr, 5180 gettext("\t%s -g <group> -q r <newvol>\treplace disk queue for a" 5181 " group\n"), program); 5182 5183 (void) fprintf(stderr, 5184 gettext("\t%s -q a <vol> <shost>:<sdev>\tadd disk queue to " 5185 "a set\n"), program); 5186 (void) fprintf(stderr, 5187 gettext("\t%s -q d <shost>:<sdev>\t\tremove disk queue from " 5188 "a set\n"), program); 5189 (void) fprintf(stderr, 5190 gettext("\t%s -q r <newvol> <shost>:<sdev>\treplace disk queue for " 5191 "a set\n"), program); 5192 5193 } 5194 5195 static void 5196 usage() 5197 { 5198 (void) fprintf(stderr, gettext("usage:\n")); 5199 5200 (void) fprintf(stderr, 5201 gettext("\t%s [opts] -a {on | off} [set]\t" 5202 "set autosync\n"), program); 5203 5204 (void) fprintf(stderr, 5205 gettext("\t%s [opts] -A <asyncthr> [set]\t" 5206 "set the number of asynchronous\n\t\t\t\t\t\tthreads\n"), 5207 program); 5208 5209 (void) fprintf(stderr, 5210 gettext("\t%s [opts] -d [set]\t\t\t" 5211 "disable\n"), program); 5212 5213 (void) fprintf(stderr, 5214 gettext("\t%s [opts] -e [set]\t\t\t" 5215 "enable with bits in bitmap set\n"), program); 5216 5217 (void) fprintf(stderr, 5218 gettext("\t%s [opts] -E [set]\t\t\t" 5219 "enable with bits in bitmap clear\n"), program); 5220 5221 (void) fprintf(stderr, 5222 gettext("\t%s [opts] -F <maxqfbas> [set]\t" 5223 "set maximum fbas to queue\n"), program); 5224 5225 (void) fprintf(stderr, 5226 gettext("\t%s [opts] -D {block | noblock} [set]\t" 5227 "set disk queue blocking mode\n"), program); 5228 5229 (void) fprintf(stderr, 5230 gettext("\t%s [opts] -H [set]\t\t\t" 5231 "report link health\n"), program); 5232 5233 (void) fprintf(stderr, 5234 gettext("\t%s -h\t\t\t\tusage message\n"), program); 5235 5236 (void) fprintf(stderr, 5237 gettext("\t%s -I a <master> <shadow> <bitmap>\t" 5238 "add ndr_ii config entry\n"), program); 5239 5240 (void) fprintf(stderr, 5241 gettext("\t%s -I d <master> <shadow> <bitmap>\t" 5242 "delete ndr_ii config entry\n"), program); 5243 5244 (void) fprintf(stderr, 5245 gettext("\t%s [opts] -i [set]\t\t\t" 5246 "print sets in config file format\n"), program); 5247 5248 (void) fprintf(stderr, 5249 gettext("\t%s [opts] -l [set]\t\t\t" 5250 "enter logging mode\n"), program); 5251 5252 (void) fprintf(stderr, 5253 gettext("\t%s [opts] -m [set]\t\t\t" 5254 "full sync\n"), program); 5255 5256 (void) fprintf(stderr, 5257 gettext("\t%s [opts] -m -r [set]\t\t" 5258 "full reverse sync\n"), program); 5259 5260 (void) fprintf(stderr, 5261 gettext("\t%s [opts] -P [set]\t\t\t" 5262 "print sets verbose\n"), program); 5263 5264 (void) fprintf(stderr, 5265 gettext("\t%s [opts] -p [set]\t\t\t" 5266 "print sets\n"), program); 5267 5268 (void) fprintf(stderr, 5269 gettext("\t%s [opts] -R\t\t\t" 5270 "reset error conditions\n"), program); 5271 5272 (void) fprintf(stderr, 5273 gettext("\t%s [opts] -R b p <bitmap> [set]\t" 5274 "reconfig primary bitmap\n"), program); 5275 5276 (void) fprintf(stderr, 5277 gettext("\t%s [opts] -R b s <bitmap> [set]\t" 5278 "reconfig secondary bitmap\n"), program); 5279 5280 if (clustered) 5281 (void) fprintf(stderr, 5282 gettext("\t%s [opts] -R C <ctag> [set]\t" 5283 "reconfig cluster tag\n"), program); 5284 5285 #ifdef _RDC_CAMPUS 5286 (void) fprintf(stderr, 5287 gettext("\t%s [opts] -R d <pathname> [set]\t" 5288 "reconfig campus direct file\n"), program); 5289 #endif 5290 5291 (void) fprintf(stderr, 5292 gettext("\t%s [opts] -R -f <volset-file> \t" 5293 "reconfig from file\n"), program); 5294 5295 (void) fprintf(stderr, 5296 gettext("\t%s [opts] -R g <group> [set]\t" 5297 "reconfig group\n"), program); 5298 5299 (void) fprintf(stderr, 5300 gettext("\t%s [opts] -R m {sync|async} [set]\t" 5301 "reconfig mode\n"), program); 5302 5303 if (allow_role) 5304 (void) fprintf(stderr, 5305 gettext("\t%s [opts] -R r [set]\t\t" 5306 "reverse roles\n"), program); 5307 5308 (void) fprintf(stderr, 5309 gettext("\t%s [opts] -u [set]\t\t\t" 5310 "update sync\n"), program); 5311 5312 (void) fprintf(stderr, 5313 gettext("\t%s [opts] -u -r [set]\t\t" 5314 "update reverse sync\n"), program); 5315 5316 (void) fprintf(stderr, 5317 gettext("\t%s -v\t\t\t\tdisplay version\n"), program); 5318 5319 (void) fprintf(stderr, 5320 gettext("\t%s [opts] -W <maxwrites> [set]\t" 5321 "set maximum writes to queue\n"), program); 5322 5323 (void) fprintf(stderr, 5324 gettext("\t%s [opts] -w [set]\t\t\t" 5325 "wait\n"), program); 5326 q_usage(0); 5327 5328 (void) fprintf(stderr, gettext("\nopts:\n")); 5329 (void) fprintf(stderr, gettext("\t-n\t\tnon-interactive mode " 5330 "(not valid for print operations)\n")); 5331 (void) fprintf(stderr, gettext( 5332 "\t-g <group>\toperate on sets in group only " 5333 "(not valid for enable\n\t\t\toperations)\n")); 5334 if (clustered) 5335 (void) fprintf(stderr, 5336 gettext("\t-C <ctag>\tignore sets not in cluster ctag " 5337 "(not valid for enable\n\t\t\toperations)\n")); 5338 5339 (void) fprintf(stderr, gettext("\nset:\n")); 5340 if (clustered) 5341 (void) fprintf(stderr, 5342 gettext("\t<phost> <pdev> <pbmp> " 5343 #ifdef _RDC_CAMPUS 5344 "<shost> <sdev> <sbmp> {ip | <directfile>} " 5345 #else 5346 "<shost> <sdev> <sbmp> ip " 5347 #endif 5348 "\\\n\t\t{sync | async} [g <group>] [q <qdev>] " 5349 "[C <ctag>]\n")); 5350 else 5351 (void) fprintf(stderr, 5352 gettext("\t<phost> <pdev> <pbmp> " 5353 #ifdef _RDC_CAMPUS 5354 "<shost> <sdev> <sbmp> {ip | <directfile>} " 5355 #else 5356 "<shost> <sdev> <sbmp> ip " 5357 #endif 5358 "\\\n\t\t{sync | async} [g <group>] [q <qdev>]\n")); 5359 (void) fprintf(stderr, 5360 gettext("\t<shost>:<sdev>\t\t" 5361 "operate on set matching shost and sdev\n")); 5362 (void) fprintf(stderr, 5363 gettext("\t-f volset-file\t\t" 5364 "operate on all sets specified in config file\n" 5365 "\t\t\t\tnote: not valid for single set operations. See\n" 5366 "\t\t\t\t%s(1RDC).\n"), program); 5367 (void) fprintf(stderr, 5368 gettext("\t<no arg>\t\toperate on all configured sets\n")); 5369 } 5370 5371 int 5372 prompt_user(int flag, int options) 5373 { 5374 int c; 5375 5376 switch (flag) { 5377 case RDC_CMD_DISABLE: 5378 (void) printf(gettext("Disable Remote Mirror? (Y/N) [N]: ")); 5379 break; 5380 case RDC_CMD_ENABLE: 5381 (void) printf(gettext("Enable Remote Mirror? (Y/N) [N]: ")); 5382 break; 5383 case RDC_CMD_HEALTH: 5384 (void) printf(gettext("Report Remote Mirror link health? (Y/N)" 5385 "[N]: ")); 5386 break; 5387 case RDC_CMD_COPY: 5388 if (options & RDC_OPT_FULL) { 5389 if (options & RDC_OPT_REVERSE) 5390 (void) printf(gettext("Overwrite primary with" 5391 " secondary? (Y/N) [N]: ")); 5392 else 5393 (void) printf(gettext("Overwrite secondary with" 5394 " primary? (Y/N) [N]: ")); 5395 } else { 5396 if (options & RDC_OPT_REVERSE) 5397 (void) printf(gettext("Refresh primary with" 5398 " secondary? (Y/N) [N]: ")); 5399 else 5400 (void) printf(gettext("Refresh secondary with" 5401 " primary? (Y/N) [N]: ")); 5402 } 5403 break; 5404 case RDC_CMD_RECONFIG: 5405 (void) printf(gettext( 5406 "Perform Remote Mirror reconfiguration? (Y/N) [N]: ")); 5407 break; 5408 case RDC_CMD_RESET: 5409 (void) printf(gettext("Perform Remote Mirror reset? (Y/N) " 5410 "[N]: ")); 5411 break; 5412 case RDC_CMD_TUNABLE: 5413 (void) printf(gettext("Change Remote Mirror tunable? (Y/N) " 5414 "[N]: ")); 5415 break; 5416 case RDC_CMD_LOG: 5417 (void) printf(gettext( 5418 "Put Remote Mirror into logging mode? (Y/N) [N]: ")); 5419 break; 5420 case RDC_CMD_WAIT: 5421 (void) printf(gettext( 5422 "Wait for Remote Mirror sync completion? (Y/N) [N]: ")); 5423 break; 5424 default: 5425 (void) printf(gettext("Perform Remote Mirror operation? (Y/N) " 5426 "[N]: ")); 5427 } 5428 5429 c = getchar(); 5430 if ((c != 'y') && (c != 'Y')) { 5431 (void) printf("\n"); 5432 return (-1); 5433 } 5434 return (0); 5435 } 5436 5437 static void 5438 load_rdc_vols(CFGFILE *cfg) 5439 { 5440 int set; 5441 char key[ CFG_MAX_KEY ]; 5442 char buf[ CFG_MAX_BUF ]; 5443 _sd_dual_pair_t pair; 5444 char *vol, *bmp; 5445 char *host1 = pair.fhost, *host2 = pair.thost; 5446 char *diskqueue = pair.diskqueue; 5447 volcount_t *volcount; 5448 char lghn[ MAX_RDC_HOST_SIZE ]; 5449 5450 if (volhash) { 5451 return; 5452 } 5453 5454 cfg_rewind(cfg, CFG_SEC_CONF); 5455 volhash = nsc_create_hash(); 5456 for (set = 1; /*CSTYLED*/; set++) { 5457 (void) snprintf(key, CFG_MAX_KEY, "sndr.set%d", set); 5458 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF)) { 5459 break; 5460 } 5461 5462 if (parse_cfg_buf(buf, &pair, lghn)) 5463 continue; 5464 vol = pair.ffile; 5465 bmp = pair.fbitmap; 5466 5467 /* use lghn if possible */ 5468 if (*lghn) { 5469 if (strcmp(host2, lghn) == 0) { 5470 vol = pair.tfile; 5471 bmp = pair.tbitmap; 5472 } 5473 } else if (!self_check(host1)) { 5474 /* next one had better be ours */ 5475 vol = pair.tfile; 5476 bmp = pair.tbitmap; 5477 5478 if (!self_check(host2)) { 5479 rdc_warn(NULL, 5480 gettext("config error: neither %s nor %s" 5481 " is localhost"), host1, host2); 5482 continue; 5483 } 5484 } 5485 5486 /* primary vol may be used more than once */ 5487 volcount = (volcount_t *)nsc_lookup(volhash, vol); 5488 if (volcount) { 5489 volcount->count++; 5490 } else { 5491 volcount = (volcount_t *)malloc(sizeof (volcount_t)); 5492 volcount->count = 1; 5493 (void) nsc_insert_node(volhash, volcount, vol); 5494 } 5495 5496 /* bitmap ought to be only used once */ 5497 volcount = (volcount_t *)nsc_lookup(volhash, bmp); 5498 if (volcount) { 5499 /* argh */ 5500 volcount->count++; 5501 } else { 5502 volcount = (volcount_t *)malloc(sizeof (volcount_t)); 5503 volcount->count = 1; 5504 (void) nsc_insert_node(volhash, volcount, bmp); 5505 } 5506 5507 if (strcmp(diskqueue, place_holder) == 0) 5508 continue; 5509 /* diskqueue vol may be used more than once */ 5510 volcount = (volcount_t *)nsc_lookup(volhash, diskqueue); 5511 if (volcount) { 5512 volcount->count++; 5513 } else { 5514 volcount = (volcount_t *)malloc(sizeof (volcount_t)); 5515 volcount->count = 1; 5516 (void) nsc_insert_node(volhash, volcount, diskqueue); 5517 } 5518 } 5519 } 5520 5521 static void 5522 unload_rdc_vols() 5523 { 5524 nsc_remove_all(volhash, free); 5525 volhash = 0; 5526 } 5527 5528 static int 5529 perform_autosv() 5530 { 5531 if (!clustered) { 5532 return (1); 5533 } else { 5534 return (cfg_issuncluster()); 5535 } 5536 } 5537 5538 /* 5539 * Check the user supplied fields against those in the dscfg for 5540 * this set. 5541 * Never returns on an error. 5542 */ 5543 static void 5544 checkgfields(CFGFILE *cfg, int setnumber, char *fromhost, char *fromfile, 5545 char *frombitmap, char *tobitmap, char *type, char *mode, char *group, 5546 char *ctag, char *diskq) 5547 { 5548 if (fromhost[0]) 5549 checkgfield(cfg, setnumber, "phost", 5550 gettext("primary host"), fromhost); 5551 if (fromfile[0]) 5552 checkgfield(cfg, setnumber, "primary", 5553 gettext("primary volume"), fromfile); 5554 if (frombitmap[0]) 5555 checkgfield(cfg, setnumber, "pbitmap", 5556 gettext("primary bitmap"), frombitmap); 5557 if (tobitmap[0]) 5558 checkgfield(cfg, setnumber, "sbitmap", 5559 gettext("secondary bitmap"), tobitmap); 5560 if (type[0]) 5561 checkgfield(cfg, setnumber, "type", 5562 gettext("type of connection"), type); 5563 if (mode[0]) 5564 checkgfield(cfg, setnumber, "mode", 5565 gettext("mode of connection"), mode); 5566 if (group[0]) 5567 checkgfield(cfg, setnumber, "group", 5568 gettext("group"), group); 5569 if (ctag[0]) 5570 checkgfield(cfg, setnumber, "cnode", 5571 gettext("cluster tag"), ctag); 5572 if (diskq[0]) 5573 checkgfield(cfg, setnumber, "diskq", 5574 gettext("disk queue volume"), diskq); 5575 } 5576 5577 /* 5578 * Check the 'fname' field in the dscfg file for set number 'setnumber' 5579 * If it does not match the user's data, 'data', then print the error 5580 * message using the friendly field name 'ufield'. 5581 * Never returns on an error. 5582 */ 5583 static void 5584 checkgfield(CFGFILE *cfg, int setnumber, char *fname, char *ufield, char *data) 5585 { 5586 char buf[CFG_MAX_BUF]; 5587 char key[CFG_MAX_KEY]; 5588 5589 (void) snprintf(key, sizeof (key), "sndr.set%d.%s", setnumber, fname); 5590 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { 5591 rdc_err(NULL, gettext("unable to fetch data for key %s"), 5592 key); 5593 } 5594 if (strcmp(buf, data) != 0) { 5595 rdc_err(NULL, 5596 gettext("the value specified for the %s field is not\nthe " 5597 "same as that contained within the configuration storage " 5598 "file for this set.\nYou specified \"%s\" " 5599 "expected \"%s\"."), 5600 ufield, data, buf); 5601 } 5602 } 5603 5604 /* 5605 * load and send the contents of the bitmap file to the kernel. 5606 */ 5607 static int 5608 rdc_bitmapset(char *tohost, char *tofile, char *bitmap, int op, 5609 nsc_off_t offset) 5610 { 5611 rdc_bitmap_op_t bmop; 5612 int fd; 5613 void *buffer; 5614 int buffersz; 5615 struct stat s; 5616 int n; 5617 int ret; 5618 /* 5619 * open bitmap file for reading. 5620 */ 5621 if ((fd = open(bitmap, O_RDONLY)) < 0) { 5622 rdc_warn(NULL, gettext("Unable to open bitmap file %s"), 5623 bitmap); 5624 return (1); 5625 } 5626 (void) fstat(fd, &s); 5627 5628 if (S_ISREG(s.st_mode) == 0) { 5629 rdc_warn(NULL, gettext("Bitmap %s is not a regular file"), 5630 bitmap); 5631 (void) close(fd); 5632 return (1); 5633 } 5634 5635 if (op == 0) { 5636 op = RDC_BITMAPOR; 5637 } 5638 /* 5639 * use the file size to allocate buffer. This 5640 * size should be a multiple of FBA, but don't check 5641 * it here. 5642 */ 5643 buffersz = s.st_size; 5644 buffer = malloc(buffersz); 5645 if (buffer == NULL) { 5646 rdc_warn(NULL, gettext("Unable to allocate %d bytes " 5647 "for bitmap file %s"), buffersz, bitmap); 5648 (void) close(fd); 5649 return (1); 5650 } 5651 n = read(fd, buffer, buffersz); 5652 (void) close(fd); 5653 if (n != buffersz) { 5654 rdc_warn(NULL, gettext("Unable to read the bitmap file, " 5655 "read returned %d instead of %d"), 5656 n, buffersz); 5657 free(buffer); 5658 return (1); 5659 } 5660 bmop.offset = offset; 5661 bmop.op = op; 5662 (void) strncpy(bmop.sechost, tohost, MAX_RDC_HOST_SIZE); 5663 (void) strncpy(bmop.secfile, tofile, NSC_MAXPATH); 5664 bmop.len = buffersz; 5665 bmop.addr = (unsigned long)buffer; 5666 ret = rdc_ioctl_simple(RDC_BITMAPOP, &bmop); 5667 free(buffer); 5668 if (ret < 0) { 5669 rdc_warn(NULL, gettext("Setting bitmap ioctl failed for set " 5670 "%s:%s"), tohost, tofile); 5671 5672 switch (errno) { 5673 case EIO: 5674 rdc_warn(NULL, gettext("One of the sets is not " 5675 "enabled")); 5676 break; 5677 case ENXIO: 5678 rdc_warn(NULL, gettext("One of the sets is not " 5679 "logging")); 5680 break; 5681 default: 5682 break; 5683 } 5684 } else { 5685 ret = 0; 5686 } 5687 if (ret) 5688 ret = 1; 5689 return (ret); 5690 } 5691 5692 /* 5693 * verify_groupname: Check the group name for the following rules: 5694 * 1. The name does not start with a '-' 5695 * 2. The name does not contain any space characters as defined by 5696 * isspace(3C). 5697 * 5698 * If either of these rules are broken, error immediately. 5699 */ 5700 static void 5701 verify_groupname(char *grp) 5702 { 5703 int i; 5704 5705 if (grp[0] == '-') { 5706 rdc_err(NULL, gettext("group name cannot start with a '-'")); 5707 } 5708 5709 for (i = 0; grp[i] != '\0'; i++) { 5710 if (isspace(grp[i])) { 5711 rdc_err(NULL, gettext("group name cannot contain a " 5712 "space")); 5713 } 5714 } 5715 }