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