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