1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/time.h> 28 #include <errno.h> 29 #include <signal.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <fcntl.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <values.h> 36 #include <locale.h> 37 #include <langinfo.h> 38 #include <sys/mman.h> 39 #include <sys/stat.h> 40 #include <sys/wait.h> 41 #include <strings.h> 42 #include <stdarg.h> 43 #include <ctype.h> 44 #include <math.h> 45 #include <sys/param.h> 46 #include <sys/mnttab.h> 47 #include <nsctl.h> 48 #include <netdb.h> 49 #include <search.h> 50 51 #include <sys/nsctl/cfg.h> 52 #include <sys/nsctl/nsc_hash.h> 53 54 #include <sys/unistat/spcs_s.h> 55 #include <sys/unistat/spcs_s_u.h> 56 #include <sys/unistat/spcs_errors.h> 57 #include <sys/nsctl/dsw.h> 58 #include <sys/nsctl/dsw_dev.h> /* for bit map header format */ 59 60 #include <sys/nskernd.h> 61 62 typedef struct mstcount_s { 63 int count; 64 } mstcount_t; 65 typedef struct shdvol_s { 66 char master[ DSW_NAMELEN ]; 67 } shdvol_t; 68 typedef struct grptag_s { 69 char ctag[ DSW_NAMELEN ]; 70 } grptag_t; 71 hash_node_t **volhash = NULL; 72 73 #define DSW_TEXT_DOMAIN "II" 74 75 #include <dlfcn.h> 76 #define RDC_LIB "/usr/lib/librdc.so.1" 77 static int (*self_check)(char *); 78 79 /* 80 * Support for the special cluster tag "local" to be used with -C in a 81 * cluster for local volumes. 82 */ 83 #define II_LOCAL_TAG "local" 84 85 #define II_NOT_CLUSTER 1 86 #define II_CLUSTER 2 87 #define II_CLUSTER_LCL 3 88 89 static char *cfg_cluster_tag = NULL; 90 static CFGFILE *cfg = NULL; 91 92 void sigterm(int sig); 93 94 #define SD_BIT_CLR(bmap, bit) (bmap &= ~(1 << bit)) 95 #define SD_BIT_ISSET(bmap, bit) ((bmap & (1 << bit)) != 0) 96 97 #define MAX_LINE_SIZE 256 /* maximum characters per line in config file */ 98 #define MAX_GROUPS 1024 /* maximum number of groups to support */ 99 #define MAX_CLUSTERS 1024 /* maximum number of resource groups */ 100 101 unsigned long bm_size; /* size in bytes of bitmap */ 102 unsigned long bm_actual; /* original number of bits in bitmap */ 103 int debug = 0; 104 105 int dsw_fd; 106 107 #define LD_II 0x00000001 108 #define LD_DSVOLS 0x00000002 109 #define LD_SVOLS 0x00000004 110 #define LD_SHADOWS 0x00000008 111 112 static int reload_vols = 0; 113 static int config_locked = 0; 114 static int last_lock; 115 116 /* 117 * names for do_copy() flags. 118 */ 119 120 enum copy_update {Copy = 0, Update}; 121 enum copy_direction {ToShadow = 0, ToMaster}; 122 enum copy_wait {WaitForStart = 0, WaitForEnd}; 123 124 char *cmdnam; 125 126 unsigned char *allocate_bitmap(char *); 127 void usage(char *); 128 void enable(char *, char *, char *, char *); 129 int disable(char *); 130 void bitmap_op(char *, int, int, int, int); 131 void print_status(dsw_config_t *, int); 132 int abort_copy(char *); 133 int reset(char *); 134 int overflow(char *); 135 void iiversion(void); 136 int wait_for_copy(char *); 137 int export(char *); 138 void list_volumes(void); 139 void dsw_error(char *, spcs_s_info_t *); 140 void InitEnv(); 141 static void check_dg_is_local(char *dgname); 142 static int check_resource_group(char *volume); 143 static int check_diskgroup(char *path, char *result); 144 static int check_cluster(); 145 static void unload_ii_vols(); 146 static void load_ii_vols(CFGFILE *); 147 static int perform_autosv(); 148 static int is_exported(char *); 149 static void conform_name(char **); 150 static void do_attach(dsw_config_t *); 151 static int ii_lock(CFGFILE *, int); 152 static void verify_groupname(char *grp, int testDash); 153 154 void dsw_list_clusters(char *); 155 void dsw_enable(int, char **); 156 void dsw_disable(int, char **); 157 void dsw_copy_to_shadow(int, char **); 158 void dsw_update_shadow(int, char **); 159 void dsw_copy_to_master(int, char **); 160 void dsw_update_master(int, char **); 161 void dsw_abort_copy(int, char **); 162 void dsw_display_status(int, char **); 163 void dsw_display_bitmap(int, char **); 164 void dsw_reset(int, char **); 165 void dsw_overflow(int, char **); 166 void dsw_version(int, char **); 167 void dsw_wait(int, char **); 168 void dsw_list_volumes(int, char **); 169 void dsw_list_group_volumes(); 170 void dsw_export(int, char **); 171 void dsw_import(int, char **); 172 void dsw_join(int, char **); 173 void dsw_attach(int, char **); 174 void dsw_detach(int, char **); 175 void dsw_params(int, char **); 176 void dsw_olist(int, char **); 177 void dsw_ostat(int, char **); 178 void dsw_move_2_group(int, char **); 179 void dsw_list_groups(); 180 void check_iishadow(char *); 181 182 extern char *optarg; 183 extern int optind, opterr, optopt; 184 185 int Aflg; 186 int Cflg; 187 int CLflg; 188 int Dflg; 189 int Eflg; 190 int Iflg; 191 int Jflg; 192 int Lflg; 193 int Oflg; 194 int Pflg; 195 int Qflg; 196 int Rflg; 197 int aflg; 198 int bflg; 199 int cflg; 200 int dflg; 201 int eflg; 202 int fflg; 203 int gflg; 204 int gLflg; 205 int hflg; 206 int iflg; 207 int lflg; 208 int mflg; 209 int nflg; 210 int pflg; 211 int uflg; 212 int vflg; 213 int wflg; 214 215 int errflg; 216 #ifdef DEBUG 217 const char single_opts[] = 218 "a:b:c:d:e:f:g:hilmnpu:vw:A:C:D:E:I:J:LO:PQ:R:"; 219 #else 220 /* no b or f flags */ 221 const char single_opts[] = "a:c:d:e:g:hilmnpu:vw:A:C:D:E:I:J:LO:PQ:R:"; 222 #endif 223 const char group_opts[] = "ac:de:ilmnpu:wA:C:DELPR"; 224 const char *opt_list = single_opts; 225 226 char buf[CFG_MAX_BUF]; 227 char key[CFG_MAX_KEY]; 228 char last_overflow[DSW_NAMELEN]; 229 int setnumber; 230 char *group_name; 231 char **group_volumes; 232 enum copy_direction direction; 233 char *param_delay, *param_unit; 234 char *overflow_file; 235 236 #ifdef lint 237 int 238 iiadm_lintmain(int argc, char *argv[]) 239 #else 240 int 241 main(int argc, char *argv[]) 242 #endif 243 { 244 int c; 245 int actions = 0; 246 int ac; 247 char *av[1024]; 248 249 InitEnv(); 250 251 (void) memset(av, 0, sizeof (av)); 252 cmdnam = argv[0]; 253 while ((c = getopt(argc, argv, opt_list)) != EOF) 254 switch (c) { 255 case 'c': 256 cflg++; 257 actions++; 258 if (strcmp(optarg, "m") == 0) { 259 av[0] = "copy_to_master"; 260 direction = ToMaster; 261 } else if (strcmp(optarg, "s") == 0) { 262 av[0] = "copy_to_shadow"; 263 direction = ToShadow; 264 } else { 265 errflg ++; 266 usage(gettext( 267 "must specify m or s with -c")); 268 } 269 ac = 2; 270 break; 271 case 'd': 272 dflg++; 273 actions++; 274 av[0] = "disable"; 275 av[1] = optarg; 276 ac = 2; 277 break; 278 case 'e': 279 eflg++; 280 actions++; 281 av[0] = "enable"; 282 if (strcmp(optarg, "ind") == 0) 283 av[4] = "independent"; 284 else if (strcmp(optarg, "dep") == 0) 285 av[4] = "dependent"; 286 else { 287 errflg ++; 288 usage(gettext( 289 "must specify ind or dep with -e")); 290 } 291 ac = 1; 292 break; 293 case 'g': 294 gflg++; 295 opt_list = group_opts; 296 group_name = optarg; 297 if (group_name && *group_name == '-') { 298 gLflg = (strcmp("-L", group_name) == 0); 299 if (gLflg) 300 actions++; 301 } 302 verify_groupname(group_name, !gLflg); 303 break; 304 case 'h': 305 hflg++; 306 actions++; 307 break; 308 case 'u': 309 uflg++; 310 actions++; 311 if (strcmp(optarg, "m") == 0) { 312 av[0] = "update_master"; 313 direction = ToMaster; 314 } else if (strcmp(optarg, "s") == 0) { 315 av[0] = "update_shadow"; 316 direction = ToShadow; 317 } else { 318 errflg ++; 319 usage(gettext( 320 "must specify m or s with -u")); 321 } 322 ac = 2; 323 break; 324 case 'i': 325 iflg++; 326 actions++; 327 av[0] = "display_status"; 328 break; 329 case 'l': 330 lflg++; 331 actions++; 332 av[0] = "list_config"; 333 ac = 1; 334 break; 335 case 'm': 336 mflg++; 337 actions++; 338 av[0] = "move_to_group"; 339 ac = 1; 340 break; 341 case 'n': 342 nflg++; 343 break; 344 case 'p': 345 pflg++; 346 break; 347 case 'b': 348 bflg++; 349 actions++; 350 av[0] = "display_bitmap"; 351 av[1] = optarg; 352 ac = 2; 353 break; 354 case 'a': 355 aflg++; 356 actions++; 357 av[0] = "abort_copy"; 358 av[1] = optarg; 359 ac = 2; 360 break; 361 case 'v': 362 vflg++; 363 actions++; 364 av[1] = "version"; 365 ac = 1; 366 break; 367 case 'w': 368 wflg++; 369 actions++; 370 av[0] = "wait"; 371 av[1] = optarg; 372 ac = 2; 373 break; 374 case 'A': 375 Aflg++; 376 actions++; 377 av[0] = "attach"; 378 av[1] = optarg; 379 ac = 2; 380 break; 381 case 'C': 382 Cflg++; 383 cfg_cluster_tag = optarg; 384 if (cfg_cluster_tag && *cfg_cluster_tag == '-') { 385 CLflg = (strcmp("-L", cfg_cluster_tag) == 0); 386 if (CLflg) 387 actions++; 388 } 389 break; 390 case 'D': 391 Dflg++; 392 actions++; 393 av[0] = "detach"; 394 av[1] = optarg; 395 ac = 2; 396 break; 397 case 'O': 398 Oflg++; 399 actions++; 400 av[0] = "overflow"; 401 av[1] = optarg; 402 ac = 2; 403 break; 404 case 'R': 405 Rflg++; 406 actions++; 407 av[0] = "reset"; 408 av[1] = optarg; 409 ac = 2; 410 break; 411 case 'E': 412 Eflg++; 413 actions++; 414 av[0] = "export"; 415 av[1] = optarg; 416 ac = 2; 417 break; 418 case 'I': 419 Iflg++; 420 actions++; 421 av[0] = "import"; 422 av[1] = optarg; 423 ac = 2; 424 break; 425 case 'J': 426 Jflg++; 427 actions++; 428 av[0] = "join"; 429 av[1] = optarg; 430 ac = 2; 431 break; 432 case 'P': 433 Pflg++; 434 actions++; 435 av[0] = "parameter"; 436 ac = 1; 437 break; 438 case 'L': 439 Lflg++; 440 actions++; 441 /* If -g group -L, force error */ 442 if (group_name) actions++; 443 av[0] = "LIST"; 444 ac = 1; 445 break; 446 case 'Q': 447 Qflg++; 448 actions++; 449 av[0] = "query"; 450 av[1] = optarg; 451 ac = 2; 452 break; 453 case '?': 454 errflg++; 455 break; 456 } 457 if (hflg) { 458 usage(NULL); 459 exit(0); 460 } 461 462 if (errflg) 463 usage(gettext("unrecognized argument")); 464 switch (actions) { 465 case 0: 466 if (argc > 1) 467 usage(gettext("must specify an action flag")); 468 469 /* default behavior is to list configuration */ 470 lflg++; av[0] = "list_config"; ac = 1; 471 break; 472 case 1: 473 break; 474 default: 475 usage(gettext("too many action flags")); 476 break; 477 } 478 479 if (gflg && (Iflg || Jflg || Oflg || Qflg)) 480 usage(gettext("can't use a group with this option")); 481 if (!gflg && (mflg)) 482 usage(gettext("must use a group with this option")); 483 484 /* 485 * Open configuration file. 486 */ 487 if ((cfg = cfg_open(NULL)) == NULL) { 488 perror("unable to access configuration"); 489 exit(2); 490 } 491 492 /* 493 * Set write locking (CFG_WRLOCK) for: 494 * iiadm -e (enable) 495 * iiadm -d (disable) 496 * iiadm -A (attach overflow) 497 * iiadm -D (detach overflow) 498 * iiadm -g grp -m volume (move volume into group) 499 * iiadm -E (export shadow [needs to update dsvol section]) 500 * iiadm -I (import shadow [ditto]) 501 * iiadm -J (join shadow [ditto]) 502 * read locking (CFG_RDLOCK) for all other commands 503 */ 504 last_lock = (eflg || dflg || mflg || Aflg || Dflg || Eflg || Iflg || 505 Jflg)? CFG_WRLOCK : CFG_RDLOCK; 506 if (!cfg_lock(cfg, last_lock)) { 507 perror("unable to lock configuration"); 508 exit(2); 509 } 510 config_locked = 1; 511 512 /* 513 * If we are in a cluster, set or derive a valid disk group 514 */ 515 switch (check_cluster()) { 516 case II_CLUSTER: 517 /* 518 * If in a Sun Cluster, can't Import an II shadow 519 * Must be done as -C local 520 */ 521 if (Iflg) 522 dsw_error(gettext( 523 "-I (import) only allowed as -C local"), NULL); 524 /*FALLTHRU*/ 525 case II_CLUSTER_LCL: 526 /* 527 * If a cluster tag was specified or derived, set it 528 */ 529 if (CLflg) { 530 dsw_list_clusters(argv[optind]); 531 cfg_close(cfg); 532 exit(0); 533 } else { 534 cfg_resource(cfg, cfg_cluster_tag); 535 } 536 break; 537 case II_NOT_CLUSTER: 538 if (cfg_cluster_tag != NULL) 539 dsw_error(gettext( 540 "-C is valid only in a Sun Cluster"), NULL); 541 break; 542 default: 543 dsw_error(gettext( 544 "Unexpected return from check_cluster()"), NULL); 545 } 546 547 /* preload the ii config */ 548 load_ii_vols(cfg); 549 reload_vols |= LD_II; 550 551 if (eflg) { 552 if (argc - optind != 3) 553 usage(gettext("must specify 3 volumes with -e")); 554 av[1] = argv[optind++]; 555 av[2] = argv[optind++]; 556 av[3] = argv[optind++]; 557 ac = 5; 558 dsw_enable(ac, av); 559 } else if (dflg) { 560 dsw_disable(ac, av); 561 } else if (uflg) { 562 if (argv[optind] == NULL && group_name == NULL) 563 usage(gettext("must specify volume with -u")); 564 for (c = 1; argv[optind] != NULL; optind++) 565 av[c++] = argv[optind]; 566 av[c] = NULL; 567 568 if (direction == ToMaster) 569 dsw_update_master(ac, av); 570 else 571 dsw_update_shadow(ac, av); 572 } else if (iflg) { 573 if (argv[optind]) { 574 av[1] = argv[optind]; 575 ac = 2; 576 } else 577 ac = 1; 578 dsw_display_status(ac, av); 579 } else if (bflg) { 580 dsw_display_bitmap(ac, av); 581 } else if (cflg) { 582 if (argv[optind] == NULL && group_name == NULL) 583 usage(gettext("must specify volume with -c")); 584 for (c = 1; argv[optind] != NULL; optind++) 585 av[c++] = argv[optind]; 586 av[c] = NULL; 587 588 if (direction == ToMaster) 589 dsw_copy_to_master(ac, av); 590 else 591 dsw_copy_to_shadow(ac, av); 592 } else if (aflg) { 593 dsw_abort_copy(ac, av); 594 } else if (Eflg) { 595 dsw_export(ac, av); 596 } else if (Iflg) { 597 if (argc - optind != 1) 598 usage(gettext("must specify 2 volumes with -I")); 599 av[2] = argv[optind++]; 600 ac = 3; 601 dsw_import(ac, av); 602 } else if (Aflg) { 603 if (group_name) { 604 if (argc - optind != 0) 605 usage(gettext("must specify overflow volume " \ 606 "when using groups with -A")); 607 ac = 2; 608 } else { 609 if (argc - optind != 1) 610 usage(gettext("specify 2 volumes with -A")); 611 ac = 3; 612 av[2] = argv[optind++]; 613 } 614 dsw_attach(ac, av); 615 } else if (Dflg) { 616 dsw_detach(ac, av); 617 } else if (Jflg) { 618 if (argc - optind != 1) 619 usage(gettext("must specify 2 volumes with -J")); 620 av[2] = argv[optind++]; 621 ac = 3; 622 dsw_join(ac, av); 623 } else if (Pflg) { 624 if (argc - optind == ((group_name) ? 0 : 1)) { 625 av[1] = argv[optind++]; 626 ac = (group_name) ? 0 : 2; 627 } else if (argc - optind == ((group_name) ? 2 : 3)) { 628 av[1] = argv[optind++]; 629 av[2] = argv[optind++]; 630 av[3] = argv[optind++]; 631 ac = (group_name) ? 2 : 4; 632 } else 633 usage(gettext( 634 "must specify delay, unit and shadow with -P")); 635 dsw_params(ac, av); 636 } else if (Oflg) { 637 dsw_overflow(ac, av); 638 } else if (Rflg) { 639 dsw_reset(ac, av); 640 } else if (vflg) { 641 dsw_version(ac, av); 642 } else if (wflg) { 643 dsw_wait(ac, av); 644 } else if (lflg) { 645 if ((gflg) && (!group_name)) 646 dsw_list_group_volumes(); 647 else 648 dsw_list_volumes(ac, av); 649 } else if (Lflg) { 650 dsw_olist(ac, av); 651 } else if (gLflg) { 652 dsw_list_groups(); 653 } else if (Qflg) { 654 dsw_ostat(ac, av); 655 } else if (mflg) { 656 if (argc - optind < 1) 657 usage(gettext("must specify one or more volumes")); 658 for (c = 1; argv[optind] != NULL; optind++) 659 av[c++] = argv[optind]; 660 av[c] = NULL; 661 dsw_move_2_group(ac, av); 662 } 663 if (cfg) 664 cfg_close(cfg); 665 666 exit(0); 667 return (0); 668 } 669 670 static int 671 ii_lock(CFGFILE *cfg, int locktype) 672 { 673 last_lock = locktype; 674 return (cfg_lock(cfg, locktype)); 675 } 676 677 static int 678 do_ioctl(int fd, int cmd, void *arg) 679 { 680 int unlocked = 0; 681 int rc; 682 int save_errno; 683 684 if (config_locked) { 685 switch (cmd) { 686 case DSWIOC_ENABLE: 687 case DSWIOC_RESUME: 688 case DSWIOC_SUSPEND: 689 case DSWIOC_COPY: 690 case DSWIOC_BITMAP: 691 case DSWIOC_DISABLE: 692 case DSWIOC_SHUTDOWN: 693 case DSWIOC_ABORT: 694 case DSWIOC_RESET: 695 case DSWIOC_OFFLINE: 696 case DSWIOC_WAIT: 697 case DSWIOC_ACOPY: 698 case DSWIOC_EXPORT: 699 case DSWIOC_IMPORT: 700 case DSWIOC_JOIN: 701 case DSWIOC_COPYP: 702 case DSWIOC_OATTACH: 703 case DSWIOC_ODETACH: 704 case DSWIOC_SBITSSET: 705 case DSWIOC_CBITSSET: 706 case DSWIOC_SEGMENT: 707 case DSWIOC_MOVEGRP: 708 case DSWIOC_CHANGETAG: 709 cfg_unlock(cfg); 710 unlocked = 1; 711 break; 712 713 case DSWIOC_STAT: 714 case DSWIOC_VERSION: 715 case DSWIOC_LIST: 716 case DSWIOC_OCREAT: 717 case DSWIOC_OLIST: 718 case DSWIOC_OSTAT: 719 case DSWIOC_OSTAT2: 720 case DSWIOC_LISTLEN: 721 case DSWIOC_OLISTLEN: 722 case DSWIOC_CLIST: 723 case DSWIOC_GLIST: 724 break; 725 726 default: 727 (void) fprintf(stderr, 728 "cfg locking needs to be set for %08x\n", cmd); 729 exit(1); 730 break; 731 } 732 } 733 if (unlocked) { 734 /* unload vol hashes */ 735 if (reload_vols & LD_II) 736 unload_ii_vols(); 737 if (reload_vols & LD_SHADOWS) 738 cfg_unload_shadows(); 739 if (reload_vols & LD_DSVOLS) 740 cfg_unload_dsvols(); 741 if (reload_vols & LD_SVOLS) 742 cfg_unload_svols(); 743 } 744 rc = ioctl(fd, cmd, arg); 745 save_errno = errno; 746 if (config_locked && unlocked) { 747 (void) cfg_lock(cfg, last_lock); 748 } 749 if (unlocked) { 750 /* reload vol hashes */ 751 if (reload_vols & LD_SVOLS) 752 (void) cfg_load_svols(cfg); 753 if (reload_vols & LD_DSVOLS) 754 (void) cfg_load_dsvols(cfg); 755 if (reload_vols & LD_SHADOWS) 756 (void) cfg_load_shadows(cfg); 757 if (reload_vols & LD_II) 758 load_ii_vols(cfg); 759 } 760 761 errno = save_errno; 762 return (rc); 763 } 764 765 static int 766 get_dsw_config(int setno, dsw_config_t *parms) 767 { 768 char buf[CFG_MAX_BUF]; 769 char key[CFG_MAX_KEY]; 770 771 bzero(parms, sizeof (dsw_config_t)); 772 (void) snprintf(key, sizeof (key), "ii.set%d.master", setno); 773 if (cfg_get_cstring(cfg, key, parms->master_vol, DSW_NAMELEN) < 0) 774 return (-1); 775 776 (void) snprintf(key, sizeof (key), "ii.set%d.shadow", setno); 777 (void) cfg_get_cstring(cfg, key, parms->shadow_vol, DSW_NAMELEN); 778 779 (void) snprintf(key, sizeof (key), "ii.set%d.bitmap", setno); 780 (void) cfg_get_cstring(cfg, key, parms->bitmap_vol, DSW_NAMELEN); 781 782 (void) snprintf(key, sizeof (key), "ii.set%d.mode", setno); 783 (void) cfg_get_cstring(cfg, key, buf, sizeof (buf)); 784 if (strcmp(buf, "I") == 0) 785 parms->flag |= DSW_GOLDEN; 786 787 (void) snprintf(key, sizeof (key), "ii.set%d.overflow", setno); 788 (void) cfg_get_cstring(cfg, key, last_overflow, DSW_NAMELEN); 789 790 (void) snprintf(key, sizeof (key), "ii.set%d.group", setno); 791 (void) cfg_get_cstring(cfg, key, parms->group_name, DSW_NAMELEN); 792 793 (void) snprintf(key, sizeof (key), "ii.set%d.cnode", setno); 794 (void) cfg_get_cstring(cfg, key, parms->cluster_tag, DSW_NAMELEN); 795 return (0); 796 } 797 798 static int 799 find_next_cf_line(char *volume, int next) 800 { 801 dsw_config_t cf_line; 802 803 for (setnumber = next; get_dsw_config(setnumber, &cf_line) == 0; 804 setnumber++) { 805 if (strncmp(volume, cf_line.master_vol, DSW_NAMELEN) == 0 || 806 strncmp(volume, cf_line.shadow_vol, DSW_NAMELEN) == 0 || 807 strncmp(volume, cf_line.bitmap_vol, DSW_NAMELEN) == 0) 808 return (1); 809 } 810 return (0); 811 } 812 int 813 find_any_cf_line(char *volume) 814 { 815 return (find_next_cf_line(volume, 1)); 816 } 817 818 static int 819 find_next_shadow_line(char *volume, int next) 820 { 821 dsw_config_t cf_line; 822 823 for (setnumber = next; get_dsw_config(setnumber, &cf_line) == 0; 824 setnumber++) { 825 if (strncmp(volume, cf_line.shadow_vol, DSW_NAMELEN) == 0) 826 return (1); 827 } 828 return (0); 829 } 830 int 831 find_shadow_line(char *volume) 832 { 833 return (find_next_shadow_line(volume, 1)); 834 } 835 836 /* 837 * this function is designed to be called once, subsequent calls won't 838 * free memory allocated by earlier invocations. 839 */ 840 char * 841 get_overflow_list() 842 { 843 dsw_aioctl_t *acopy_args; 844 int rc, num; 845 846 num = do_ioctl(dsw_fd, DSWIOC_OLISTLEN, NULL); 847 if (num < 0) 848 dsw_error(gettext("Can't get overflow list length"), NULL); 849 850 acopy_args = malloc(sizeof (dsw_aioctl_t) + num * DSW_NAMELEN); 851 if (acopy_args == NULL) 852 dsw_error(gettext("Can't get memory for list enquiry"), NULL); 853 854 acopy_args->count = num; 855 acopy_args->flags = 0; 856 acopy_args->status = spcs_s_ucreate(); 857 858 rc = do_ioctl(dsw_fd, DSWIOC_OLIST, acopy_args); 859 if (rc == -1) 860 dsw_error(gettext("Overflow list access failure"), 861 &acopy_args->status); 862 else 863 acopy_args->shadow_vol[DSW_NAMELEN*acopy_args->count] = NULL; 864 865 return (acopy_args->shadow_vol); 866 } 867 868 /* 869 * this function is designed to be called once, subsequent calls won't 870 * free memory allocated by earlier invocations. 871 */ 872 873 int 874 find_group_members(char *group) 875 { 876 int nmembers = 0; 877 int vector_len = 0; 878 879 group_volumes = NULL; 880 for (setnumber = 1; /*CSTYLED*/; setnumber++) { 881 (void) snprintf(key, sizeof (key), "ii.set%d.group", setnumber); 882 if (cfg_get_cstring(cfg, key, buf, 883 sizeof (buf)) < 0) 884 break; 885 886 if (strcmp(group, buf)) 887 continue; 888 889 (void) snprintf(key, sizeof (key), "ii.set%d.shadow", 890 setnumber); 891 if (cfg_get_cstring(cfg, key, buf, 892 sizeof (buf)) < 0) 893 break; 894 895 if (nmembers >= vector_len) { 896 vector_len += 10; 897 group_volumes = realloc(group_volumes, (1+vector_len) * 898 sizeof (char *)); 899 } 900 group_volumes[nmembers] = strdup(buf); 901 nmembers++; 902 } 903 if (group_volumes) 904 group_volumes[nmembers] = NULL; /* terminate list */ 905 return (nmembers); 906 } 907 908 static int 909 find_next_matching_cf_line( 910 char *volume, dsw_config_t *conf, dsw_ioctl_t *io, int next) 911 { 912 dsw_config_t config; 913 914 if (!find_next_cf_line(volume, next)) { 915 return (0); 916 } 917 918 if (conf == NULL) 919 conf = &config; 920 (void) get_dsw_config(setnumber, conf); 921 if (io) { 922 (void) strncpy(io->shadow_vol, conf->shadow_vol, DSW_NAMELEN); 923 io->shadow_vol[DSW_NAMELEN] = '\0'; 924 } 925 return (1); 926 } 927 928 int 929 find_matching_cf_line(char *volume, dsw_config_t *conf, dsw_ioctl_t *io) 930 { 931 return (find_next_matching_cf_line(volume, conf, io, 1)); 932 } 933 934 int 935 find_shadow_config(char *volume, dsw_config_t *conf, dsw_ioctl_t *io) 936 { 937 dsw_config_t *c, cf; 938 939 if (io) { 940 bzero(io, sizeof (dsw_ioctl_t)); 941 } 942 c = conf ? conf : &cf; 943 setnumber = 1; 944 /* perform action for each line of the stored config file */ 945 for ((void) snprintf(key, sizeof (key), "ii.set%d.shadow", setnumber); 946 cfg_get_cstring(cfg, key, c->shadow_vol, DSW_NAMELEN) >= 0; 947 (void) snprintf(key, sizeof (key), "ii.set%d.shadow", 948 ++setnumber)) { 949 if (strncmp(volume, c->shadow_vol, DSW_NAMELEN) == 0) { 950 (void) get_dsw_config(setnumber, c); 951 952 if (check_resource_group(c->bitmap_vol)) { 953 setnumber = 0; 954 continue; 955 } 956 957 switch (check_cluster()) { 958 case II_CLUSTER: 959 if ((cfg_cluster_tag) && 960 (strcmp(cfg_cluster_tag, c->cluster_tag))) 961 continue; 962 break; 963 case II_CLUSTER_LCL: 964 if (strlen(c->cluster_tag)) 965 continue; 966 break; 967 } 968 969 if (io) { 970 (void) strncpy(io->shadow_vol, c->shadow_vol, 971 DSW_NAMELEN); 972 io->shadow_vol[DSW_NAMELEN] = '\0'; 973 } 974 return (1); 975 } 976 } 977 return (0); 978 } 979 980 void 981 add_cfg_entry(dsw_config_t *parms) 982 { 983 /* insert the well-known fields first */ 984 (void) snprintf(buf, sizeof (buf), "%s %s %s %s", 985 parms->master_vol, parms->shadow_vol, parms->bitmap_vol, 986 (parms->flag & DSW_GOLDEN) ? "I" : "D"); 987 988 if (cfg_put_cstring(cfg, "ii", buf, strlen(buf)) >= 0) { 989 /* if we have a group name, add it */ 990 if (group_name) { 991 if (find_any_cf_line(parms->shadow_vol)) { 992 (void) sprintf(buf, "ii.set%d.group", 993 setnumber); 994 if (cfg_put_cstring(cfg, buf, 995 group_name, strlen(group_name)) < 0) 996 perror("cfg_put_cstring"); 997 } 998 else 999 perror("cfg_location"); 1000 } 1001 1002 /* commit the record */ 1003 (void) cfg_commit(cfg); 1004 } 1005 else 1006 perror("cfg_put_string"); 1007 } 1008 1009 void 1010 remove_iiset(int setno, char *shadow, int shd_exp) 1011 { 1012 mstcount_t *mdata; 1013 shdvol_t *sdata; 1014 char sn[CFG_MAX_BUF]; 1015 1016 if (perform_autosv()) { 1017 if (volhash) { 1018 unload_ii_vols(); 1019 } 1020 load_ii_vols(cfg); 1021 if (cfg_load_dsvols(cfg) < 0 || cfg_load_svols(cfg) < 0) { 1022 dsw_error(gettext("Unable to parse config file"), NULL); 1023 } 1024 1025 sdata = (shdvol_t *)nsc_lookup(volhash, shadow); 1026 if (sdata) { 1027 /* 1028 * Handle the normal cases of disabling a set that is 1029 * not an imported shadow volume 1030 */ 1031 if (strcmp(sdata->master, II_IMPORTED_SHADOW)) { 1032 /* 1033 * Handle multiple-shadows of single master 1034 */ 1035 mdata = (mstcount_t *) 1036 nsc_lookup(volhash, sdata->master); 1037 if ((mdata) && (mdata->count == 1)) { 1038 if (cfg_vol_disable(cfg, sdata->master, 1039 cfg_cluster_tag, "ii") < 0) 1040 dsw_error(gettext( 1041 "SV disable of master failed"), 1042 NULL); 1043 } 1044 } 1045 1046 /* 1047 * Handle disk group name of different shadow 1048 */ 1049 if (shd_exp) { 1050 /* 1051 * If shadow is exported, then do nothing 1052 */ 1053 /*EMPTY*/; 1054 } else if (cfg_cluster_tag && 1055 strcmp(cfg_cluster_tag, "") && 1056 cfg_dgname(shadow, sn, sizeof (sn)) && 1057 strlen(sn) && 1058 strcmp(sn, cfg_cluster_tag)) { 1059 /* reload disk group volumes */ 1060 cfg_resource(cfg, sn); 1061 cfg_unload_dsvols(); 1062 cfg_unload_svols(); 1063 (void) cfg_load_dsvols(cfg); 1064 (void) cfg_load_svols(cfg); 1065 if (cfg_vol_disable(cfg, shadow, sn, 1066 "ii") < 0) 1067 dsw_error(gettext( 1068 "SV disable of shadow failed"), 1069 NULL); 1070 cfg_resource(cfg, cfg_cluster_tag); 1071 } else { 1072 if (cfg_vol_disable(cfg, shadow, 1073 cfg_cluster_tag, "ii") < 0) 1074 dsw_error(gettext( 1075 "SV disable of shadow failed"), 1076 NULL); 1077 } 1078 } 1079 cfg_unload_svols(); 1080 cfg_unload_dsvols(); 1081 unload_ii_vols(); 1082 reload_vols &= ~(LD_SVOLS | LD_DSVOLS | LD_II); 1083 } 1084 1085 (void) sprintf(key, "ii.set%d", setno); 1086 if (cfg_put_cstring(cfg, key, NULL, 0) < 0) { 1087 perror("cfg_put_cstring"); 1088 } 1089 (void) cfg_commit(cfg); 1090 } 1091 1092 /* 1093 * determine if we are running in a Sun Cluster Environment 1094 */ 1095 int 1096 check_cluster() 1097 { 1098 static int is_cluster = -1; 1099 int rc; 1100 #ifdef DEBUG 1101 char *cdebug = getenv("II_SET_CLUSTER"); 1102 #endif 1103 1104 /* 1105 * If this routine was previously called, just return results 1106 */ 1107 if (is_cluster != -1) 1108 return (is_cluster); 1109 1110 /* 1111 * See if Sun Cluster was installed on this node 1112 */ 1113 #ifdef DEBUG 1114 if (cdebug) rc = atoi(cdebug); 1115 else 1116 #endif 1117 rc = cfg_iscluster(); 1118 if (rc > 0) { 1119 /* 1120 * Determine if user specified -C local 1121 */ 1122 if ((cfg_cluster_tag == NULL) || 1123 (strcmp(cfg_cluster_tag, II_LOCAL_TAG))) { 1124 /* 1125 * We're in a Sun Cluster, and no "-C local" 1126 */ 1127 is_cluster = II_CLUSTER; 1128 } else { 1129 /* 1130 * We're in a Sun Cluster, but "-C local" was specified 1131 */ 1132 is_cluster = II_CLUSTER_LCL; 1133 cfg_cluster_tag = ""; 1134 } 1135 return (is_cluster); 1136 } else if (rc == 0) { 1137 /* 1138 * Not in a Sun Cluster 1139 */ 1140 is_cluster = II_NOT_CLUSTER; 1141 return (is_cluster); 1142 } else { 1143 dsw_error(gettext("unable to ascertain environment"), NULL); 1144 /*NOTREACHED*/ 1145 } 1146 1147 /* gcc */ 1148 return (is_cluster); 1149 } 1150 1151 /* 1152 * Determine if we need to set a cfg_resource based on this volume 1153 */ 1154 static int 1155 check_resource_group(char *volume) 1156 { 1157 char diskgroup[CFG_MAX_BUF]; 1158 1159 /* 1160 * If we are in a cluster, attempt to derive a new resource group 1161 */ 1162 1163 #ifdef DEBUG 1164 if (getenv("II_SET_CLUSTER") || (check_cluster() == II_CLUSTER)) { 1165 #else 1166 if (check_cluster() == II_CLUSTER) { 1167 #endif 1168 if (check_diskgroup(volume, diskgroup)) { 1169 if (cfg_cluster_tag == NULL) { 1170 cfg_cluster_tag = strdup(diskgroup); 1171 if (cfg_cluster_tag == NULL) 1172 dsw_error(gettext( 1173 "Memory allocation failure"), NULL); 1174 cfg_resource(cfg, cfg_cluster_tag); 1175 return (1); 1176 } else { 1177 /* 1178 * Check dgname and cluster tag from -C are the same. 1179 */ 1180 if (strcmp(diskgroup, cfg_cluster_tag) != 0) { 1181 char error_buffer[128]; 1182 (void) snprintf(error_buffer, sizeof (error_buffer), 1183 gettext( 1184 "-C (%s) does not match disk group " 1185 "name (%s) for %s"), cfg_cluster_tag, 1186 diskgroup, volume); 1187 spcs_log("ii", NULL, error_buffer); 1188 dsw_error(error_buffer, NULL); 1189 } 1190 } 1191 } else if (cfg_cluster_tag == NULL) 1192 dsw_error(gettext( 1193 "Point-in-Time Copy volumes, that are not " 1194 "in a device group which has been " 1195 "registered with SunCluster, " 1196 "require usage of \"-C\""), NULL); 1197 } 1198 return (0); 1199 } 1200 1201 static void 1202 check_dg_is_local(char *dgname) 1203 { 1204 char error_buffer[128]; 1205 char *othernode; 1206 int rc; 1207 1208 /* 1209 * check where this disk service is mastered 1210 */ 1211 rc = cfg_dgname_islocal(dgname, &othernode); 1212 if (rc < 0) { 1213 (void) snprintf(error_buffer, sizeof (error_buffer), 1214 gettext("Unable to find disk service:%s"), dgname); 1215 dsw_error(error_buffer, NULL); 1216 } else if (rc == 0) { 1217 (void) snprintf(error_buffer, sizeof (error_buffer), 1218 gettext("disk service, %s, is active on node \"%s\"\n" 1219 "Please re-issue the command on that node"), dgname, 1220 othernode); 1221 dsw_error(error_buffer, NULL); 1222 } 1223 } 1224 1225 /* 1226 * Carry out cluster based checks for a specified volume, or just 1227 * global options. 1228 */ 1229 static int 1230 check_diskgroup(char *path, char *result) 1231 { 1232 char dgname[CFG_MAX_BUF]; 1233 char error_buffer[128]; 1234 1235 #ifdef DEBUG 1236 char *override = getenv("II_CLUSTER_TAG"); 1237 if (override) { 1238 (void) strcpy(result, override); 1239 return (1); 1240 } 1241 #endif 1242 /* 1243 * Check on path name, a returned NULL dgname is valid 1244 */ 1245 if (cfg_dgname(path, dgname, sizeof (dgname)) == NULL) { 1246 (void) snprintf(error_buffer, sizeof (error_buffer), gettext( 1247 "unable to determine disk group name for %s"), path); 1248 dsw_error(error_buffer, NULL); 1249 } 1250 if (strcmp(dgname, "") == 0) 1251 return (0); 1252 1253 /* 1254 * See if disk group is local to this node 1255 */ 1256 check_dg_is_local(dgname); 1257 1258 /* 1259 * Copy dgname into result 1260 */ 1261 (void) strcpy(result, dgname); 1262 return (1); 1263 } 1264 1265 /* 1266 * sigterm (): traps specified signal , usually termination one 1267 */ 1268 void 1269 sigterm(int sig) 1270 { 1271 spcs_log("ii", NULL, gettext("%s received signal %d"), cmdnam, sig); 1272 exit(1); 1273 } 1274 1275 /* 1276 * sigchild; reap child and collect status. 1277 */ 1278 1279 volatile pid_t dead_child; 1280 int dead_stat; 1281 1282 /*ARGSUSED*/ 1283 void 1284 sigchild(int sig) 1285 { 1286 dead_child = wait(&dead_stat); 1287 } 1288 1289 /* 1290 * InitEnv(): initializes environment 1291 */ 1292 void 1293 InitEnv() 1294 { 1295 (void) setlocale(LC_ALL, ""); 1296 (void) textdomain(DSW_TEXT_DOMAIN); 1297 1298 #ifndef DEBUG 1299 (void) sigset(SIGHUP, sigterm); 1300 (void) sigset(SIGINT, sigterm); 1301 (void) sigset(SIGQUIT, sigterm); 1302 (void) sigset(SIGILL, sigterm); 1303 (void) sigset(SIGEMT, sigterm); 1304 (void) sigset(SIGABRT, sigterm); 1305 (void) sigset(SIGFPE, sigterm); 1306 (void) sigset(SIGBUS, sigterm); 1307 (void) sigset(SIGSEGV, sigterm); 1308 (void) sigset(SIGTERM, sigterm); 1309 (void) sigset(SIGPWR, sigterm); 1310 (void) sigset(SIGSTOP, sigterm); 1311 (void) sigset(SIGTSTP, sigterm); 1312 #endif 1313 1314 dsw_fd = open(DSWDEV, O_RDONLY); 1315 if (dsw_fd < 0) { 1316 perror(DSWDEV); 1317 exit(1); 1318 } 1319 1320 (void) setsid(); 1321 } 1322 1323 /* 1324 * print an error message, followed by decoded errno then exit. 1325 */ 1326 void 1327 dsw_error(char *str, spcs_s_info_t *status) 1328 { 1329 char *sp; 1330 1331 (void) fprintf(stderr, "%s: %s:\n", cmdnam, str); 1332 if (status == NULL) { 1333 /* deflect ESRCH */ 1334 if (ESRCH == errno) { 1335 sp = "Set/volume not found"; 1336 } else { 1337 sp = strerror(errno); 1338 } 1339 (void) fprintf(stderr, "%s\n", sp ? sp : ""); 1340 } else { 1341 spcs_s_report(*status, stderr); 1342 spcs_s_ufree(status); 1343 } 1344 if (cfg) 1345 cfg_close(cfg); 1346 exit(2); 1347 } 1348 1349 1350 #undef size 1351 1352 void 1353 free_bitmap(unsigned char *bitmap) 1354 { 1355 free(bitmap); 1356 } 1357 1358 1359 int 1360 get_bitmap(master_volume, shd_bitmap, copy_bitmap, size) 1361 char *master_volume; 1362 unsigned char *shd_bitmap; 1363 unsigned char *copy_bitmap; 1364 unsigned long size; 1365 { 1366 dsw_bitmap_t parms; 1367 1368 (void) strncpy(parms.shadow_vol, master_volume, DSW_NAMELEN); 1369 parms.shadow_vol[DSW_NAMELEN-1] = '\0'; 1370 parms.shd_bitmap = shd_bitmap; 1371 parms.shd_size = size; 1372 parms.copy_bitmap = copy_bitmap; 1373 parms.copy_size = size; 1374 1375 return (do_ioctl(dsw_fd, DSWIOC_BITMAP, &parms)); 1376 } 1377 1378 unsigned char * 1379 allocate_bitmap(char *shadow_volume) 1380 { 1381 unsigned char *shd_bitmap; 1382 unsigned char *copy_bitmap; 1383 unsigned char *p; 1384 unsigned char *q; 1385 int i; 1386 dsw_stat_t args; 1387 int stat_flags; 1388 1389 (void) strncpy(args.shadow_vol, shadow_volume, DSW_NAMELEN); 1390 args.shadow_vol[DSW_NAMELEN-1] = '\0'; 1391 1392 args.status = spcs_s_ucreate(); 1393 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) 1394 dsw_error(gettext("Stat failed"), &args.status); 1395 1396 stat_flags = args.stat; 1397 if (stat_flags & DSW_BMPOFFLINE) 1398 return (NULL); 1399 1400 bm_size = args.size; 1401 bm_size = (bm_size + DSW_SIZE-1) / DSW_SIZE; 1402 bm_actual = bm_size; 1403 bm_size = (bm_size + DSW_BITS-1) / DSW_BITS; 1404 spcs_s_ufree(&args.status); 1405 1406 p = shd_bitmap = (unsigned char *) malloc(bm_size); 1407 if (!shd_bitmap) { 1408 perror(gettext("malloc bitmap")); 1409 return (NULL); 1410 } 1411 1412 q = copy_bitmap = (unsigned char *) malloc(bm_size); 1413 if (!copy_bitmap) { 1414 perror(gettext("malloc bitmap")); 1415 free(shd_bitmap); 1416 return (NULL); 1417 } 1418 1419 (void) memset(shd_bitmap, 0, bm_size); 1420 (void) memset(copy_bitmap, 0, bm_size); 1421 1422 if (get_bitmap(shadow_volume, shd_bitmap, copy_bitmap, bm_size) < 0) { 1423 free(copy_bitmap); 1424 free(shd_bitmap); 1425 return (NULL); 1426 } 1427 1428 /* 1429 * "or" the copy and shadow bitmaps together to return a composite 1430 * bitmap that contains the total set of differences between the 1431 * volumes. 1432 */ 1433 for (i = bm_size; i-- > 0; /*CSTYLED*/) 1434 *p++ |= *q++; 1435 1436 free(copy_bitmap); 1437 1438 return (shd_bitmap); 1439 } 1440 1441 /* 1442 * print usage message and exit. 1443 */ 1444 void 1445 usage(char *why) 1446 { 1447 if (why) { 1448 (void) fprintf(stderr, "%s: %s\n", cmdnam, why); 1449 1450 (void) fprintf(stderr, "%s\n", 1451 gettext("\nBrief summary:")); 1452 (void) fprintf(stderr, "%s\n", 1453 gettext("\t-e {ind|dep} master_vol shadow_vol " 1454 "bitmap_vol")); 1455 (void) fprintf(stderr, "%s\n", 1456 gettext("\t-[cu {s|m}] volume_set")); 1457 (void) fprintf(stderr, "%s\n", 1458 gettext("\t-i all")); 1459 (void) fprintf(stderr, "%s\n", 1460 gettext("\t-[adDEilPRw] volume_set")); 1461 (void) fprintf(stderr, "%s\n", 1462 gettext("\t-g group_name [options]")); 1463 (void) fprintf(stderr, "%s\n", 1464 gettext("\t-C cluster_tag [options]")); 1465 (void) fprintf(stderr, "%s\n", 1466 gettext("\t-[hilLv]")); 1467 (void) fprintf(stderr, "%s\n", 1468 gettext("\t-[IJ] volume_set bitmap")); 1469 (void) fprintf(stderr, "%s\n", 1470 gettext("\t-A overflow_vol volume_set")); 1471 (void) fprintf(stderr, "%s\n", 1472 gettext("\t-[OQ] overflow_vol")); 1473 (void) fprintf(stderr, "%s\n", 1474 gettext("\t-P {delay} {units} volume_set")); 1475 1476 /* assume we came here due to a user mistake */ 1477 exit(1); 1478 /* NOTREACHED */ 1479 } else { 1480 1481 (void) fprintf(stdout, "%s\n", 1482 gettext("Point-in-Time Copy Administrator CLI options")); 1483 (void) fprintf(stdout, "%s\n", 1484 gettext("Usage summary:")); 1485 (void) fprintf(stdout, "%s\n", 1486 gettext("\t-e ind m s b\tenable independent master shadow " 1487 "bitmap")); 1488 (void) fprintf(stdout, "%s\n", 1489 gettext("\t-e dep m s b\tenable dependent master shadow " 1490 "bitmap")); 1491 if (check_cluster() == II_CLUSTER) 1492 (void) fprintf(stdout, "%s\n", 1493 gettext("\t-ne ind m s b\tenable exportable master " 1494 "shadow bitmap")); 1495 (void) fprintf(stdout, "%s\n", 1496 gettext("\t-d v\t\tdisable volume")); 1497 (void) fprintf(stdout, "%s\n", 1498 gettext("\t-u s v\t\tupdate shadow volume")); 1499 (void) fprintf(stdout, "%s\n", 1500 gettext("\t-u m v\t\tupdate master volume")); 1501 (void) fprintf(stdout, "%s\n", 1502 gettext("\t-c s v\t\tcopy to shadow volume")); 1503 (void) fprintf(stdout, "%s\n", 1504 gettext("\t-c m v\t\tcopy to master volume")); 1505 (void) fprintf(stdout, "%s\n", 1506 gettext("\t-a v\t\tabort copy volume")); 1507 (void) fprintf(stdout, "%s\n", 1508 gettext("\t-w v\t\twait volume")); 1509 (void) fprintf(stdout, "%s\n", 1510 gettext("\t-i v\t\tdisplay volume status")); 1511 (void) fprintf(stdout, "%s\n", 1512 gettext("\t-i all\t\tdisplay all volume status")); 1513 (void) fprintf(stdout, "%s\n", 1514 gettext("\t-l\t\tlist all volumes")); 1515 (void) fprintf(stdout, "%s\n", 1516 gettext("\t-R v\t\treset volume")); 1517 (void) fprintf(stdout, "%s\n", 1518 gettext("\t-A o v\t\tattach overflow to volume")); 1519 (void) fprintf(stdout, "%s\n", 1520 gettext("\t-D v\t\tdetach overflow from volume")); 1521 (void) fprintf(stdout, "%s\n", 1522 gettext("\t-L\t\tlist all overflow volumes")); 1523 (void) fprintf(stdout, "%s\n", 1524 gettext("\t-O o\t\tinitialize overflow")); 1525 (void) fprintf(stdout, "%s\n", 1526 gettext("\t-Q o\t\tquery status of overflow")); 1527 (void) fprintf(stdout, "%s\n", 1528 gettext("\t-E v\t\texport shadow volume")); 1529 (void) fprintf(stdout, "%s\n", 1530 gettext("\t-I v b\t\timport volume bitmap")); 1531 (void) fprintf(stdout, "%s\n", 1532 gettext("\t-J v b\t\tjoin volume bitmap")); 1533 (void) fprintf(stdout, "%s\n", 1534 gettext("\t-P d u v\tset copy delay/units for volume")); 1535 (void) fprintf(stdout, "%s\n", 1536 gettext("\t-P v\t\tget copy delay/units for volume")); 1537 (void) fprintf(stdout, "%s\n", 1538 gettext("\t-C tag\t\tcluster resource tag")); 1539 #ifdef DEBUG 1540 (void) fprintf(stdout, "%s\n", 1541 gettext("\t-b v\t\tdisplay bitmap volume")); 1542 (void) fprintf(stdout, "%s\n", 1543 gettext("\t-f f\t\tuse private configuration file")); 1544 #endif 1545 (void) fprintf(stdout, "%s\n", 1546 gettext("\t-v\t\tprint software versions")); 1547 (void) fprintf(stdout, "%s\n", 1548 gettext("\t-n\t\tperform action without question")); 1549 (void) fprintf(stdout, "%s\n", 1550 gettext("\t-p [-c|-u] {m|s}" 1551 "enable PID locking on copy or update")); 1552 (void) fprintf(stdout, "%s\n", 1553 gettext("\t-p -w v\t\tdisable PID locking")); 1554 (void) fprintf(stdout, "%s\n", 1555 gettext("\t-h\t\tiiadm usage summary")); 1556 (void) fprintf(stdout, "%s\n", 1557 gettext("\nUsage summary for options that support " 1558 "grouping (-g g):")); 1559 (void) fprintf(stdout, "%s\n", 1560 gettext("\t-g g -e ind m s b group enable independent " 1561 "master shadow bitmap")); 1562 (void) fprintf(stdout, "%s\n", 1563 gettext("\t-g g -e dep m s b group enable dependent " 1564 "master shadow bitmap")); 1565 (void) fprintf(stdout, "%s\n", 1566 gettext("\t-g g -d\t\tdisable group")); 1567 (void) fprintf(stdout, "%s\n", 1568 gettext("\t-g g -u s\tupdate shadow for all volumes in " 1569 "group")); 1570 (void) fprintf(stdout, "%s\n", 1571 gettext("\t-g g -u m\tupdate master for all volumes in " 1572 "group")); 1573 (void) fprintf(stdout, "%s\n", 1574 gettext("\t-g g -c s\tcopy to shadow for all volumes in " 1575 "group")); 1576 (void) fprintf(stdout, "%s\n", 1577 gettext("\t-g g -c m\tcopy to master for all volumes in " 1578 "group")); 1579 (void) fprintf(stdout, "%s\n", 1580 gettext("\t-g g -a\t\tabort copy for all volumes in " 1581 "group")); 1582 (void) fprintf(stdout, "%s\n", 1583 gettext("\t-g g -w\t\twait for all volumes in group")); 1584 (void) fprintf(stdout, "%s\n", 1585 gettext("\t-g g -i\t\tdisplay status of all volumes in " 1586 "group")); 1587 (void) fprintf(stdout, "%s\n", 1588 gettext("\t-g g -l\t\tlist all volumes in group")); 1589 (void) fprintf(stdout, "%s\n", 1590 gettext("\t-g -L\t\tlist all groups")); 1591 (void) fprintf(stdout, "%s\n", 1592 gettext("\t-g g -m v v\tmove one or more volumes into " 1593 "group")); 1594 (void) fprintf(stdout, "%s\n", 1595 gettext("\t-g \"\" -m v\tremove volume from group")); 1596 (void) fprintf(stdout, "%s\n", 1597 gettext("\t-g g -R\t\treset all volumes in group")); 1598 (void) fprintf(stdout, "%s\n", 1599 gettext("\t-g g -A o\tattach overflow to all volumes in " 1600 "group")); 1601 (void) fprintf(stdout, "%s\n", 1602 gettext("\t-g g -D\t\tdetach overflow from all volumes in " 1603 "group")); 1604 (void) fprintf(stdout, "%s\n", 1605 gettext("\t-g g -E\t\texport shadow volume for all " 1606 "volumes in group")); 1607 (void) fprintf(stdout, "%s\n", 1608 gettext("\t-g g -P d u\tset copy delay/units for all " 1609 "volumes in group")); 1610 (void) fprintf(stdout, "%s\n", 1611 gettext("\t-g g -P\t\tget copy delay/units for all " 1612 "volumes in group")); 1613 (void) fprintf(stdout, "%s\n", 1614 gettext("\nLegend summary:")); 1615 (void) fprintf(stdout, "%s\n", 1616 gettext("\tind\t\tindependent volume set")); 1617 (void) fprintf(stdout, "%s\n", 1618 gettext("\tdep\t\tdependent volume set")); 1619 (void) fprintf(stdout, "%s\n", 1620 gettext("\tall\t\tall configured volumes")); 1621 (void) fprintf(stdout, "%s\n", 1622 gettext("\tm\t\tmaster volume")); 1623 (void) fprintf(stdout, "%s\n", 1624 gettext("\ts\t\tshadow volume")); 1625 (void) fprintf(stdout, "%s\n", 1626 gettext("\tv\t\tshadow volume (reference name)")); 1627 (void) fprintf(stdout, "%s\n", 1628 gettext("\to\t\toverflow volume")); 1629 (void) fprintf(stdout, "%s\n", 1630 gettext("\tb\t\tbitmap volume")); 1631 #ifdef DEBUG 1632 (void) fprintf(stdout, "%s\n", 1633 gettext("\tf\t\tconfiguration file name")); 1634 #endif 1635 (void) fprintf(stdout, "%s\n", 1636 gettext("\td\t\tdelay tick interval")); 1637 (void) fprintf(stdout, "%s\n", 1638 gettext("\tu\t\tunit size")); 1639 (void) fprintf(stdout, "%s\n", 1640 gettext("\tg\t\tgroup name")); 1641 1642 /* assume we came here because user request help text */ 1643 exit(0); 1644 /* NOTREACHED */ 1645 } 1646 1647 } 1648 1649 static char yeschr[MAX_LINE_SIZE + 2]; 1650 static char nochr[MAX_LINE_SIZE + 2]; 1651 1652 static int 1653 yes(void) 1654 { 1655 int i, b; 1656 char ans[MAX_LINE_SIZE + 1]; 1657 1658 for (i = 0; /*CSTYLED*/; i++) { 1659 b = getchar(); 1660 if (b == '\n' || b == '\0' || b == EOF) { 1661 if (i < MAX_LINE_SIZE) 1662 ans[i] = 0; 1663 break; 1664 } 1665 if (i < MAX_LINE_SIZE) 1666 ans[i] = b; 1667 } 1668 if (i >= MAX_LINE_SIZE) { 1669 i = MAX_LINE_SIZE; 1670 ans[MAX_LINE_SIZE] = 0; 1671 } 1672 if ((i == 0) || (strncmp(yeschr, ans, i))) { 1673 if (strncmp(nochr, ans, i) == 0) 1674 return (0); 1675 else if (strncmp(yeschr, ans, i) == 0) 1676 return (1); 1677 else { 1678 (void) fprintf(stderr, "%s %s/%s\n", 1679 gettext("You have to respond with"), 1680 yeschr, nochr); 1681 return (2); 1682 } 1683 } 1684 return (1); 1685 } 1686 1687 static int 1688 convert_int(char *str) 1689 { 1690 int result, rc; 1691 char *buf; 1692 1693 buf = (char *)calloc(strlen(str) + 256, sizeof (char)); 1694 rc = sscanf(str, "%d%s", &result, buf); 1695 1696 if (rc != 1) { 1697 (void) sprintf(buf, gettext("'%s' is not a valid number"), str); 1698 /* dsw_error calls exit which frees 'buf' */ 1699 errno = EINVAL; 1700 dsw_error(buf, NULL); 1701 } 1702 free(buf); 1703 1704 return (result); 1705 } 1706 1707 void 1708 check_action(char *will_happen) 1709 { 1710 int answer; 1711 1712 if (nflg || !isatty(fileno(stdin))) 1713 return; 1714 (void) strncpy(yeschr, nl_langinfo(YESSTR), MAX_LINE_SIZE + 1); 1715 (void) strncpy(nochr, nl_langinfo(NOSTR), MAX_LINE_SIZE + 1); 1716 1717 /*CONSTCOND*/ 1718 while (1) { 1719 (void) printf("%s %s/%s ", will_happen, yeschr, nochr); 1720 answer = yes(); 1721 if (answer == 1 || answer == 0) 1722 break; 1723 } 1724 if (answer == 1) 1725 return; 1726 exit(1); 1727 } 1728 1729 enum child_event {Status, CopyStart}; 1730 1731 /* 1732 * Wait for child process to get to some state, where some state may be: 1733 * 1734 * Status Set up the shadow enough so that it responds 1735 * to status requests. 1736 * CopyStart Start copy/update operations. 1737 */ 1738 1739 int 1740 child_wait(pid_t child, enum child_event event, char *volume) 1741 { 1742 dsw_stat_t args; 1743 int rc; 1744 1745 (void) strncpy(args.shadow_vol, volume, DSW_NAMELEN); 1746 args.shadow_vol[DSW_NAMELEN-1] = '\0'; 1747 1748 for (; dead_child != child; (void) sleep(1)) { 1749 1750 /* poll shadow group with a status ioctl() */ 1751 args.status = spcs_s_ucreate(); 1752 errno = 0; 1753 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &args); 1754 1755 spcs_s_ufree(&args.status); 1756 1757 if (event == Status) { 1758 /* keep polling while we fail with DSW_ENOTFOUND */ 1759 if (rc != -1 || errno != DSW_ENOTFOUND) 1760 return (0); 1761 } else { 1762 /* event == CopyStart */ 1763 if (rc == -1) { 1764 return (1); /* something wrong */ 1765 } 1766 if (args.stat & DSW_COPYINGP) 1767 return (0); /* copying underway */ 1768 } 1769 } 1770 /* child died */ 1771 if (WIFEXITED(dead_stat)) 1772 return (WEXITSTATUS(dead_stat)); 1773 else 1774 return (1); 1775 } 1776 1777 int 1778 mounted(char *t) 1779 { 1780 int rdsk; 1781 int i; 1782 FILE *mntfp; 1783 struct mnttab mntref; 1784 struct mnttab mntent; 1785 char target[DSW_NAMELEN]; 1786 char *s; 1787 1788 rdsk = i = 0; 1789 for (s = target; i < DSW_NAMELEN && (*s = *t++); i++) { 1790 if (*s == 'r' && rdsk == 0) 1791 rdsk = 1; 1792 else 1793 s++; 1794 } 1795 *s = '\0'; 1796 1797 mntref.mnt_special = target; 1798 mntref.mnt_mountp = NULL; 1799 mntref.mnt_fstype = NULL; 1800 mntref.mnt_mntopts = NULL; 1801 mntref.mnt_time = NULL; 1802 1803 if ((mntfp = fopen("/etc/mnttab", "r")) == NULL) { 1804 dsw_error(gettext("Can not check volume against mount table"), 1805 NULL); 1806 } 1807 if (getmntany(mntfp, &mntent, &mntref) != -1) { 1808 /* found something before EOF */ 1809 (void) fclose(mntfp); 1810 return (1); 1811 } 1812 (void) fclose(mntfp); 1813 return (0); 1814 } 1815 1816 void 1817 enable(char *master_volume, char *shadow_volume, 1818 char *bitmap_volume, char *copy_type) 1819 { 1820 dsw_config_t parms; 1821 dsw_ioctl_t temp; 1822 char *p; 1823 int rc; 1824 pid_t child; 1825 spcs_s_info_t *sp_info; 1826 struct stat mstat, sstat, bstat; 1827 char mst_dg[DSW_NAMELEN] = {0}; 1828 char shd_dg[DSW_NAMELEN] = {0}; 1829 char bmp_dg[DSW_NAMELEN] = {0}; 1830 int mvol_enabled; 1831 char *altname; 1832 grptag_t *gdata; 1833 1834 bzero(&parms, sizeof (dsw_config_t)); 1835 1836 if (strcmp(copy_type, "independent") == 0 || 1837 strcmp(copy_type, gettext("independent")) == 0) 1838 parms.flag = DSW_GOLDEN; 1839 else if (strcmp(copy_type, "dependent") == 0 || 1840 strcmp(copy_type, gettext("dependent")) == 0) 1841 parms.flag = 0; 1842 else 1843 dsw_error(gettext("don't understand shadow type"), NULL); 1844 1845 /* validate volume names */ 1846 if (perform_autosv()) { 1847 if (cfg_load_svols(cfg) < 0 || cfg_load_dsvols(cfg) < 0 || 1848 cfg_load_shadows(cfg) < 0) { 1849 dsw_error(gettext("Unable to parse config file"), NULL); 1850 } 1851 load_ii_vols(cfg); 1852 reload_vols = LD_SVOLS | LD_DSVOLS | LD_SHADOWS | LD_II; 1853 1854 /* see if it's been used before under a different name */ 1855 conform_name(&master_volume); 1856 conform_name(&shadow_volume); 1857 rc = cfg_get_canonical_name(cfg, bitmap_volume, &altname); 1858 if (rc < 0) { 1859 dsw_error(gettext("Unable to parse config file"), NULL); 1860 } 1861 if (rc) { 1862 errno = EBUSY; 1863 dsw_error(gettext("Bitmap in use"), NULL); 1864 } 1865 } 1866 1867 /* 1868 * If not local, determine disk group names for volumes in II set 1869 */ 1870 switch (check_cluster()) { 1871 case II_CLUSTER: 1872 /* 1873 * Check if none or all volumes are in a disk group 1874 */ 1875 rc = 0; 1876 if (check_diskgroup(master_volume, mst_dg)) rc++; 1877 if (check_diskgroup(shadow_volume, shd_dg)) rc++; 1878 if (check_diskgroup(bitmap_volume, bmp_dg)) rc++; 1879 if ((rc != 0) && (rc != 3)) 1880 dsw_error(gettext( 1881 "Not all Point-in-Time Copy volumes are " 1882 "in a disk group"), NULL); 1883 1884 /* 1885 * If volumes are not in a disk group, but are in a 1886 * cluster, then "-C <tag>", must be set 1887 */ 1888 if (rc == 0 && cfg_cluster_tag == NULL) 1889 dsw_error(gettext( 1890 "Point-in-Time Copy volumes, that are not " 1891 "in a device group which has been " 1892 "registered with SunCluster, " 1893 "require usage of \"-C\""), NULL); 1894 1895 /* 1896 * the same disk group 1897 * If -n, plus mst_dg==bmp_dg, then allow E/I/J in SunCluster 1898 */ 1899 if ((strcmp(mst_dg, bmp_dg)) || 1900 (strcmp(mst_dg, shd_dg) && (!nflg))) 1901 dsw_error(gettext( 1902 "Volumes are not in same disk group"), NULL); 1903 1904 /* 1905 * Can never enable the same shadow twice, regardless of 1906 * exportable shadow device group movement 1907 */ 1908 if (find_shadow_line(shadow_volume)) 1909 dsw_error(gettext( 1910 "Shadow volume is already configured"), NULL); 1911 1912 /* 1913 * Groups cannot span multiple clusters 1914 */ 1915 if (group_name && perform_autosv()) { 1916 gdata = (grptag_t *)nsc_lookup(volhash, group_name); 1917 if (gdata && 1918 strncmp(gdata->ctag, mst_dg, DSW_NAMELEN) != 0) { 1919 errno = EINVAL; 1920 dsw_error(gettext("Group contains sets not " 1921 "in the same cluster resource"), NULL); 1922 } 1923 } 1924 1925 /* 1926 * Check cluster tag and bitmap disk group 1927 * set latter if different 1928 */ 1929 if (check_resource_group(bitmap_volume)) { 1930 /* 1931 * Unload and reload in the event cluster tag has 1932 * changed 1933 */ 1934 if (perform_autosv()) { 1935 unload_ii_vols(); 1936 cfg_unload_shadows(); 1937 cfg_unload_dsvols(); 1938 cfg_unload_svols(); 1939 if (cfg_load_svols(cfg) < 0 || 1940 cfg_load_dsvols(cfg) < 0 || 1941 cfg_load_shadows(cfg) < 0) { 1942 dsw_error(gettext( 1943 "Unable to parse config " 1944 "file"), NULL); 1945 } 1946 load_ii_vols(cfg); 1947 } 1948 } 1949 /* 1950 * Copy cluster name into config 1951 */ 1952 (void) strncpy(parms.cluster_tag, cfg_cluster_tag, DSW_NAMELEN); 1953 break; 1954 1955 case II_CLUSTER_LCL: 1956 /* ensure that the -C local won't interfere with the set */ 1957 if (group_name && perform_autosv()) { 1958 gdata = (grptag_t *)nsc_lookup(volhash, group_name); 1959 if (gdata) { 1960 if (strlen(gdata->ctag) != 0) { 1961 errno = EINVAL; 1962 dsw_error(gettext("Unable to put set " 1963 "into -C local and specified " 1964 "group"), NULL); 1965 } 1966 } 1967 } 1968 break; 1969 } 1970 1971 /* 1972 * If we've got a group name, add it into the config 1973 */ 1974 if (group_name) { 1975 (void) strncpy(parms.group_name, group_name, DSW_NAMELEN); 1976 } 1977 1978 /* 1979 * Determine accessability of volumes 1980 */ 1981 if (stat(master_volume, &mstat) != 0) 1982 dsw_error(gettext( 1983 "Unable to access master volume"), NULL); 1984 if (!S_ISCHR(mstat.st_mode)) 1985 dsw_error(gettext( 1986 "Master volume is not a character device"), NULL); 1987 /* check the shadow_vol hasn't be used as SNDR secondary vol */ 1988 check_iishadow(shadow_volume); 1989 if (stat(shadow_volume, &sstat) != 0) 1990 dsw_error(gettext( 1991 "Unable to access shadow volume"), NULL); 1992 if (!S_ISCHR(sstat.st_mode)) 1993 dsw_error(gettext( 1994 "Shadow volume is not a character device"), NULL); 1995 if (mounted(shadow_volume)) { 1996 errno = EBUSY; 1997 dsw_error(gettext( 1998 "Shadow volume is mounted, unmount it first"), NULL); 1999 } 2000 if (mstat.st_rdev == sstat.st_rdev) { 2001 errno = EINVAL; 2002 dsw_error(gettext( 2003 "Master and shadow are the same device"), NULL); 2004 } 2005 if (stat(bitmap_volume, &bstat) != 0) { 2006 dsw_error(gettext("Unable to access bitmap"), NULL); 2007 } 2008 if (!S_ISCHR(bstat.st_mode)) 2009 dsw_error(gettext( 2010 "Bitmap volume is not a character device"), NULL); 2011 if (S_ISCHR(bstat.st_mode)) { 2012 if (mstat.st_rdev == bstat.st_rdev) { 2013 errno = EINVAL; 2014 dsw_error(gettext( 2015 "Master and bitmap are the same device"), NULL); 2016 } else if (sstat.st_rdev == bstat.st_rdev) { 2017 errno = EINVAL; 2018 dsw_error(gettext( 2019 "Shadow and bitmap are the same device"), NULL); 2020 } 2021 } 2022 2023 (void) strncpy(parms.master_vol, master_volume, DSW_NAMELEN); 2024 (void) strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN); 2025 (void) strncpy(parms.bitmap_vol, bitmap_volume, DSW_NAMELEN); 2026 errno = 0; 2027 parms.status = spcs_s_ucreate(); 2028 2029 /* 2030 * Check that none of the member volumes forms part of another 2031 * InstantImage group. 2032 * 2033 * -- this check has been removed; it is done in the kernel instead 2034 * -- PJW 2035 */ 2036 2037 /* 2038 * Check against overflow volumes 2039 */ 2040 for (p = get_overflow_list(); *p != NULL; p += DSW_NAMELEN) { 2041 if (strncmp(master_volume, p, DSW_NAMELEN) == 0) 2042 dsw_error(gettext( 2043 "Master volume is already an overflow volume"), 2044 NULL); 2045 else if (strncmp(shadow_volume, p, DSW_NAMELEN) == 0) 2046 dsw_error(gettext( 2047 "Shadow volume is already an overflow volume"), 2048 NULL); 2049 else if (strncmp(bitmap_volume, p, DSW_NAMELEN) == 0) 2050 dsw_error(gettext( 2051 "Bitmap volume is already an overflow volume"), 2052 NULL); 2053 } 2054 2055 /* 2056 * Make sure that the shadow volume is not already configured 2057 */ 2058 if (find_shadow_config(shadow_volume, NULL, &temp)) 2059 dsw_error(gettext( 2060 "Shadow volume is already configured"), NULL); 2061 if (perform_autosv()) { 2062 /* 2063 * parse the dsvol entries to see if we need to place 2064 * the master or shadow under SV control 2065 */ 2066 if (nsc_lookup(volhash, master_volume) == NULL) { 2067 if (cfg_vol_enable(cfg, master_volume, cfg_cluster_tag, 2068 "ii") < 0) { 2069 dsw_error( 2070 gettext("Cannot enable master volume"), 2071 NULL); 2072 } 2073 mvol_enabled = 1; 2074 } else { 2075 mvol_enabled = 0; 2076 } 2077 if (nsc_lookup(volhash, shadow_volume) == NULL) { 2078 if (nflg) { 2079 cfg_resource(cfg, shd_dg); 2080 rc = cfg_vol_enable(cfg, shadow_volume, 2081 shd_dg, "ii"); 2082 cfg_resource(cfg, cfg_cluster_tag); 2083 } else { 2084 rc = cfg_vol_enable(cfg, shadow_volume, 2085 cfg_cluster_tag, "ii"); 2086 } 2087 if (rc < 0) { 2088 if (mvol_enabled) { 2089 if (cfg_vol_disable(cfg, 2090 master_volume, cfg_cluster_tag, 2091 "ii") < 0) 2092 dsw_error(gettext( 2093 "SV disable of master failed"), 2094 NULL); 2095 } 2096 dsw_error( 2097 gettext("Cannot enable shadow volume"), 2098 NULL); 2099 } 2100 } 2101 unload_ii_vols(); 2102 cfg_unload_shadows(); 2103 cfg_unload_dsvols(); 2104 cfg_unload_svols(); 2105 reload_vols = 0; 2106 } 2107 2108 add_cfg_entry(&parms); 2109 cfg_unlock(cfg); 2110 config_locked = 0; 2111 2112 (void) sigset(SIGCHLD, sigchild); 2113 switch (child = fork()) { 2114 2115 case (pid_t)-1: 2116 dsw_error(gettext("Unable to fork"), NULL); 2117 break; 2118 2119 case 0: 2120 rc = do_ioctl(dsw_fd, DSWIOC_ENABLE, &parms); 2121 if (rc == -1 && errno != DSW_EABORTED && errno != DSW_EIO) { 2122 /* 2123 * Failed to enable shadow group, log problem and remove 2124 * the shadow group from the config file. 2125 */ 2126 spcs_log("ii", &parms.status, 2127 gettext("Enable failed %s %s %s (%s)"), 2128 master_volume, shadow_volume, bitmap_volume, 2129 parms.flag & DSW_GOLDEN ? 2130 "independent" : "dependent"); 2131 2132 if (!ii_lock(cfg, CFG_WRLOCK) || 2133 !find_shadow_config(shadow_volume, NULL, &temp)) { 2134 dsw_error(gettext( 2135 "Enable failed, can't tidy up cfg"), 2136 &parms.status); 2137 } 2138 config_locked = 1; 2139 remove_iiset(setnumber, shadow_volume, 0); 2140 dsw_error(gettext("Enable failed"), &parms.status); 2141 } 2142 2143 if (rc == -1) 2144 sp_info = &parms.status; 2145 else 2146 sp_info = NULL; 2147 spcs_log("ii", sp_info, gettext("Enabled %s %s %s (%s)"), 2148 master_volume, shadow_volume, bitmap_volume, 2149 parms.flag & DSW_GOLDEN ? "independent" : "dependent"); 2150 spcs_s_ufree(&parms.status); 2151 break; 2152 2153 default: 2154 exit(child_wait(child, Status, shadow_volume)); 2155 break; 2156 } 2157 } 2158 2159 int 2160 reset(char *volume) 2161 { 2162 dsw_ioctl_t args; 2163 dsw_config_t parms; 2164 int rc; 2165 int wait_loc; 2166 pid_t child = (pid_t)0; 2167 enum copy_wait wait_action; 2168 spcs_s_info_t *stat; 2169 dsw_stat_t prev_stat; 2170 int stat_flags; 2171 static int unlocked = 0; 2172 int do_enable = 0; 2173 char key[CFG_MAX_KEY]; 2174 char optval[CFG_MAX_BUF]; 2175 unsigned int flags; 2176 2177 wait_action = WaitForStart; 2178 2179 if (unlocked && !ii_lock(cfg, CFG_RDLOCK)) { 2180 dsw_error(gettext("Unable to set locking on the configuration"), 2181 NULL); 2182 } 2183 config_locked = 1; 2184 if (!find_shadow_config(volume, &parms, &args)) 2185 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 2186 "group"), NULL); 2187 2188 cfg_unlock(cfg); 2189 config_locked = 0; 2190 unlocked = 1; 2191 2192 spcs_log("ii", NULL, gettext("Start reset %s"), volume); 2193 (void) strncpy(prev_stat.shadow_vol, volume, DSW_NAMELEN); 2194 prev_stat.shadow_vol[DSW_NAMELEN - 1] = '\0'; 2195 prev_stat.status = spcs_s_ucreate(); 2196 if (do_ioctl(dsw_fd, DSWIOC_STAT, &prev_stat) == -1) { 2197 /* set is suspended, so we do the enable processing instead */ 2198 do_enable = 1; 2199 2200 /* first check to see whether the set was offline */ 2201 (void) snprintf(key, CFG_MAX_KEY, "ii.set%d.options", 2202 setnumber); 2203 if (!ii_lock(cfg, CFG_RDLOCK)) { 2204 dsw_error(gettext("Unable to set locking on the " 2205 "configuration"), NULL); 2206 } 2207 config_locked = 1; 2208 unlocked = 0; 2209 if (cfg_get_single_option(cfg, CFG_SEC_CONF, key, 2210 NSKERN_II_BMP_OPTION, optval, CFG_MAX_BUF) < 0) { 2211 dsw_error(gettext("unable to read config file"), NULL); 2212 } 2213 cfg_unlock(cfg); 2214 config_locked = 0; 2215 unlocked = 1; 2216 (void) sscanf(optval, "%x", &flags); 2217 if ((flags & DSW_OFFLINE) == 0) { 2218 /* set wasn't offline - don't reset */ 2219 dsw_error(gettext("Set not offline, will not reset"), 2220 NULL); 2221 } 2222 parms.status = spcs_s_ucreate(); 2223 stat = &parms.status; 2224 stat_flags = DSW_BMPOFFLINE; 2225 } else { 2226 args.status = spcs_s_ucreate(); 2227 stat = &args.status; 2228 stat_flags = prev_stat.stat; 2229 } 2230 spcs_s_ufree(&prev_stat.status); 2231 2232 if (wait_action == WaitForStart) 2233 (void) sigset(SIGCHLD, sigchild); 2234 2235 switch (child = fork()) { 2236 2237 case (pid_t)-1: 2238 dsw_error(gettext("Unable to fork"), NULL); 2239 break; 2240 2241 case 0: 2242 if (do_enable) { 2243 rc = do_ioctl(dsw_fd, DSWIOC_ENABLE, &parms); 2244 } else { 2245 rc = do_ioctl(dsw_fd, DSWIOC_RESET, &args); 2246 } 2247 if (rc == -1 && errno != DSW_EABORTED && errno != DSW_EIO) { 2248 spcs_log("ii", stat, gettext("Fail reset %s"), volume); 2249 dsw_error(gettext("Reset shadow failed"), stat); 2250 } 2251 /* last_overflow is set during find_shadow_config */ 2252 if (strlen(last_overflow) > 0 && 2253 (stat_flags & (DSW_SHDOFFLINE | DSW_BMPOFFLINE)) != 0) { 2254 /* reattach it */ 2255 (void) strncpy(parms.bitmap_vol, last_overflow, 2256 DSW_NAMELEN); 2257 do_attach(&parms); 2258 } 2259 spcs_log("ii", stat, gettext("Finish reset %s"), volume); 2260 spcs_s_ufree(stat); 2261 2262 exit(0); 2263 break; 2264 default: 2265 if (wait_action == WaitForStart) { 2266 rc = child_wait(child, CopyStart, args.shadow_vol); 2267 } else { /* wait_action == WaitForEnd */ 2268 wait_loc = 0; 2269 (void) wait(&wait_loc); 2270 if (WIFEXITED(wait_loc) && (WEXITSTATUS(wait_loc) == 0)) 2271 rc = 0; 2272 else 2273 rc = -1; 2274 } 2275 break; 2276 } 2277 /* if successful, remove flags entry from options field */ 2278 if (rc >= 0) { 2279 if (!ii_lock(cfg, CFG_WRLOCK)) { 2280 dsw_error(gettext("Unable to set locking on the " 2281 "configuration"), NULL); 2282 } 2283 config_locked = 1; 2284 if (!find_shadow_config(volume, &parms, &args)) { 2285 dsw_error(gettext("Volume is not in a Point-in-Time " 2286 "Copy group"), NULL); 2287 } 2288 (void) snprintf(key, CFG_MAX_KEY, "ii.set%d.options", 2289 setnumber); 2290 if (cfg_del_option(cfg, CFG_SEC_CONF, key, NSKERN_II_BMP_OPTION) 2291 < 0) { 2292 dsw_error(gettext("Update of config failed"), NULL); 2293 } 2294 (void) cfg_commit(cfg); 2295 cfg_unlock(cfg); 2296 config_locked = 0; 2297 } 2298 2299 return (rc); 2300 } 2301 2302 int 2303 overflow(char *volume) 2304 { 2305 dsw_ioctl_t args; 2306 int rc; 2307 spcs_s_info_t *stat; 2308 2309 check_action(gettext("Initialize this overflow volume?")); 2310 if (find_matching_cf_line(volume, NULL, &args)) 2311 dsw_error(gettext("Volume is part of a Point-in-Time Copy " 2312 "group"), NULL); 2313 args.status = spcs_s_ucreate(); 2314 (void) strncpy(args.shadow_vol, volume, DSW_NAMELEN); 2315 rc = do_ioctl(dsw_fd, DSWIOC_OCREAT, &args); 2316 if (rc == -1) { 2317 spcs_log("ii", &args.status, 2318 gettext("Create overflow failed %s"), volume); 2319 dsw_error(gettext("Create overflow failed"), &args.status); 2320 } 2321 if (rc == -1) 2322 stat = &args.status; 2323 else 2324 stat = NULL; 2325 spcs_log("ii", stat, gettext("Create overflow succeeded %s"), volume); 2326 spcs_s_ufree(&args.status); 2327 2328 return (0); 2329 } 2330 2331 void 2332 bitmap_op(char *master_volume, int print_bitmap, int bitmap_percent, int used, 2333 int is_compact) 2334 { 2335 unsigned char *bitmap; 2336 char *name; 2337 int i, x, y; 2338 unsigned j; 2339 unsigned long n; 2340 unsigned long percent; 2341 2342 bitmap = allocate_bitmap(master_volume); 2343 if (bitmap == NULL) 2344 return; 2345 2346 if (bitmap_percent) { 2347 /* count the number of bits set in bitmap */ 2348 for (i = n = 0; i < bm_size; i++) 2349 for (j = (unsigned)bitmap[i]; j; j &= j -1) 2350 n++; 2351 if (is_compact) 2352 (void) printf(gettext("Chunks in map: %d used: %d\n"), 2353 used, n); 2354 if (bm_actual < 100) { 2355 percent = 0; 2356 } else { 2357 percent = (n * 100) / bm_actual; 2358 } 2359 (void) printf(gettext("Percent of bitmap set: %u\n"), percent); 2360 percent = percent/100; 2361 /* distinguish between 0.0000% and 0.n% of bitmap set */ 2362 if (percent < 1) 2363 (void) printf("\t(%s)\n", n > 0 ? 2364 gettext("bitmap dirty") : gettext("bitmap clean")); 2365 } 2366 2367 if (print_bitmap) { 2368 name = strrchr(master_volume, '/'); 2369 if (name++ == NULL) 2370 name = master_volume; 2371 i = bm_size * 8; 2372 x = (int)ceil(sqrt((double)i)); 2373 x += (8 - (x % 8)); /* round up to nearest multiple of 8 */ 2374 y = i / x; 2375 if (y * x < i) 2376 y++; 2377 (void) printf("#define bm%s_width %d\n#define bm%s_height %d\n", 2378 name, x, name, y); 2379 (void) printf("#define bm%s_x_hot 0\n#define bm%s_y_hot 0\n", 2380 name, name); 2381 (void) printf("static char bm%s_bits[] = {\n", name); 2382 for (i = 0; i < bm_size; i++) { 2383 if (i % 12 == 0) 2384 (void) printf("\n"); 2385 (void) printf("0x%02x, ", bitmap[i]); 2386 } 2387 y = x * y; 2388 for (; i < y; i++) { 2389 if (i % 12 == 0) 2390 (void) printf("\n"); 2391 (void) printf("0x00, "); 2392 } 2393 (void) printf("\n};\n"); 2394 } 2395 2396 free_bitmap(bitmap); 2397 } 2398 2399 static int 2400 validate_group_names(char **vol_list, char *group) 2401 { 2402 ENTRY item, *found; 2403 int i, rc, count; 2404 dsw_aioctl_t *group_list; 2405 char *ptr; 2406 2407 if (group == NULL || *group == NULL) { 2408 /* no group set, just count volume list */ 2409 for (i = 0; *vol_list++ != NULL; i++) 2410 ; 2411 return (i); 2412 } 2413 2414 if ((count = do_ioctl(dsw_fd, DSWIOC_LISTLEN, NULL)) < 0) 2415 dsw_error("DSWIOC_LISTLEN", NULL); 2416 2417 group_list = malloc(sizeof (dsw_aioctl_t) + count * DSW_NAMELEN); 2418 if (group_list == NULL) 2419 dsw_error(gettext("Failed to allocate memory"), NULL); 2420 2421 bzero(group_list, sizeof (dsw_aioctl_t) + count * DSW_NAMELEN); 2422 group_list->count = count; 2423 group_list->flags = 0; 2424 group_list->status = spcs_s_ucreate(); 2425 (void) strncpy(group_list->shadow_vol, group, DSW_NAMELEN); 2426 2427 rc = do_ioctl(dsw_fd, DSWIOC_GLIST, group_list); 2428 if (rc < 0) 2429 dsw_error(gettext("Group list access failure"), 2430 &group_list->status); 2431 2432 group_list->shadow_vol[DSW_NAMELEN * group_list->count] = '\0'; 2433 2434 /* create hash and enter all volumes into it */ 2435 if (hcreate(group_list->count) == 0) 2436 dsw_error(gettext("Failed to allocate memory"), NULL); 2437 ptr = group_list->shadow_vol; 2438 count = group_list->count; 2439 i = 0; 2440 while (i < count) { 2441 ptr[ DSW_NAMELEN - 1 ] = '\0'; 2442 item.key = ptr; 2443 item.data = (void *) 0; 2444 (void) hsearch(item, ENTER); 2445 ++i; 2446 ptr += DSW_NAMELEN; 2447 } 2448 2449 /* now compare the volume list with the hash */ 2450 for (i = 0; vol_list[ i ]; i++) { 2451 item.key = vol_list[ i ]; 2452 found = hsearch(item, FIND); 2453 if (!found) 2454 dsw_error(gettext("Group config does not match kernel"), 2455 NULL); 2456 if (found->data != (void *) 0) 2457 dsw_error(gettext("Duplicate volume specified"), NULL); 2458 found->data = (void *) 1; 2459 } 2460 if (i != count) 2461 dsw_error(gettext("Group config does not match kernel"), NULL); 2462 2463 /* everything checks out */ 2464 free(group_list); 2465 hdestroy(); 2466 2467 return (count); 2468 } 2469 2470 int 2471 do_acopy(char **vol_list, enum copy_update update_mode, 2472 enum copy_direction direction) 2473 { 2474 dsw_aioctl_t *acopy_args; 2475 dsw_ioctl_t copy_args; 2476 dsw_config_t parms; 2477 dsw_stat_t stat_s; 2478 int i; 2479 int rc; 2480 int n_vols; 2481 char *t; 2482 char buf[1024]; 2483 char *sp; 2484 char *ppid; 2485 2486 n_vols = validate_group_names(vol_list, group_name); 2487 2488 acopy_args = calloc(sizeof (dsw_aioctl_t) + n_vols * DSW_NAMELEN, 1); 2489 if (acopy_args == NULL) 2490 dsw_error(gettext("Too many volumes given for update"), NULL); 2491 2492 acopy_args->count = n_vols; 2493 2494 acopy_args->flags = 0; 2495 2496 if (update_mode == Update) 2497 acopy_args->flags |= CV_BMP_ONLY; 2498 if (direction == ToMaster) 2499 acopy_args->flags |= CV_SHD2MST; 2500 if (pflg) { 2501 acopy_args->flags |= CV_LOCK_PID; 2502 #ifdef DEBUG 2503 ppid = getenv("IIADM_PPID"); 2504 if (ppid) { 2505 acopy_args->pid = atoi(ppid); 2506 (void) fprintf(stderr, "(using %s for ppid)\n", ppid); 2507 } else { 2508 acopy_args->pid = getppid(); 2509 } 2510 #else 2511 acopy_args->pid = getppid(); 2512 #endif 2513 } 2514 2515 for (i = 0; i < n_vols; i++) { 2516 if (!find_shadow_config(vol_list[i], &parms, ©_args)) 2517 dsw_error(gettext("Volume is not in a Point-in-Time " 2518 "group"), NULL); 2519 if (direction == ToMaster) { 2520 t = parms.master_vol; 2521 } else { 2522 t = parms.shadow_vol; 2523 } 2524 2525 if (mounted(t)) { 2526 errno = EBUSY; 2527 dsw_error(gettext("Target of copy/update is mounted, " 2528 "unmount it first"), NULL); 2529 } 2530 2531 (void) strncpy(stat_s.shadow_vol, parms.shadow_vol, 2532 DSW_NAMELEN); 2533 stat_s.shadow_vol[DSW_NAMELEN-1] = '\0'; 2534 stat_s.status = spcs_s_ucreate(); 2535 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &stat_s); 2536 spcs_s_ufree(&stat_s.status); 2537 if (rc == -1) { 2538 (void) sprintf(buf, 2539 gettext("Shadow group %s is suspended"), 2540 vol_list[i]); 2541 dsw_error(buf, NULL); 2542 } 2543 2544 if (stat_s.stat & DSW_COPYINGP) { 2545 (void) fprintf(stderr, "%s: %s\n", cmdnam, 2546 gettext("Copy already in progress")); 2547 exit(1); 2548 } 2549 } 2550 acopy_args->status = spcs_s_ucreate(); 2551 for (i = 0; i < n_vols; i++) { 2552 spcs_log("ii", NULL, gettext("Atomic %s %s %s"), 2553 update_mode == Update ? 2554 gettext("update") : gettext("copy"), 2555 vol_list[i], 2556 direction == ToMaster ? gettext("from shadow") : 2557 gettext("to shadow")); 2558 } 2559 if (group_name == NULL || *group_name == NULL) { 2560 sp = acopy_args->shadow_vol; 2561 for (i = 0; i < n_vols; i++, sp += DSW_NAMELEN) 2562 (void) strncpy(sp, vol_list[i], DSW_NAMELEN); 2563 } else { 2564 (void) strncpy(acopy_args->shadow_vol, group_name, DSW_NAMELEN); 2565 acopy_args->flags |= CV_IS_GROUP; 2566 } 2567 rc = do_ioctl(dsw_fd, DSWIOC_ACOPY, acopy_args); 2568 if (rc == -1) { 2569 i = acopy_args->count; 2570 if (i < 0 || i >= n_vols) { 2571 spcs_log("ii", NULL, gettext("Atomic update failed")); 2572 (void) sprintf(buf, gettext("Update failed")); 2573 } else { 2574 spcs_log("ii", NULL, 2575 gettext("Atomic update of %s failed"), 2576 vol_list[acopy_args->count]); 2577 (void) sprintf(buf, gettext("Update of %s failed"), 2578 vol_list[acopy_args->count]); 2579 } 2580 dsw_error(buf, &(acopy_args->status)); 2581 } 2582 return (rc); 2583 } 2584 2585 int 2586 do_copy(char **vol_list, enum copy_update update_mode, 2587 enum copy_direction direction, enum copy_wait wait_action) 2588 { 2589 dsw_ioctl_t copy_args; 2590 dsw_config_t parms; 2591 dsw_stat_t stat_s; 2592 int rc; 2593 int wait_loc; 2594 char *t; 2595 char *volume; 2596 pid_t child = (pid_t)0; 2597 char *ppid; 2598 2599 if (vol_list[0] && vol_list[1]) 2600 return (do_acopy(vol_list, update_mode, direction)); 2601 2602 volume = vol_list[0]; 2603 if (!find_shadow_config(volume, &parms, ©_args)) 2604 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 2605 "group"), NULL); 2606 2607 cfg_unlock(cfg); 2608 config_locked = 0; 2609 copy_args.flags = 0; 2610 2611 if (update_mode == Update) 2612 copy_args.flags |= CV_BMP_ONLY; 2613 if (direction == ToMaster) { 2614 copy_args.flags |= CV_SHD2MST; 2615 t = parms.master_vol; 2616 } else { 2617 t = parms.shadow_vol; 2618 } 2619 if (pflg) { 2620 copy_args.flags |= CV_LOCK_PID; 2621 #ifdef DEBUG 2622 ppid = getenv("IIADM_PPID"); 2623 if (ppid) { 2624 copy_args.pid = atoi(ppid); 2625 (void) fprintf(stderr, "(using %s for ppid)\n", ppid); 2626 } else { 2627 copy_args.pid = getppid(); 2628 } 2629 #else 2630 copy_args.pid = getppid(); 2631 #endif 2632 } 2633 2634 if (mounted(t)) { 2635 errno = EBUSY; 2636 dsw_error(gettext("Target of copy/update is mounted, " 2637 "unmount it first"), NULL); 2638 } 2639 2640 (void) strncpy(stat_s.shadow_vol, copy_args.shadow_vol, DSW_NAMELEN); 2641 stat_s.shadow_vol[DSW_NAMELEN-1] = '\0'; 2642 stat_s.status = spcs_s_ucreate(); 2643 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &stat_s); 2644 spcs_s_ufree(&stat_s.status); 2645 if (rc == -1) 2646 dsw_error(gettext("Shadow group suspended"), NULL); 2647 2648 if (stat_s.stat & DSW_COPYINGP) { 2649 (void) fprintf(stderr, "%s: %s\n", cmdnam, 2650 gettext("Copy already in progress")); 2651 exit(1); 2652 } 2653 2654 copy_args.status = spcs_s_ucreate(); 2655 spcs_log("ii", NULL, gettext("Start %s %s %s"), 2656 update_mode == Update ? 2657 gettext("update") : gettext("copy"), 2658 volume, 2659 direction == ToMaster ? gettext("from shadow") : 2660 gettext("to shadow")); 2661 2662 if (wait_action == WaitForStart) 2663 (void) sigset(SIGCHLD, sigchild); 2664 switch (child = fork()) { 2665 2666 case (pid_t)-1: 2667 dsw_error(gettext("Unable to fork"), 2668 NULL); 2669 break; 2670 2671 case 0: 2672 rc = do_ioctl(dsw_fd, DSWIOC_COPY, ©_args); 2673 if (rc == -1) { 2674 spcs_log("ii", ©_args.status, 2675 gettext("Fail %s %s %s"), 2676 update_mode == Update ? 2677 gettext("update") : gettext("copy"), 2678 volume, 2679 direction == ToMaster ? gettext("from shadow") 2680 : gettext("to shadow")); 2681 dsw_error(gettext("Copy failed"), ©_args.status); 2682 } 2683 spcs_s_ufree(©_args.status); 2684 spcs_log("ii", NULL, gettext("Finish %s %s %s"), 2685 update_mode == Update ? 2686 gettext("update") : gettext("copy"), 2687 volume, 2688 direction == ToMaster ? gettext("from shadow") : 2689 gettext("to shadow")); 2690 2691 exit(0); 2692 break; 2693 default: 2694 if (wait_action == WaitForStart) { 2695 rc = child_wait(child, CopyStart, copy_args.shadow_vol); 2696 } else { /* wait_action == WaitForEnd */ 2697 wait_loc = 0; 2698 (void) wait(&wait_loc); 2699 if (WIFEXITED(wait_loc) && (WEXITSTATUS(wait_loc) == 0)) 2700 rc = 0; 2701 else 2702 rc = 1; 2703 } 2704 break; 2705 } 2706 return (rc); 2707 } 2708 2709 void 2710 print_status(dsw_config_t *conf, int in_config) 2711 { 2712 dsw_stat_t args; 2713 int stat_flags; 2714 static int need_sep = 0; 2715 time_t tmp_time; 2716 2717 if (need_sep++ > 0) 2718 (void) printf("--------------------------------------" 2719 "----------------------------------------\n"); 2720 (void) strncpy(args.shadow_vol, conf->shadow_vol, DSW_NAMELEN); 2721 args.shadow_vol[DSW_NAMELEN-1] = '\0'; 2722 if (in_config) { 2723 (void) printf("%s: %s\n", 2724 conf->master_vol, gettext("(master volume)")); 2725 (void) printf("%s: %s\n", 2726 conf->shadow_vol, gettext("(shadow volume)")); 2727 (void) printf("%s: %s\n", 2728 conf->bitmap_vol, gettext("(bitmap volume)")); 2729 } 2730 2731 /* 2732 * Do special checking on the status of this volume in a Sun Cluster 2733 */ 2734 if (check_cluster() == II_CLUSTER) { 2735 char dgname[CFG_MAX_BUF], *other_node; 2736 2737 if (cfg_dgname(conf->bitmap_vol, dgname, sizeof (dgname))) { 2738 if (strlen(dgname)) { 2739 int rc = cfg_dgname_islocal(dgname, &other_node); 2740 if (rc < 0) { 2741 (void) printf(gettext( 2742 "Suspended on this node, not active elsewhere\n")); 2743 return; 2744 } else if (rc == 0) { 2745 (void) printf(gettext( 2746 "Suspended on this node, active on %s\n"), 2747 other_node); 2748 return; 2749 } 2750 } 2751 } 2752 } 2753 2754 args.status = spcs_s_ucreate(); 2755 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) { 2756 2757 /* Handle Not found or not in config */ 2758 if (errno != DSW_ENOTFOUND || !in_config) 2759 dsw_error(gettext("Stat failed"), &args.status); 2760 2761 /* Just suspend */ 2762 (void) printf(gettext("Suspended.\n")); 2763 return; 2764 } 2765 2766 if (args.overflow_vol[0] != '\0') 2767 (void) printf("%s: %s\n", args.overflow_vol, 2768 gettext("(overflow volume)")); 2769 2770 if (conf->group_name[0] != '\0') 2771 (void) printf(gettext("Group name: %s\n"), 2772 conf->group_name); 2773 2774 if (conf->cluster_tag[0] != '\0') 2775 (void) printf(gettext("Cluster tag: %s\n"), 2776 conf->cluster_tag); 2777 2778 stat_flags = args.stat; 2779 spcs_s_ufree(&args.status); 2780 if (stat_flags & DSW_GOLDEN) 2781 (void) printf(gettext("Independent copy")); 2782 else 2783 (void) printf(gettext("Dependent copy")); 2784 2785 if (stat_flags & DSW_TREEMAP) 2786 (void) printf(gettext(", compacted shadow space")); 2787 2788 if (stat_flags & DSW_COPYINGP) 2789 (void) printf(gettext(", copy in progress")); 2790 else if (stat_flags & DSW_COPYING) 2791 (void) printf(gettext(", copy not active")); 2792 2793 if (stat_flags & DSW_COPYINGM) 2794 (void) printf(gettext(", copying master to shadow")); 2795 2796 if (stat_flags & DSW_COPYINGS) 2797 (void) printf(gettext(", copying shadow to master")); 2798 2799 if (stat_flags & DSW_COPYINGX) 2800 (void) printf(gettext(", abort of copy requested")); 2801 2802 if (stat_flags & DSW_MSTOFFLINE) 2803 (void) printf(gettext(", master volume offline")); 2804 2805 if (stat_flags & DSW_SHDOFFLINE) 2806 (void) printf(gettext(", shadow volume offline")); 2807 2808 if (stat_flags & DSW_BMPOFFLINE) 2809 (void) printf(gettext(", bitmap volume offline")); 2810 2811 if (stat_flags & DSW_OVROFFLINE) 2812 (void) printf(gettext(", overflow volume offline")); 2813 2814 if (stat_flags & DSW_SHDEXPORT) 2815 (void) printf(gettext(", shadow volume exported")); 2816 2817 if (stat_flags & DSW_SHDIMPORT) 2818 (void) printf(gettext(", shadow volume imported")); 2819 2820 if (stat_flags & DSW_OVERFLOW) 2821 (void) printf(gettext(", out of space")); 2822 2823 if (stat_flags & DSW_VOVERFLOW) 2824 (void) printf(gettext(", spilled into overflow volume")); 2825 (void) printf("\n"); 2826 2827 tmp_time = args.mtime; 2828 if (tmp_time != 0) 2829 (void) printf("%s %s", gettext("Latest modified time:"), 2830 ctime(&tmp_time)); 2831 else 2832 (void) printf("%s\n", gettext("Latest modified time: unknown")); 2833 2834 (void) printf("%s %8llu\n", gettext("Volume size:"), args.size); 2835 if (args.shdsize != 0) { 2836 (void) printf("%s %lld %s %lld\n", 2837 gettext("Shadow chunks total:"), args.shdsize, 2838 gettext("Shadow chunks used:"), args.shdused); 2839 } 2840 bitmap_op(args.shadow_vol, 0, 1, 0, 0); 2841 } 2842 2843 int 2844 abort_copy(char *volume) 2845 { 2846 dsw_ioctl_t args; 2847 2848 if (!find_shadow_config(volume, NULL, &args)) 2849 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 2850 "group"), NULL); 2851 args.status = spcs_s_ucreate(); 2852 if (do_ioctl(dsw_fd, DSWIOC_ABORT, &args) == -1) 2853 dsw_error(gettext("Abort failed"), &args.status); 2854 spcs_log("ii", NULL, gettext("Abort %s"), args.shadow_vol); 2855 spcs_s_ufree(&args.status); 2856 return (0); 2857 } 2858 2859 void 2860 iiversion() 2861 { 2862 dsw_version_t args; 2863 2864 args.status = spcs_s_ucreate(); 2865 if (do_ioctl(dsw_fd, DSWIOC_VERSION, &args) == -1) 2866 dsw_error(gettext("Version failed"), &args.status); 2867 spcs_s_ufree(&args.status); 2868 #ifdef DEBUG 2869 (void) printf(gettext("Point in Time Copy version %d.%d.%d.%d\n"), 2870 args.major, args.minor, args.micro, args.baseline); 2871 #else 2872 if (args.micro) { 2873 (void) printf(gettext("Point in Time Copy version %d.%d.%d\n"), 2874 args.major, args.minor, args.micro); 2875 } else { 2876 (void) printf(gettext("Point in Time Copy version %d.%d\n"), 2877 args.major, args.minor); 2878 } 2879 #endif 2880 } 2881 2882 void 2883 list_volumes() 2884 { 2885 dsw_list_t args; 2886 int i, set, found; 2887 dsw_config_t *lp; 2888 ENTRY item, *ip; 2889 dsw_config_t parms; 2890 2891 if ((i = do_ioctl(dsw_fd, DSWIOC_LISTLEN, &args)) == -1) 2892 dsw_error("DSWIOC_LISTLEN", NULL); 2893 2894 args.status = spcs_s_ucreate(); 2895 args.list_used = 0; 2896 args.list_size = i + 4; 2897 lp = args.list = (dsw_config_t *) 2898 malloc(args.list_size * sizeof (dsw_config_t)); 2899 2900 if (args.list == NULL) 2901 dsw_error(gettext("Failed to allocate memory"), NULL); 2902 if (do_ioctl(dsw_fd, DSWIOC_LIST, &args) == -1) 2903 dsw_error(gettext("List failed"), &args.status); 2904 spcs_s_ufree(&args.status); 2905 2906 /* make a hashtable */ 2907 if (args.list_used > 0) { 2908 if (hcreate(args.list_used) == 0) { 2909 dsw_error(gettext("Failed to allocate memory"), NULL); 2910 /*NOTREACHED*/ 2911 } 2912 } 2913 2914 /* populate the hashtable */ 2915 for (i = 0; i < args.list_used; i++, lp++) { 2916 item.key = lp->shadow_vol; 2917 item.data = (char *)lp; 2918 if (hsearch(item, ENTER) == NULL) { 2919 dsw_error(gettext("Failed to allocate memory"), NULL); 2920 /*NOTREACHED*/ 2921 } 2922 } 2923 2924 /* perform action for each line of the stored config file */ 2925 for (set = 1; get_dsw_config(set, &parms) == 0; set++) { 2926 2927 /* Are there any II sets configured on this node? */ 2928 if (args.list_used > 0) { 2929 item.key = parms.shadow_vol; 2930 2931 /* Is this volume configured on this node? */ 2932 if (ip = hsearch(item, FIND)) { 2933 2934 /* Handle Imported Shadows */ 2935 /* LINTED alignment of cast ok */ 2936 lp = (dsw_config_t *)ip->data; 2937 if (strcmp(parms.master_vol, 2938 II_IMPORTED_SHADOW)) 2939 found = !(lp->flag & DSW_SHDIMPORT); 2940 else 2941 found = (lp->flag & DSW_SHDIMPORT); 2942 } 2943 else 2944 found = FALSE; 2945 } 2946 else 2947 found = FALSE; 2948 2949 if ((cfg_cluster_tag) && 2950 strcmp(cfg_cluster_tag, parms.cluster_tag)) 2951 continue; 2952 2953 if ((group_name) && strcmp(group_name, parms.group_name)) 2954 continue; 2955 2956 (void) printf("%s %.*s %.*s %.*s%s\n", 2957 (parms.flag & DSW_GOLDEN) ? "ind" : "dep", 2958 DSW_NAMELEN, parms.master_vol, 2959 DSW_NAMELEN, parms.shadow_vol, 2960 DSW_NAMELEN, parms.bitmap_vol, 2961 found ? "" : gettext(" (suspended)")); 2962 } 2963 hdestroy(); 2964 free(args.list); 2965 } 2966 2967 int 2968 wait_for_copy(char *volume) 2969 { 2970 dsw_ioctl_t parms; 2971 int rc; 2972 static int unlocked = 0; 2973 char *ppid; 2974 2975 if (unlocked && !ii_lock(cfg, CFG_RDLOCK)) { 2976 dsw_error(gettext("Unable to set locking on the configuration"), 2977 NULL); 2978 } 2979 config_locked = 1; 2980 if (!find_shadow_config(volume, NULL, &parms)) 2981 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 2982 "group"), NULL); 2983 cfg_unlock(cfg); 2984 config_locked = 0; 2985 unlocked = 1; 2986 2987 parms.status = spcs_s_ucreate(); 2988 if (pflg) { 2989 #ifdef DEBUG 2990 ppid = getenv("IIADM_PPID"); 2991 if (ppid) { 2992 parms.pid = atoi(ppid); 2993 (void) fprintf(stderr, "(using %s for ppid)\n", ppid); 2994 } else { 2995 parms.pid = (nflg) ? -1 : getppid(); 2996 } 2997 #else 2998 parms.pid = (nflg) ? -1 : getppid(); 2999 #endif 3000 parms.flags |= CV_LOCK_PID; 3001 } 3002 3003 rc = do_ioctl(dsw_fd, DSWIOC_WAIT, &parms); 3004 if (rc == -1) 3005 dsw_error(gettext("Wait failed"), &parms.status); 3006 spcs_s_ufree(&parms.status); 3007 return (0); 3008 } 3009 3010 int 3011 export(char *volume) 3012 { 3013 dsw_ioctl_t parms; 3014 dsw_config_t conf; 3015 char *old_ctag, dgname[DSW_NAMELEN]; 3016 int rc; 3017 3018 if (!find_shadow_config(volume, &conf, &parms)) 3019 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 3020 "group"), NULL); 3021 if (mounted(volume)) 3022 dsw_error(gettext("Can't export a mounted volume"), NULL); 3023 3024 /* If this is an exportable shadow in the cluster, change ctag */ 3025 if (strlen(conf.cluster_tag) && 3026 (cfg_dgname(volume, dgname, sizeof (dgname)))) { 3027 old_ctag = cfg_cluster_tag; 3028 cfg_resource(cfg, cfg_cluster_tag = strdup(dgname)); 3029 } else old_ctag = NULL; 3030 3031 if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) { 3032 dsw_error(gettext("Unable to parse config file"), NULL); 3033 } 3034 reload_vols = LD_DSVOLS | LD_SHADOWS; 3035 conform_name(&volume); 3036 3037 spcs_log("ii", NULL, gettext("Export %s"), volume); 3038 parms.status = spcs_s_ucreate(); 3039 rc = do_ioctl(dsw_fd, DSWIOC_EXPORT, &parms); 3040 if (rc == -1) 3041 dsw_error(gettext("Export failed"), &parms.status); 3042 if (perform_autosv()) { 3043 if (cfg_vol_disable(cfg, volume, cfg_cluster_tag, "ii") < 0) { 3044 dsw_error(gettext("SV-disable failed"), NULL); 3045 } 3046 (void) cfg_commit(cfg); 3047 } 3048 3049 /* restore old cluster tag, if changed */ 3050 if (old_ctag != NULL) 3051 cfg_resource(cfg, cfg_cluster_tag = old_ctag); 3052 3053 spcs_s_ufree(&parms.status); 3054 return (0); 3055 } 3056 3057 int 3058 detach(char *volume) 3059 { 3060 dsw_ioctl_t parms; 3061 int rc; 3062 3063 if (!find_shadow_config(volume, NULL, &parms)) 3064 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 3065 "group"), NULL); 3066 parms.status = spcs_s_ucreate(); 3067 rc = do_ioctl(dsw_fd, DSWIOC_ODETACH, &parms); 3068 if (rc == 0) { 3069 /* remove overflow from cfg line */ 3070 (void) sprintf(key, "ii.set%d.overflow", setnumber); 3071 if (cfg_put_cstring(cfg, key, "-", 1) < 0) { 3072 perror("cfg_put_cstring"); 3073 } 3074 (void) cfg_commit(cfg); 3075 } else { 3076 spcs_log("ii", NULL, gettext("Detach of overflow %s failed"), 3077 parms.shadow_vol); 3078 dsw_error(gettext("Failed to detach overflow volume"), 3079 &parms.status); 3080 } 3081 return (rc); 3082 } 3083 3084 static void 3085 can_disable(char *vol) 3086 { 3087 dsw_stat_t args; 3088 3089 if (mounted(vol)) { 3090 (void) strncpy(args.shadow_vol, vol, DSW_NAMELEN); 3091 args.shadow_vol[DSW_NAMELEN - 1] = '\0'; 3092 args.status = spcs_s_ucreate(); 3093 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) != -1 && 3094 (args.stat & DSW_GOLDEN) == 0) { 3095 errno = EBUSY; 3096 dsw_error(gettext("Shadow Volume is currently mounted " 3097 "and dependent on the master volume"), NULL); 3098 } 3099 spcs_s_ufree(&args.status); 3100 } 3101 } 3102 3103 static void 3104 clean_up_after_failed_disable(dsw_ioctl_t *parms) 3105 { 3106 char **p; 3107 dsw_stat_t args; 3108 3109 for (p = group_volumes; *p; p++) { 3110 (void) strncpy(args.shadow_vol, *p, DSW_NAMELEN); 3111 args.shadow_vol[DSW_NAMELEN - 1] = '\0'; 3112 args.status = spcs_s_ucreate(); 3113 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) { 3114 /* set was successfully disabled */ 3115 if (find_shadow_config(*p, NULL, NULL)) 3116 remove_iiset(setnumber, *p, 0); 3117 } 3118 spcs_s_ufree(&args.status); 3119 } 3120 3121 dsw_error(gettext("Some sets in the group failed to disable"), 3122 &parms->status); 3123 } 3124 3125 int 3126 dsw_group_or_single_disable(int argc, char *argv[]) 3127 { 3128 int rc = 0; 3129 char **p; 3130 dsw_ioctl_t parms; 3131 int flags = 0; 3132 dsw_config_t conf; 3133 int shd_exported = 0; 3134 3135 if (argc != 2) 3136 usage(gettext("Incorrect number of arguments")); 3137 3138 if (group_name) { 3139 if (find_group_members(group_name) < 1) 3140 dsw_error(gettext("Group does not exist or " 3141 "has no members"), NULL); 3142 for (p = group_volumes; *p; p++) { 3143 can_disable(*p); 3144 } 3145 3146 (void) strncpy(parms.shadow_vol, group_name, DSW_NAMELEN); 3147 if (*group_name) 3148 flags = CV_IS_GROUP; 3149 } else { 3150 if (!find_shadow_config(argv[1], &conf, &parms)) { 3151 dsw_error(gettext("Volume is not in a Point-in-Time " 3152 "Copy group"), NULL); 3153 } 3154 3155 can_disable(argv[1]); 3156 flags = 0; 3157 } 3158 3159 if (group_name && !*group_name) { 3160 /* user typed iiadm -g "" -d */ 3161 for (p = group_volumes; *p; p++) { 3162 parms.status = spcs_s_ucreate(); 3163 parms.flags = flags; 3164 (void) strncpy(parms.shadow_vol, *p, DSW_NAMELEN); 3165 rc = do_ioctl(dsw_fd, DSWIOC_DISABLE, &parms); 3166 if (rc == -1 && errno != DSW_ENOTFOUND) 3167 dsw_error(gettext("Disable failed"), 3168 &parms.status); 3169 if (!find_shadow_config(*p, NULL, NULL)) 3170 dsw_error(gettext("Volume is not in a Point-in" 3171 "-Time Copy group"), &parms.status); 3172 remove_iiset(setnumber, *p, 0); 3173 spcs_s_ufree(&parms.status); 3174 spcs_log("ii", NULL, gettext("Disabled %s"), 3175 parms.shadow_vol); 3176 } 3177 } else { 3178 if (is_exported(conf.shadow_vol)) { 3179 shd_exported = 1; 3180 } 3181 if ((strcmp(conf.master_vol, II_IMPORTED_SHADOW) == 0) && 3182 is_exported(conf.shadow_vol)) { 3183 dsw_error(gettext( 3184 "Imported shadow not disabled"), NULL); 3185 } 3186 3187 parms.status = spcs_s_ucreate(); 3188 parms.flags = flags; 3189 rc = do_ioctl(dsw_fd, DSWIOC_DISABLE, &parms); 3190 if (rc == -1 && errno != DSW_ENOTFOUND) { 3191 if (errno == DSW_EDISABLE) { 3192 /* 3193 * one or more sets within the group 3194 * couldn't disable 3195 */ 3196 clean_up_after_failed_disable(&parms); 3197 } else { 3198 dsw_error(gettext("Disable failed"), 3199 &parms.status); 3200 } 3201 } 3202 spcs_log("ii", NULL, gettext("Disabled %s"), parms.shadow_vol); 3203 } 3204 3205 3206 if (group_name && *group_name) { 3207 for (p = group_volumes; *p; p++) { 3208 if (!find_shadow_config(*p, NULL, NULL)) { 3209 /* argh! */ 3210 (void) fprintf(stderr, 3211 gettext("Volume '%s' is not " 3212 "in a Point-in-Time Copy group"), *p); 3213 } else { 3214 remove_iiset(setnumber, *p, 0); 3215 } 3216 } 3217 } else if (!group_name) { 3218 if (!find_shadow_config(argv[1], NULL, NULL)) { 3219 /* argh! */ 3220 dsw_error(gettext("Volume is not in a Point-in-Time " 3221 "Copy group"), NULL); 3222 } 3223 3224 remove_iiset(setnumber, argv[1], shd_exported); 3225 } 3226 3227 return (0); 3228 } 3229 3230 int 3231 dsw_group_or_single_op(int argc, char *argv[], int (*op)(char *)) 3232 { 3233 int rc = 0; 3234 3235 if (argc != 2) 3236 usage(gettext("Incorrect number of arguments")); 3237 3238 if (group_name) { 3239 if (find_group_members(group_name) < 1) 3240 dsw_error(gettext("Group does not exist or " 3241 "has no members"), 3242 NULL); 3243 for (; *group_volumes; group_volumes++) 3244 rc |= (*op)(*group_volumes); 3245 } else { 3246 rc = (*op)(argv[1]); 3247 } 3248 return (rc); 3249 } 3250 3251 void 3252 dsw_list_clusters(char *cluster) 3253 { 3254 dsw_aioctl_t *acopy_args; 3255 int rc, i, count; 3256 char *ptr; 3257 3258 if ((count = do_ioctl(dsw_fd, DSWIOC_LISTLEN, NULL)) < 0) 3259 dsw_error("DSWIOC_LISTLEN", NULL); 3260 3261 acopy_args = malloc(sizeof (dsw_aioctl_t) + count * DSW_NAMELEN); 3262 if (acopy_args == NULL) 3263 dsw_error(gettext("Can't get memory for list enquiry"), NULL); 3264 3265 bzero(acopy_args, sizeof (dsw_aioctl_t) + count * DSW_NAMELEN); 3266 acopy_args->count = count; 3267 acopy_args->flags = 0; 3268 acopy_args->status = spcs_s_ucreate(); 3269 if (cluster) 3270 (void) strncpy(acopy_args->shadow_vol, cluster, DSW_NAMELEN); 3271 3272 rc = do_ioctl(dsw_fd, DSWIOC_CLIST, acopy_args); 3273 if (rc == -1) 3274 dsw_error(gettext("Cluster list access failure"), 3275 &acopy_args->status); 3276 3277 acopy_args->shadow_vol[DSW_NAMELEN*acopy_args->count] = NULL; 3278 3279 if (cluster) { 3280 (void) printf(gettext("Sets in cluster resource group %s:\n"), 3281 cluster); 3282 } else { 3283 (void) printf( 3284 gettext("Currently configured resource groups\n")); 3285 } 3286 for (i = 0, ptr = acopy_args->shadow_vol; *ptr && 3287 i < acopy_args->count; i++, ptr += DSW_NAMELEN) { 3288 (void) printf(" %-64.64s\n", ptr); 3289 } 3290 } 3291 3292 void 3293 dsw_enable(int argc, char *argv[]) 3294 { 3295 if (argc != 5) 3296 usage(gettext("Incorrect number of arguments")); 3297 3298 enable(argv[1], argv[2], argv[3], argv[4]); 3299 exit(0); 3300 } 3301 3302 3303 void 3304 dsw_disable(int argc, char *argv[]) 3305 { 3306 (void) dsw_group_or_single_disable(argc, argv); 3307 exit(0); 3308 } 3309 3310 3311 void 3312 dsw_copy_to_shadow(int argc, char *argv[]) 3313 { 3314 char **volume_list; 3315 3316 if (argc != 2) 3317 usage(gettext("Incorrect number of arguments")); 3318 if (group_name == NULL) 3319 volume_list = ++argv; 3320 else { 3321 if (find_group_members(group_name) < 1) 3322 dsw_error(gettext("Group does not exist or " 3323 "has no members"), 3324 NULL); 3325 volume_list = group_volumes; 3326 } 3327 3328 exit(do_copy(volume_list, Copy, ToShadow, WaitForStart)); 3329 } 3330 3331 3332 void 3333 dsw_update_shadow(int argc, char *argv[]) 3334 { 3335 char **volume_list; 3336 3337 if (argc != 2) 3338 usage(gettext("Incorrect number of arguments")); 3339 if (group_name == NULL) 3340 volume_list = ++argv; 3341 else { 3342 if (find_group_members(group_name) < 1) 3343 dsw_error(gettext("Group does not exist or " 3344 "has no members"), 3345 NULL); 3346 volume_list = group_volumes; 3347 } 3348 3349 exit(do_copy(volume_list, Update, ToShadow, WaitForStart)); 3350 } 3351 3352 3353 void 3354 dsw_copy_to_master(int argc, char *argv[]) 3355 { 3356 char **volume_list; 3357 3358 if (argc != 2) 3359 usage(gettext("Incorrect number of arguments")); 3360 if (group_name == NULL) { 3361 volume_list = ++argv; 3362 check_action(gettext("Overwrite master with shadow volume?")); 3363 } else { 3364 check_action(gettext("Overwrite every" 3365 " master in this group with its shadow volume?")); 3366 if (find_group_members(group_name) < 1) 3367 dsw_error(gettext("Group does not exist or " 3368 "has no members"), 3369 NULL); 3370 volume_list = group_volumes; 3371 } 3372 3373 exit(do_copy(volume_list, Copy, ToMaster, WaitForStart)); 3374 } 3375 3376 3377 void 3378 dsw_update_master(int argc, char *argv[]) 3379 { 3380 char **volume_list; 3381 3382 if (argc != 2) 3383 usage(gettext("Incorrect number of arguments")); 3384 if (group_name == NULL) { 3385 volume_list = ++argv; 3386 check_action(gettext("Overwrite master with shadow volume?")); 3387 } else { 3388 check_action(gettext("Overwrite every" 3389 " master in this group with its shadow volume?")); 3390 if (find_group_members(group_name) < 1) 3391 dsw_error(gettext("Group does not exist or " 3392 "has no members"), 3393 NULL); 3394 volume_list = group_volumes; 3395 } 3396 3397 exit(do_copy(volume_list, Update, ToMaster, WaitForStart)); 3398 } 3399 3400 3401 void 3402 dsw_abort_copy(int argc, char *argv[]) 3403 { 3404 exit(dsw_group_or_single_op(argc, argv, abort_copy)); 3405 } 3406 3407 3408 void 3409 dsw_display_status(int argc, char *argv[]) 3410 { 3411 dsw_config_t parms; 3412 int in_config; 3413 3414 if (argc != 2 && argc != 1) 3415 usage(gettext("Incorrect number of arguments")); 3416 3417 /* "iiadm -i" and "iiadm -i all" are equivalent */ 3418 if (argc == 2 && strcmp("all", argv[1]) != 0) { 3419 in_config = find_shadow_config(argv[1], &parms, NULL); 3420 if (!in_config) { 3421 (void) printf(gettext( 3422 "Volume is not in configuration file\n"), NULL); 3423 (void) fflush(stdout); 3424 (void) strncpy(parms.shadow_vol, argv[1], DSW_NAMELEN); 3425 parms.shadow_vol[DSW_NAMELEN] = '\0'; 3426 } 3427 print_status(&parms, in_config); 3428 } else if (group_name) { 3429 if (find_group_members(group_name) < 1) 3430 dsw_error(gettext("Group does not exist or " 3431 "has no members"), 3432 NULL); 3433 for (; *group_volumes; group_volumes++) { 3434 in_config = find_shadow_config(*group_volumes, 3435 &parms, NULL); 3436 if (in_config) 3437 print_status(&parms, in_config); 3438 } 3439 } else { 3440 /* perform action for each line of the stored config file */ 3441 for (setnumber = 1; 3442 !get_dsw_config(setnumber, &parms); setnumber++) { 3443 switch (check_cluster()) { 3444 case II_CLUSTER: 3445 if ((cfg_cluster_tag) && 3446 (strcmp(cfg_cluster_tag, parms.cluster_tag))) 3447 continue; 3448 break; 3449 case II_CLUSTER_LCL: 3450 if (strlen(parms.cluster_tag)) 3451 continue; 3452 break; 3453 } 3454 print_status(&parms, 1); 3455 } 3456 } 3457 exit(0); 3458 } 3459 3460 void 3461 dsw_display_bitmap(int argc, char *argv[]) 3462 { 3463 dsw_config_t parms; 3464 int in_config; 3465 3466 if (argc != 2) 3467 usage(gettext("Incorrect number of arguments")); 3468 3469 in_config = find_shadow_config(argv[1], &parms, NULL); 3470 if (!in_config) { 3471 (void) printf(gettext( 3472 "Volume is not in configuration file\n"), NULL); 3473 (void) fflush(stdout); 3474 (void) strncpy(parms.master_vol, argv[1], DSW_NAMELEN); 3475 parms.master_vol[DSW_NAMELEN] = '\0'; 3476 } 3477 3478 bitmap_op(parms.shadow_vol, 1, 0, 0, 0); 3479 exit(0); 3480 } 3481 3482 3483 /*ARGSUSED*/ 3484 void 3485 dsw_version(int argc, char *argv[]) 3486 { 3487 iiversion(); 3488 exit(0); 3489 } 3490 3491 void 3492 dsw_reset(int argc, char *argv[]) 3493 { 3494 exit(dsw_group_or_single_op(argc, argv, reset)); 3495 } 3496 3497 void 3498 dsw_overflow(int argc, char *argv[]) 3499 { 3500 if (argc != 2) 3501 usage(gettext("Incorrect number of arguments")); 3502 3503 exit(overflow(argv[1])); 3504 } 3505 3506 void 3507 dsw_wait(int argc, char *argv[]) 3508 { 3509 exit(dsw_group_or_single_op(argc, argv, wait_for_copy)); 3510 } 3511 3512 /*ARGSUSED*/ 3513 void 3514 dsw_list_volumes(int argc, char *argv[]) 3515 { 3516 if (argc != 1) 3517 usage(gettext("Incorrect number of arguments")); 3518 3519 list_volumes(); 3520 exit(0); 3521 } 3522 3523 void 3524 dsw_export(int argc, char *argv[]) 3525 { 3526 if (argc != 2) 3527 usage(gettext("Incorrect number of arguments")); 3528 3529 exit(dsw_group_or_single_op(argc, argv, export)); 3530 } 3531 3532 void 3533 dsw_detach(int argc, char *argv[]) 3534 { 3535 (void) dsw_group_or_single_op(argc, argv, detach); 3536 exit(0); 3537 } 3538 3539 void 3540 import(char *shadow_volume, char *bitmap_volume) 3541 { 3542 dsw_config_t parms = {0}; 3543 int rc = 0; 3544 char shd_dg[DSW_NAMELEN]; 3545 char bmp_dg[DSW_NAMELEN]; 3546 3547 /* 3548 * If importing a shadow volume and the shadow volume is already 3549 * configured, we only support this if we are in a Sun Cluster 3550 * and the current user specified a cluster tag of -C local 3551 */ 3552 if (find_shadow_config(shadow_volume, &parms, NULL)) { 3553 dsw_error(gettext("Can't import volume on same node"), NULL); 3554 } 3555 3556 switch (check_cluster()) { 3557 case II_CLUSTER: 3558 case II_CLUSTER_LCL: 3559 (void) check_resource_group(shadow_volume); 3560 if (cfg_cluster_tag) { /* check all volumes are in same dg */ 3561 if (cfg_dgname(shadow_volume, shd_dg, DSW_NAMELEN) 3562 == NULL) 3563 dsw_error(gettext("Shadow volume not in a" 3564 " disk group"), NULL); 3565 if (cfg_dgname(bitmap_volume, bmp_dg, DSW_NAMELEN) 3566 == NULL) 3567 dsw_error(gettext("Bitmap volume not in a" 3568 " disk group"), NULL); 3569 if (strcmp(bmp_dg, shd_dg) != 0) 3570 dsw_error(gettext("Bitmap volume not in" 3571 " same disk group as shadow set members"), 3572 NULL); 3573 } 3574 break; 3575 case II_NOT_CLUSTER: 3576 /* do nothing */ 3577 break; 3578 default: 3579 dsw_error(gettext( 3580 "Unexpected return from check_cluster()"), NULL); 3581 } 3582 3583 /* Local configuration volumes */ 3584 if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) { 3585 dsw_error(gettext("Unable to parse config file"), NULL); 3586 } 3587 3588 reload_vols = LD_DSVOLS | LD_SHADOWS; 3589 conform_name(&shadow_volume); 3590 (void) strcpy(parms.master_vol, II_IMPORTED_SHADOW); 3591 (void) strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN); 3592 parms.shadow_vol[DSW_NAMELEN-1] = '\0'; 3593 (void) strncpy(parms.bitmap_vol, bitmap_volume, DSW_NAMELEN); 3594 parms.bitmap_vol[DSW_NAMELEN-1] = '\0'; 3595 parms.flag = DSW_GOLDEN; 3596 3597 spcs_log("ii", NULL, gettext("Import %s %s"), 3598 parms.shadow_vol, parms.bitmap_vol); 3599 parms.status = spcs_s_ucreate(); 3600 rc = do_ioctl(dsw_fd, DSWIOC_IMPORT, &parms); 3601 if (rc == -1) { 3602 spcs_log("ii", NULL, gettext("Import failed %s %s"), 3603 parms.shadow_vol, parms.bitmap_vol); 3604 dsw_error(gettext("Import failed"), &parms.status); 3605 } 3606 if (perform_autosv()) { 3607 if (cfg_vol_enable(cfg, shadow_volume, cfg_cluster_tag, "ii") 3608 < 0) { 3609 dsw_error(gettext("SV-enable failed"), NULL); 3610 } 3611 /* cfg_commit is called by add_cfg_entry below */ 3612 } 3613 spcs_s_ufree(&parms.status); 3614 add_cfg_entry(&parms); 3615 } 3616 3617 void 3618 dsw_import(int argc, char *argv[]) 3619 { 3620 if (argc != 3) 3621 usage(gettext("Incorrect number of arguments")); 3622 import(argv[1], argv[2]); 3623 3624 exit(0); 3625 } 3626 3627 void 3628 join(char *shadow_volume, char *bitmap_file) 3629 { 3630 dsw_ioctl_t shd; 3631 dsw_config_t conf; 3632 dsw_bitmap_t parms; 3633 int rc = 0; 3634 int size; 3635 FILE *bmpfp; 3636 uchar_t *shd_bitmap = 0; 3637 ii_header_t header; 3638 char dgname[DSW_NAMELEN]; 3639 3640 if (!find_shadow_config(shadow_volume, &conf, &shd)) 3641 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 3642 "group"), NULL); 3643 3644 /* If this is an exportable shadow in the cluster, change ctag */ 3645 if (strlen(conf.cluster_tag) && 3646 (cfg_dgname(shadow_volume, dgname, sizeof (dgname)))) 3647 cfg_resource(cfg, cfg_cluster_tag = strdup(dgname)); 3648 3649 if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) { 3650 dsw_error(gettext("Unable to parse config file"), NULL); 3651 } 3652 reload_vols = LD_DSVOLS | LD_SHADOWS; 3653 conform_name(&shadow_volume); 3654 3655 if ((bmpfp = fopen(bitmap_file, "r")) == NULL) { 3656 perror(bitmap_file); 3657 (void) fprintf(stderr, 3658 gettext("Can't open imported bitmap volume\n")); 3659 exit(1); 3660 } 3661 3662 if (fread(&header, sizeof (header), 1, bmpfp) != 1) { 3663 (void) fprintf(stderr, 3664 gettext("Can't read imported bitmap volume\n")); 3665 exit(1); 3666 } 3667 3668 /* See if this is a bitmap header */ 3669 switch (header.ii_magic) { 3670 case DSW_DIRTY: /* A copy of a enable bitmap volume */ 3671 case DSW_CLEAN: 3672 check_action(gettext("Use the never imported bitmap?")); 3673 break; 3674 case DSW_INVALID: /* A valid diskable secondary bitmap */ 3675 break; 3676 default: 3677 (void) fprintf(stderr, 3678 gettext("Secondary bitmap is not a valid bitmap volume\n")); 3679 exit(1); 3680 } 3681 3682 size = FBA_SIZE(header.ii_copyfba - header.ii_shdfba); 3683 if ((shd_bitmap = malloc(size)) == NULL) { 3684 perror("malloc"); 3685 exit(1); 3686 } 3687 3688 if (fseek(bmpfp, FBA_SIZE(header.ii_shdfba), SEEK_SET)) { 3689 perror("fseek"); 3690 exit(1); 3691 } 3692 3693 if (fread(shd_bitmap, 1, size, bmpfp) != size) { 3694 (void) fprintf(stderr, 3695 gettext("Can't read imported bitmap volume\n")); 3696 exit(1); 3697 } 3698 3699 (void) fclose(bmpfp); 3700 3701 (void) strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN); 3702 parms.shadow_vol[DSW_NAMELEN-1] = '\0'; 3703 parms.shd_bitmap = shd_bitmap; 3704 parms.shd_size = size; 3705 parms.copy_bitmap = NULL; 3706 parms.copy_size = 0; 3707 3708 spcs_log("ii", NULL, gettext("Join %s %s"), 3709 parms.shadow_vol, bitmap_file); 3710 parms.status = spcs_s_ucreate(); 3711 rc = do_ioctl(dsw_fd, DSWIOC_JOIN, &parms); 3712 if (rc == -1) { 3713 spcs_log("ii", NULL, gettext("Join failed %s %s"), 3714 parms.shadow_vol, bitmap_file); 3715 dsw_error(gettext("Join failed"), &parms.status); 3716 } 3717 if (perform_autosv()) { 3718 rc = cfg_vol_enable(cfg, shadow_volume, cfg_cluster_tag, "ii"); 3719 if (rc < 0) { 3720 dsw_error(gettext("SV-enable failed"), NULL); 3721 } 3722 (void) cfg_commit(cfg); 3723 } 3724 spcs_s_ufree(&parms.status); 3725 } 3726 3727 int 3728 params(char *shadow_volume) 3729 { 3730 char *delay = param_delay; 3731 char *unit = param_unit; 3732 dsw_copyp_t parms; 3733 int rc = 0; 3734 int get = 0; 3735 int new_delay; 3736 int new_unit; 3737 3738 (void) strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN); 3739 parms.shadow_vol[DSW_NAMELEN-1] = '\0'; 3740 if (delay == NULL || unit == NULL) { 3741 get = 1; 3742 parms.copy_delay = -1; 3743 parms.copy_unit = -1; 3744 } else { 3745 new_delay = parms.copy_delay = convert_int(delay); 3746 new_unit = parms.copy_unit = convert_int(unit); 3747 } 3748 3749 parms.status = spcs_s_ucreate(); 3750 rc = do_ioctl(dsw_fd, DSWIOC_COPYP, &parms); 3751 if (rc == -1) { 3752 (void) fprintf(stderr, 3753 gettext("Parameter ranges are delay(%d - %d), " 3754 "units(%d - %d)\n"), MIN_THROTTLE_DELAY, MAX_THROTTLE_DELAY, 3755 MIN_THROTTLE_UNIT, MAX_THROTTLE_UNIT); 3756 dsw_error(gettext("Set Copy Parameters failed"), &parms.status); 3757 } 3758 if (!get) 3759 spcs_log("ii", NULL, gettext("Changed copy parameters %s from " 3760 "%d %d to %d %d"), parms.shadow_vol, parms.copy_delay, 3761 parms.copy_unit, new_delay, new_unit); 3762 else 3763 (void) printf(gettext("volume: %s\ncopy delay: %d\ncopy unit:" 3764 " %d\n"), parms.shadow_vol, parms.copy_delay, 3765 parms.copy_unit); 3766 spcs_s_ufree(&parms.status); 3767 return (0); 3768 } 3769 3770 static void 3771 do_attach(dsw_config_t *parms) 3772 { 3773 dsw_config_t io; 3774 int rc; 3775 int check = 0; 3776 3777 spcs_log("ii", NULL, gettext("Attach %s %s"), 3778 parms->shadow_vol, parms->bitmap_vol); 3779 parms->status = spcs_s_ucreate(); 3780 rc = do_ioctl(dsw_fd, DSWIOC_OATTACH, parms); 3781 if (rc == -1) { 3782 check = 1; 3783 /* if overflow() fails, it calls dsw_error to exit */ 3784 (void) overflow(parms->bitmap_vol); 3785 } 3786 spcs_s_ufree(&parms->status); 3787 if (check == 1) { 3788 if (!find_shadow_config(parms->shadow_vol, &io, NULL)) 3789 dsw_error( 3790 gettext("Volume is not in a Point-in-Time Copy " 3791 "group"), NULL); 3792 (void) strncpy(io.bitmap_vol, parms->bitmap_vol, DSW_NAMELEN); 3793 io.bitmap_vol[DSW_NAMELEN-1] = '\0'; 3794 io.status = spcs_s_ucreate(); 3795 if (do_ioctl(dsw_fd, DSWIOC_OATTACH, &io) == -1) { 3796 spcs_log("ii", NULL, gettext("Attach failed %s %s"), 3797 io.shadow_vol, parms->bitmap_vol); 3798 dsw_error(gettext("Attach failed"), &io.status); 3799 } 3800 spcs_s_ufree(&io.status); 3801 } 3802 } 3803 3804 int 3805 attach(char *shadow_volume) 3806 { 3807 dsw_config_t parms; 3808 dsw_stat_t args; 3809 char shd_dg[DSW_NAMELEN]; 3810 char ovr_dg[DSW_NAMELEN]; 3811 3812 switch (check_cluster()) { 3813 case II_CLUSTER: 3814 case II_CLUSTER_LCL: 3815 (void) check_resource_group(shadow_volume); 3816 if (cfg_cluster_tag) { /* check all volumes are in same dg */ 3817 if (cfg_dgname(shadow_volume, shd_dg, DSW_NAMELEN) 3818 == NULL) 3819 dsw_error(gettext("Shadow volume not in a" 3820 " disk group"), NULL); 3821 if (cfg_dgname(overflow_file, ovr_dg, DSW_NAMELEN) 3822 == NULL) 3823 dsw_error(gettext("Overflow volume not in a" 3824 " disk group"), NULL); 3825 if (strcmp(ovr_dg, shd_dg) != 0) 3826 dsw_error(gettext("Overflow volume not in" 3827 " same disk group as shadow set members"), 3828 NULL); 3829 } 3830 break; 3831 case II_NOT_CLUSTER: 3832 /* do nothing */ 3833 break; 3834 default: 3835 dsw_error(gettext( 3836 "Unexpected return from check_cluster()"), NULL); 3837 } 3838 3839 /* assure that the overflow_file is not an II volume */ 3840 if (find_any_cf_line(overflow_file)) 3841 dsw_error(gettext( 3842 "Overflow volume is already in a Point-in-Time Copy " 3843 "group"), NULL); 3844 3845 /* use find_shadow_config() to find setnumber */ 3846 if (!find_shadow_config(shadow_volume, &parms, NULL)) 3847 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 3848 "group"), NULL); 3849 3850 /* can only attach an overflow volume to dependent, compact shadow */ 3851 (void) strncpy(args.shadow_vol, shadow_volume, DSW_NAMELEN); 3852 args.shadow_vol[DSW_NAMELEN-1] = '\0'; 3853 3854 args.status = spcs_s_ucreate(); 3855 if ((do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) || 3856 !(args.stat & DSW_TREEMAP)) 3857 dsw_error(gettext("Not a compact dependent shadow"), NULL); 3858 3859 /* bitmap_vol is overloaded */ 3860 (void) strncpy(parms.bitmap_vol, overflow_file, DSW_NAMELEN); 3861 parms.bitmap_vol[DSW_NAMELEN-1] = '\0'; 3862 3863 do_attach(&parms); 3864 3865 /* add overflow to cfg line */ 3866 (void) sprintf(key, "ii.set%d.overflow", setnumber); 3867 if (cfg_put_cstring(cfg, key, overflow_file, 3868 strlen(overflow_file)) < 0) { 3869 perror("cfg_put_cstring"); 3870 } 3871 (void) cfg_commit(cfg); 3872 return (0); 3873 } 3874 3875 void 3876 dsw_join(int argc, char *argv[]) 3877 { 3878 if (argc != 3) 3879 usage(gettext("Incorrect number of arguments")); 3880 3881 join(argv[1], argv[2]); 3882 exit(0); 3883 } 3884 3885 void 3886 dsw_params(int argc, char *argv[]) 3887 { 3888 if (argc != 4 && argc != 2 && argc != 0) 3889 usage(gettext("Incorrect number of arguments")); 3890 3891 if ((argc == 4) || (argc == 2)) { 3892 param_delay = argv[1]; 3893 param_unit = argv[2]; 3894 if (argc == 4) { 3895 argv[1] = argv[3]; 3896 argv[2] = NULL; 3897 } 3898 } 3899 exit(dsw_group_or_single_op(2, argv, params)); 3900 } 3901 3902 /*ARGSUSED*/ 3903 void 3904 dsw_attach(int argc, char *argv[]) 3905 { 3906 overflow_file = argv[1]; 3907 argv[1] = argv[2]; 3908 (void) dsw_group_or_single_op(2, argv, attach); 3909 exit(0); 3910 } 3911 3912 /*ARGSUSED*/ 3913 void 3914 dsw_olist(int argc, char *argv[]) 3915 { 3916 char *sp, *overflow_list, **vol; 3917 int count, i; 3918 ENTRY item, *found; 3919 char key[ CFG_MAX_KEY ], buf[ CFG_MAX_BUF ]; 3920 3921 overflow_list = get_overflow_list(); 3922 3923 /* count entries */ 3924 count = 0; 3925 for (sp = overflow_list; *sp; sp += DSW_NAMELEN) { 3926 ++count; 3927 } 3928 3929 /* create hash (adding room for suspended overflow volumes) */ 3930 if (hcreate(count + 1024) == 0) { 3931 dsw_error(gettext("Out of memory creating lookup table"), NULL); 3932 /*NOTREACHED*/ 3933 } 3934 3935 if (count > 0) { 3936 /* create memory to store copy of list */ 3937 vol = (char **)calloc(count, sizeof (char *)); 3938 if (!vol) { 3939 dsw_error( 3940 gettext("Out of memory creating lookup table"), 3941 NULL); 3942 /*NOTREACHED*/ 3943 } 3944 3945 /* fill hash */ 3946 for (i = 0, sp = overflow_list; *sp; sp += DSW_NAMELEN, i++) { 3947 3948 /* make copy of string */ 3949 vol[ i ] = (char *)malloc(DSW_NAMELEN + 1); 3950 (void) strncpy(vol[ i ], sp, DSW_NAMELEN); 3951 vol[ i ][ DSW_NAMELEN ] = '\0'; 3952 3953 item.key = vol[ i ]; 3954 item.data = (char *)0; 3955 (void) hsearch(item, ENTER); 3956 } 3957 } 3958 3959 /* loop through config file entries */ 3960 i = 0; 3961 cfg_rewind(cfg, CFG_SEC_CONF); 3962 3963 /*CONSTCOND*/ 3964 while (1) { 3965 ++i; 3966 (void) snprintf(key, CFG_MAX_KEY, "ii.set%d.overflow", i); 3967 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { 3968 break; 3969 } 3970 3971 /* has this set got an overflow volume? */ 3972 if (!*buf) { 3973 continue; 3974 } 3975 3976 /* look up overflow in hash */ 3977 item.key = buf; 3978 if (count > 0 && (found = hsearch(item, FIND)) != NULL) { 3979 if (0 == (int)found->data) { 3980 (void) printf("%s\n", buf); 3981 found->data = (char *)1; 3982 (void) hsearch(*found, ENTER); 3983 } 3984 } else { 3985 /* must be part of a suspended set */ 3986 (void) printf("%s (attached to suspended set)\n", buf); 3987 item.key = buf; 3988 item.data = (char *)1; 3989 (void) hsearch(item, ENTER); 3990 } 3991 } 3992 3993 exit(0); 3994 } 3995 3996 void 3997 dsw_ostat(int argc, char *argv[]) 3998 { 3999 dsw_ostat_t args; 4000 int stat_flags; 4001 4002 if (argc != 2) 4003 usage(gettext("Incorrect number of arguments")); 4004 4005 (void) strncpy(args.overflow_vol, argv[1], DSW_NAMELEN); 4006 args.overflow_vol[DSW_NAMELEN-1] = '\0'; 4007 4008 args.status = spcs_s_ucreate(); 4009 if (do_ioctl(dsw_fd, DSWIOC_OSTAT2, &args) == -1) 4010 dsw_error(gettext("Stat failed"), &args.status); 4011 spcs_s_ufree(&args.status); 4012 4013 if ((args.hversion >= 1) && (args.hmagic == II_OMAGIC)) { 4014 stat_flags = args.flags; 4015 if (stat_flags & IIO_CNTR_INVLD) 4016 (void) printf(gettext("Clean shutdown of volume " 4017 "sets associated with overflow volume " 4018 "did not occur.\n" 4019 "Overflow counters will be inconsistent " 4020 "until new point-in-time(s) are taken.\n")); 4021 } 4022 (void) printf(gettext("Total number of attached shadows: %d\n"), 4023 args.drefcnt); 4024 (void) printf(gettext("Number of currently attached shadows: %d\n"), 4025 args.crefcnt); 4026 (void) printf(gettext("Total number of chunks: %lld\n"), args.nchunks); 4027 (void) printf(gettext("Number of chunks ever allocated: %lld\n"), 4028 args.used); 4029 (void) printf(gettext("Number of used chunks: %lld\n"), 4030 (args.nchunks - args.unused)); 4031 (void) printf(gettext("Number of unused chunks: %lld\n"), args.unused); 4032 exit(0); 4033 } 4034 4035 /*ARGSUSED*/ 4036 void 4037 dsw_move_2_group(int argc, char *argv[]) 4038 { 4039 dsw_config_t parms; 4040 dsw_movegrp_t movegrp; 4041 grptag_t *gdata; 4042 int waserr = 0; 4043 4044 /* handle move to NULL group, or group of all spaces or tabs */ 4045 (void) strncpy(movegrp.new_group, group_name, DSW_NAMELEN); 4046 if ((strlen(group_name) == 0) || (strcspn(group_name, " \t") == 0)) { 4047 group_name = "-"; 4048 bzero(movegrp.new_group, DSW_NAMELEN); 4049 gdata = NULL; 4050 } else { 4051 /* get the ctag for this group (if any) */ 4052 gdata = (grptag_t *)nsc_lookup(volhash, group_name); 4053 } 4054 4055 movegrp.status = spcs_s_ucreate(); 4056 4057 for (++argv; *argv; argv++) { 4058 if (!find_shadow_config(*argv, &parms, NULL)) 4059 dsw_error(gettext("Volume is not in a Point-in-Time " 4060 "Copy group"), NULL); 4061 4062 /* ensure the ctag matches the group */ 4063 if (gdata && *gdata->ctag) { 4064 if (strncmp(parms.cluster_tag, gdata->ctag, 4065 DSW_NAMELEN) != 0) { 4066 (void) fprintf(stderr, "%s: %s %s %s\n", cmdnam, 4067 gettext("unable to move set"), *argv, 4068 gettext("into new group - cluster " 4069 "resource mismatch")); 4070 waserr = 1; 4071 continue; 4072 } 4073 } 4074 4075 /* move the set in the kernel */ 4076 (void) strncpy(movegrp.shadow_vol, parms.shadow_vol, 4077 DSW_NAMELEN); 4078 if (do_ioctl(dsw_fd, DSWIOC_MOVEGRP, &movegrp) < 0) 4079 dsw_error(gettext("Failed to move group in kernel"), 4080 NULL); 4081 4082 /* now update the config */ 4083 (void) sprintf(key, "ii.set%d.group", setnumber); 4084 if (cfg_put_cstring(cfg, key, group_name, 4085 strlen(group_name)) < 0) { 4086 perror("cfg_put_cstring"); 4087 } 4088 (void) cfg_commit(cfg); 4089 } 4090 spcs_s_ufree(&movegrp.status); 4091 cfg_close(cfg); 4092 exit(waserr); 4093 } 4094 4095 void 4096 dsw_list_groups() 4097 { 4098 FILE *pfp; 4099 4100 if ((pfp = popen("/usr/bin/sort -u", "w")) == NULL) { 4101 dsw_error(gettext("Can't open sort program"), NULL); 4102 } 4103 4104 (void) fflush(stdout); 4105 for (setnumber = 1; /*CSTYLED*/; setnumber++) { 4106 (void) snprintf(key, sizeof (key), "ii.set%d.group", setnumber); 4107 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) 4108 break; 4109 4110 /* skip if shadow set is not in any group */ 4111 if (strcmp(buf, "") == 0) 4112 continue; 4113 (void) fprintf(pfp, "%s\n", buf); 4114 } 4115 (void) pclose(pfp); 4116 } 4117 4118 void 4119 dsw_list_group_volumes() 4120 { 4121 FILE *pfp; 4122 4123 if (find_group_members(group_name) < 1) 4124 dsw_error(gettext("Group does not exist or has no members"), 4125 NULL); 4126 4127 if ((pfp = popen("/usr/bin/sort -u", "w")) == NULL) { 4128 dsw_error(gettext("Can't open sort program"), NULL); 4129 } 4130 4131 (void) fflush(stdout); 4132 for (; *group_volumes; group_volumes++) 4133 (void) fprintf(pfp, "%s\n", *group_volumes); 4134 (void) pclose(pfp); 4135 } 4136 4137 static void 4138 load_ii_vols(CFGFILE *cfg) 4139 { 4140 int set, entries; 4141 char *mst, *shd, *buf, **entry; 4142 char *ctag, *group; 4143 mstcount_t *mdata; 4144 shdvol_t *sdata; 4145 grptag_t *gdata; 4146 static int whinged = 0; 4147 4148 if (volhash) { 4149 return; 4150 } 4151 4152 volhash = nsc_create_hash(); 4153 cfg_rewind(cfg, CFG_SEC_CONF); 4154 entries = cfg_get_section(cfg, &entry, "ii"); 4155 for (set = 1; set <= entries; set++) { 4156 buf = entry[set - 1]; 4157 4158 /* grab master volume name */ 4159 mst = strtok(buf, " "); 4160 if (!mst) { 4161 free(buf); 4162 break; 4163 } 4164 4165 /* grab shadow, group & cnode fields */ 4166 shd = strtok(NULL, " "); 4167 (void) strtok(NULL, " "); /* bitmap */ 4168 (void) strtok(NULL, " "); /* mode */ 4169 (void) strtok(NULL, " "); /* overflow */ 4170 ctag = strtok(NULL, " "); /* cnode */ 4171 (void) strtok(NULL, " "); /* options */ 4172 group = strtok(NULL, " "); /* group */ 4173 4174 /* Fix optional tags */ 4175 if (ctag) 4176 ctag += strspn(ctag, "-"); 4177 if (group) 4178 group += strspn(group, "-"); 4179 4180 /* If cluster tags don't match, skip record */ 4181 if ((cfg_cluster_tag && strcmp(ctag, cfg_cluster_tag)) || 4182 (!cfg_cluster_tag && strlen(ctag))) { 4183 free(buf); 4184 continue; 4185 } 4186 4187 /* master volume, may be duplicates */ 4188 mdata = (mstcount_t *)nsc_lookup(volhash, mst); 4189 if (mdata) { 4190 ++mdata->count; 4191 } else { 4192 mdata = (mstcount_t *)malloc(sizeof (mstcount_t)); 4193 mdata->count = 1; 4194 (void) nsc_insert_node(volhash, mdata, mst); 4195 } 4196 4197 /* grab shadow volume name */ 4198 sdata = (shdvol_t *)malloc(sizeof (shdvol_t)); 4199 (void) strncpy(sdata->master, mst, DSW_NAMELEN); 4200 (void) nsc_insert_node(volhash, sdata, shd); 4201 4202 /* No need to continue if no groups or ctags */ 4203 if (!group || !*group || !ctag || !*ctag) { 4204 free(buf); 4205 continue; 4206 } 4207 4208 gdata = (grptag_t *)nsc_lookup(volhash, group); 4209 if (gdata) { 4210 /* group already exists - check ctag */ 4211 if (*ctag && 4212 (strncmp(ctag, gdata->ctag, DSW_NAMELEN) != 0)) { 4213 if (!whinged) { 4214 (void) printf(gettext( 4215 "Warning: multiple " 4216 "cluster resource groups " 4217 "defined within a single " 4218 "I/O group\n")); 4219 whinged = 1; 4220 } 4221 } 4222 } else { 4223 gdata = (grptag_t *)malloc(sizeof (grptag_t)); 4224 (void) strncpy(gdata->ctag, ctag, DSW_NAMELEN); 4225 (void) nsc_insert_node(volhash, gdata, group); 4226 } 4227 4228 free(buf); 4229 } 4230 4231 /* free up any leftovers */ 4232 while (set < entries) 4233 free(entry[set++]); 4234 if (entries) 4235 free(entry); 4236 } 4237 4238 static void 4239 unload_ii_vols() 4240 { 4241 nsc_remove_all(volhash, free); 4242 volhash = 0; 4243 } 4244 4245 static int 4246 perform_autosv() 4247 { 4248 static int result; 4249 static int calculated = 0; 4250 int rc; 4251 4252 #ifdef DEBUG 4253 if (getenv("II_SET_CLUSTER")) 4254 return (1); 4255 #endif 4256 4257 if (calculated) { 4258 return (result); 4259 } 4260 4261 /* 4262 * we only perform auto-sv if we're in a sun cluster or if 4263 * we're on a standalone system. I.e. we don't do auto-sv on Harry 4264 */ 4265 rc = check_cluster(); 4266 4267 if (II_NOT_CLUSTER == rc) { 4268 result = 1; 4269 } else { 4270 result = cfg_issuncluster(); 4271 } 4272 4273 calculated = 1; 4274 return (result); 4275 } 4276 4277 /* 4278 * Returns true if set has had the shadow volume exported. 4279 * Returns false if shadow volume is not exported, or set is suspended. 4280 */ 4281 static int 4282 is_exported(char *set) 4283 { 4284 dsw_stat_t args; 4285 int rc; 4286 4287 (void) strncpy(args.shadow_vol, set, DSW_NAMELEN); 4288 args.shadow_vol[DSW_NAMELEN-1] = '\0'; 4289 args.status = spcs_s_ucreate(); 4290 4291 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &args); 4292 spcs_s_ufree(&args.status); 4293 4294 if (-1 == rc) { 4295 /* set must be suspended, or being disabled */ 4296 return (0); 4297 } 4298 4299 return ((args.stat & DSW_SHDEXPORT) == DSW_SHDEXPORT); 4300 } 4301 4302 static void 4303 conform_name(char **path) 4304 { 4305 char *cfgname; 4306 int rc = cfg_get_canonical_name(cfg, *path, &cfgname); 4307 4308 if (rc < 0) { 4309 dsw_error(gettext("Unable to parse config file"), NULL); 4310 } 4311 if (rc) { 4312 (void) printf(" '%s'\n%s\n '%s'\n", *path, 4313 gettext("is currently configured as"), cfgname); 4314 check_action(gettext("Perform operation with indicated volume" 4315 " name?")); 4316 *path = cfgname; 4317 /* 4318 * NOTE: *path ought to be deallocated ('free(*path)') after 4319 * we're done with it, but since this routine is called just 4320 * before we exit, it doesn't really matter 4321 */ 4322 } 4323 } 4324 4325 /* 4326 * verify_groupname(char *, int); 4327 * 4328 * Check the group name for the following rules: 4329 * 1. The name does not start with a '-' 4330 * 2. The name does not contain any space characters as defined by 4331 * isspace(3C). 4332 * If either of these rules are broken, error immediately. The check for a 4333 * leading dash can be skipped if the 'testDash' argument is false. This is to 4334 * allow for the '-g -L' functionality. 4335 * 4336 */ 4337 static void 4338 verify_groupname(char *grp, int testDash) 4339 { 4340 int i; 4341 4342 if (testDash && grp[0] == '-') { 4343 errno = EINVAL; 4344 dsw_error(gettext("group name cannot start with a '-'"), NULL); 4345 } 4346 4347 for (i = 0; grp[i] != '\0'; i++) { 4348 if (isspace(grp[i])) { 4349 errno = EINVAL; 4350 dsw_error(gettext("group name cannot contain a space"), 4351 NULL); 4352 } 4353 } 4354 } 4355 4356 void 4357 check_iishadow(char *shadow_vol) { 4358 int i; 4359 int entries; 4360 char **entry; 4361 char *shost; 4362 char *svol; 4363 char *buf; 4364 void *librdc; 4365 4366 /* 4367 * See if librdc is around 4368 * If not, we can just return 4369 */ 4370 if (librdc = dlopen(RDC_LIB, RTLD_LAZY | RTLD_GLOBAL)) 4371 self_check = (int (*)(char *)) dlsym(librdc, "self_check"); 4372 else { 4373 return; 4374 } 4375 4376 entry = NULL; 4377 entries = cfg_get_section(cfg, &entry, "sndr"); 4378 for (i = 0; i < entries; i++) { 4379 buf = entry[i]; 4380 4381 (void) strtok(buf, " "); /* phost */ 4382 (void) strtok(NULL, " "); /* primary */ 4383 (void) strtok(NULL, " "); /* pbitmap */ 4384 shost = strtok(NULL, " "); /* shost */ 4385 svol = strtok(NULL, " "); /* secondary */ 4386 4387 if (self_check(shost) && (strcmp(shadow_vol, svol) == 0)) { 4388 free(buf); 4389 if (entries) 4390 free(entry); 4391 errno = EINVAL; 4392 dsw_error(gettext( 4393 "shadow volume is in use as SNDR secondary volume"), 4394 NULL); 4395 } 4396 free(buf); 4397 } 4398 4399 (void) dlclose(librdc); 4400 if (entries) 4401 free(entry); 4402 } 4403