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, sizeof (buf)) < 0) 883 break; 884 885 if (strcmp(group, buf)) 886 continue; 887 888 (void) snprintf(key, sizeof (key), "ii.set%d.shadow", 889 setnumber); 890 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) 891 break; 892 893 if (nmembers >= vector_len) { 894 vector_len += 10; 895 group_volumes = realloc(group_volumes, (1+vector_len) * 896 sizeof (char *)); 897 } 898 group_volumes[nmembers] = strdup(buf); 899 nmembers++; 900 } 901 if (group_volumes) 902 group_volumes[nmembers] = NULL; /* terminate list */ 903 return (nmembers); 904 } 905 906 static int 907 find_next_matching_cf_line( 908 char *volume, dsw_config_t *conf, dsw_ioctl_t *io, int next) 909 { 910 dsw_config_t config; 911 912 if (!find_next_cf_line(volume, next)) { 913 return (0); 914 } 915 916 if (conf == NULL) 917 conf = &config; 918 (void) get_dsw_config(setnumber, conf); 919 if (io) { 920 (void) strlcpy(io->shadow_vol, conf->shadow_vol, DSW_NAMELEN); 921 } 922 return (1); 923 } 924 925 int 926 find_matching_cf_line(char *volume, dsw_config_t *conf, dsw_ioctl_t *io) 927 { 928 return (find_next_matching_cf_line(volume, conf, io, 1)); 929 } 930 931 int 932 find_shadow_config(char *volume, dsw_config_t *conf, dsw_ioctl_t *io) 933 { 934 dsw_config_t *c, cf; 935 936 if (io) { 937 bzero(io, sizeof (dsw_ioctl_t)); 938 } 939 c = conf ? conf : &cf; 940 setnumber = 1; 941 /* perform action for each line of the stored config file */ 942 for ((void) snprintf(key, sizeof (key), "ii.set%d.shadow", setnumber); 943 cfg_get_cstring(cfg, key, c->shadow_vol, DSW_NAMELEN) >= 0; 944 (void) snprintf(key, sizeof (key), "ii.set%d.shadow", 945 ++setnumber)) { 946 if (strncmp(volume, c->shadow_vol, DSW_NAMELEN) == 0) { 947 (void) get_dsw_config(setnumber, c); 948 949 if (check_resource_group(c->bitmap_vol)) { 950 setnumber = 0; 951 continue; 952 } 953 954 switch (check_cluster()) { 955 case II_CLUSTER: 956 if ((cfg_cluster_tag) && 957 (strcmp(cfg_cluster_tag, c->cluster_tag))) 958 continue; 959 break; 960 case II_CLUSTER_LCL: 961 if (strlen(c->cluster_tag)) 962 continue; 963 break; 964 } 965 966 if (io) { 967 (void) strlcpy(io->shadow_vol, c->shadow_vol, 968 DSW_NAMELEN); 969 } 970 return (1); 971 } 972 } 973 return (0); 974 } 975 976 void 977 add_cfg_entry(dsw_config_t *parms) 978 { 979 /* insert the well-known fields first */ 980 (void) snprintf(buf, sizeof (buf), "%s %s %s %s", 981 parms->master_vol, parms->shadow_vol, parms->bitmap_vol, 982 (parms->flag & DSW_GOLDEN) ? "I" : "D"); 983 984 if (cfg_put_cstring(cfg, "ii", buf, strlen(buf)) >= 0) { 985 /* if we have a group name, add it */ 986 if (group_name) { 987 if (find_any_cf_line(parms->shadow_vol)) { 988 (void) sprintf(buf, "ii.set%d.group", 989 setnumber); 990 if (cfg_put_cstring(cfg, buf, 991 group_name, strlen(group_name)) < 0) 992 perror("cfg_put_cstring"); 993 } 994 else 995 perror("cfg_location"); 996 } 997 998 /* commit the record */ 999 (void) cfg_commit(cfg); 1000 } 1001 else 1002 perror("cfg_put_string"); 1003 } 1004 1005 void 1006 remove_iiset(int setno, char *shadow, int shd_exp) 1007 { 1008 mstcount_t *mdata; 1009 shdvol_t *sdata; 1010 char sn[CFG_MAX_BUF]; 1011 1012 if (perform_autosv()) { 1013 if (volhash) { 1014 unload_ii_vols(); 1015 } 1016 load_ii_vols(cfg); 1017 if (cfg_load_dsvols(cfg) < 0 || cfg_load_svols(cfg) < 0) { 1018 dsw_error(gettext("Unable to parse config file"), NULL); 1019 } 1020 1021 sdata = (shdvol_t *)nsc_lookup(volhash, shadow); 1022 if (sdata) { 1023 /* 1024 * Handle the normal cases of disabling a set that is 1025 * not an imported shadow volume 1026 */ 1027 if (strcmp(sdata->master, II_IMPORTED_SHADOW)) { 1028 /* 1029 * Handle multiple-shadows of single master 1030 */ 1031 mdata = (mstcount_t *) 1032 nsc_lookup(volhash, sdata->master); 1033 if ((mdata) && (mdata->count == 1)) { 1034 if (cfg_vol_disable(cfg, sdata->master, 1035 cfg_cluster_tag, "ii") < 0) 1036 dsw_error(gettext( 1037 "SV disable of master " 1038 "failed"), 1039 NULL); 1040 } 1041 } 1042 1043 /* 1044 * Handle disk group name of different shadow 1045 */ 1046 if (shd_exp) { 1047 /* 1048 * If shadow is exported, then do nothing 1049 */ 1050 /*EMPTY*/; 1051 } else if (cfg_cluster_tag && 1052 strcmp(cfg_cluster_tag, "") && 1053 cfg_dgname(shadow, sn, sizeof (sn)) && 1054 strlen(sn) && 1055 strcmp(sn, cfg_cluster_tag)) { 1056 /* reload disk group volumes */ 1057 cfg_resource(cfg, sn); 1058 cfg_unload_dsvols(); 1059 cfg_unload_svols(); 1060 (void) cfg_load_dsvols(cfg); 1061 (void) cfg_load_svols(cfg); 1062 if (cfg_vol_disable(cfg, shadow, sn, 1063 "ii") < 0) { 1064 dsw_error(gettext( 1065 "SV disable of shadow " 1066 "failed"), 1067 NULL); 1068 } 1069 cfg_resource(cfg, cfg_cluster_tag); 1070 } else { 1071 if (cfg_vol_disable(cfg, shadow, 1072 cfg_cluster_tag, "ii") < 0) 1073 dsw_error(gettext( 1074 "SV disable of shadow failed"), 1075 NULL); 1076 } 1077 } 1078 cfg_unload_svols(); 1079 cfg_unload_dsvols(); 1080 unload_ii_vols(); 1081 reload_vols &= ~(LD_SVOLS | LD_DSVOLS | LD_II); 1082 } 1083 1084 (void) sprintf(key, "ii.set%d", setno); 1085 if (cfg_put_cstring(cfg, key, NULL, 0) < 0) { 1086 perror("cfg_put_cstring"); 1087 } 1088 (void) cfg_commit(cfg); 1089 } 1090 1091 /* 1092 * determine if we are running in a Sun Cluster Environment 1093 */ 1094 int 1095 check_cluster() 1096 { 1097 static int is_cluster = -1; 1098 int rc; 1099 #ifdef DEBUG 1100 char *cdebug = getenv("II_SET_CLUSTER"); 1101 #endif 1102 1103 /* 1104 * If this routine was previously called, just return results 1105 */ 1106 if (is_cluster != -1) 1107 return (is_cluster); 1108 1109 /* 1110 * See if Sun Cluster was installed on this node 1111 */ 1112 #ifdef DEBUG 1113 if (cdebug) rc = atoi(cdebug); 1114 else 1115 #endif 1116 rc = cfg_iscluster(); 1117 if (rc > 0) { 1118 /* 1119 * Determine if user specified -C local 1120 */ 1121 if ((cfg_cluster_tag == NULL) || 1122 (strcmp(cfg_cluster_tag, II_LOCAL_TAG))) { 1123 /* 1124 * We're in a Sun Cluster, and no "-C local" 1125 */ 1126 is_cluster = II_CLUSTER; 1127 } else { 1128 /* 1129 * We're in a Sun Cluster, but "-C local" was specified 1130 */ 1131 is_cluster = II_CLUSTER_LCL; 1132 cfg_cluster_tag = ""; 1133 } 1134 return (is_cluster); 1135 } else if (rc == 0) { 1136 /* 1137 * Not in a Sun Cluster 1138 */ 1139 is_cluster = II_NOT_CLUSTER; 1140 return (is_cluster); 1141 } else { 1142 dsw_error(gettext("unable to ascertain environment"), NULL); 1143 /*NOTREACHED*/ 1144 } 1145 1146 /* gcc */ 1147 return (is_cluster); 1148 } 1149 1150 /* 1151 * Determine if we need to set a cfg_resource based on this volume 1152 */ 1153 static int 1154 check_resource_group(char *volume) 1155 { 1156 char diskgroup[CFG_MAX_BUF]; 1157 1158 /* 1159 * If we are in a cluster, attempt to derive a new resource group 1160 */ 1161 1162 #ifdef DEBUG 1163 if (getenv("II_SET_CLUSTER") || (check_cluster() == II_CLUSTER)) { 1164 #else 1165 if (check_cluster() == II_CLUSTER) { 1166 #endif 1167 if (check_diskgroup(volume, diskgroup)) { 1168 if (cfg_cluster_tag == NULL) { 1169 cfg_cluster_tag = strdup(diskgroup); 1170 if (cfg_cluster_tag == NULL) 1171 dsw_error(gettext( 1172 "Memory allocation failure"), NULL); 1173 cfg_resource(cfg, cfg_cluster_tag); 1174 return (1); 1175 } else { 1176 /* 1177 * Check dgname and cluster tag from -C are 1178 * the same. 1179 */ 1180 if (strcmp(diskgroup, cfg_cluster_tag) != 0) { 1181 char error_buffer[128]; 1182 (void) snprintf(error_buffer, 1183 sizeof (error_buffer), 1184 gettext("-C (%s) does not match " 1185 "disk group name (%s) for %s"), 1186 cfg_cluster_tag, 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) strlcpy(parms.shadow_vol, master_volume, DSW_NAMELEN); 1369 parms.shd_bitmap = shd_bitmap; 1370 parms.shd_size = size; 1371 parms.copy_bitmap = copy_bitmap; 1372 parms.copy_size = size; 1373 1374 return (do_ioctl(dsw_fd, DSWIOC_BITMAP, &parms)); 1375 } 1376 1377 unsigned char * 1378 allocate_bitmap(char *shadow_volume) 1379 { 1380 unsigned char *shd_bitmap; 1381 unsigned char *copy_bitmap; 1382 unsigned char *p; 1383 unsigned char *q; 1384 int i; 1385 dsw_stat_t args; 1386 int stat_flags; 1387 1388 (void) strlcpy(args.shadow_vol, shadow_volume, DSW_NAMELEN); 1389 1390 args.status = spcs_s_ucreate(); 1391 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) 1392 dsw_error(gettext("Stat failed"), &args.status); 1393 1394 stat_flags = args.stat; 1395 if (stat_flags & DSW_BMPOFFLINE) 1396 return (NULL); 1397 1398 bm_size = args.size; 1399 bm_size = (bm_size + DSW_SIZE-1) / DSW_SIZE; 1400 bm_actual = bm_size; 1401 bm_size = (bm_size + DSW_BITS-1) / DSW_BITS; 1402 spcs_s_ufree(&args.status); 1403 1404 p = shd_bitmap = (unsigned char *) malloc(bm_size); 1405 if (!shd_bitmap) { 1406 perror(gettext("malloc bitmap")); 1407 return (NULL); 1408 } 1409 1410 q = copy_bitmap = (unsigned char *) malloc(bm_size); 1411 if (!copy_bitmap) { 1412 perror(gettext("malloc bitmap")); 1413 free(shd_bitmap); 1414 return (NULL); 1415 } 1416 1417 (void) memset(shd_bitmap, 0, bm_size); 1418 (void) memset(copy_bitmap, 0, bm_size); 1419 1420 if (get_bitmap(shadow_volume, shd_bitmap, copy_bitmap, bm_size) < 0) { 1421 free(copy_bitmap); 1422 free(shd_bitmap); 1423 return (NULL); 1424 } 1425 1426 /* 1427 * "or" the copy and shadow bitmaps together to return a composite 1428 * bitmap that contains the total set of differences between the 1429 * volumes. 1430 */ 1431 for (i = bm_size; i-- > 0; /*CSTYLED*/) 1432 *p++ |= *q++; 1433 1434 free(copy_bitmap); 1435 1436 return (shd_bitmap); 1437 } 1438 1439 /* 1440 * print usage message and exit. 1441 */ 1442 void 1443 usage(char *why) 1444 { 1445 if (why) { 1446 (void) fprintf(stderr, "%s: %s\n", cmdnam, why); 1447 1448 (void) fprintf(stderr, "%s\n", 1449 gettext("\nBrief summary:")); 1450 (void) fprintf(stderr, "%s\n", 1451 gettext("\t-e {ind|dep} master_vol shadow_vol " 1452 "bitmap_vol")); 1453 (void) fprintf(stderr, "%s\n", 1454 gettext("\t-[cu {s|m}] volume_set")); 1455 (void) fprintf(stderr, "%s\n", 1456 gettext("\t-i all")); 1457 (void) fprintf(stderr, "%s\n", 1458 gettext("\t-[adDEilPRw] volume_set")); 1459 (void) fprintf(stderr, "%s\n", 1460 gettext("\t-g group_name [options]")); 1461 (void) fprintf(stderr, "%s\n", 1462 gettext("\t-C cluster_tag [options]")); 1463 (void) fprintf(stderr, "%s\n", 1464 gettext("\t-[hilLv]")); 1465 (void) fprintf(stderr, "%s\n", 1466 gettext("\t-[IJ] volume_set bitmap")); 1467 (void) fprintf(stderr, "%s\n", 1468 gettext("\t-A overflow_vol volume_set")); 1469 (void) fprintf(stderr, "%s\n", 1470 gettext("\t-[OQ] overflow_vol")); 1471 (void) fprintf(stderr, "%s\n", 1472 gettext("\t-P {delay} {units} volume_set")); 1473 1474 /* assume we came here due to a user mistake */ 1475 exit(1); 1476 /* NOTREACHED */ 1477 } else { 1478 1479 (void) fprintf(stdout, "%s\n", 1480 gettext("Point-in-Time Copy Administrator CLI options")); 1481 (void) fprintf(stdout, "%s\n", 1482 gettext("Usage summary:")); 1483 (void) fprintf(stdout, "%s\n", 1484 gettext("\t-e ind m s b\tenable independent master shadow " 1485 "bitmap")); 1486 (void) fprintf(stdout, "%s\n", 1487 gettext("\t-e dep m s b\tenable dependent master shadow " 1488 "bitmap")); 1489 if (check_cluster() == II_CLUSTER) 1490 (void) fprintf(stdout, "%s\n", 1491 gettext("\t-ne ind m s b\tenable exportable master " 1492 "shadow bitmap")); 1493 (void) fprintf(stdout, "%s\n", 1494 gettext("\t-d v\t\tdisable volume")); 1495 (void) fprintf(stdout, "%s\n", 1496 gettext("\t-u s v\t\tupdate shadow volume")); 1497 (void) fprintf(stdout, "%s\n", 1498 gettext("\t-u m v\t\tupdate master volume")); 1499 (void) fprintf(stdout, "%s\n", 1500 gettext("\t-c s v\t\tcopy to shadow volume")); 1501 (void) fprintf(stdout, "%s\n", 1502 gettext("\t-c m v\t\tcopy to master volume")); 1503 (void) fprintf(stdout, "%s\n", 1504 gettext("\t-a v\t\tabort copy volume")); 1505 (void) fprintf(stdout, "%s\n", 1506 gettext("\t-w v\t\twait volume")); 1507 (void) fprintf(stdout, "%s\n", 1508 gettext("\t-i v\t\tdisplay volume status")); 1509 (void) fprintf(stdout, "%s\n", 1510 gettext("\t-i all\t\tdisplay all volume status")); 1511 (void) fprintf(stdout, "%s\n", 1512 gettext("\t-l\t\tlist all volumes")); 1513 (void) fprintf(stdout, "%s\n", 1514 gettext("\t-R v\t\treset volume")); 1515 (void) fprintf(stdout, "%s\n", 1516 gettext("\t-A o v\t\tattach overflow to volume")); 1517 (void) fprintf(stdout, "%s\n", 1518 gettext("\t-D v\t\tdetach overflow from volume")); 1519 (void) fprintf(stdout, "%s\n", 1520 gettext("\t-L\t\tlist all overflow volumes")); 1521 (void) fprintf(stdout, "%s\n", 1522 gettext("\t-O o\t\tinitialize overflow")); 1523 (void) fprintf(stdout, "%s\n", 1524 gettext("\t-Q o\t\tquery status of overflow")); 1525 (void) fprintf(stdout, "%s\n", 1526 gettext("\t-E v\t\texport shadow volume")); 1527 (void) fprintf(stdout, "%s\n", 1528 gettext("\t-I v b\t\timport volume bitmap")); 1529 (void) fprintf(stdout, "%s\n", 1530 gettext("\t-J v b\t\tjoin volume bitmap")); 1531 (void) fprintf(stdout, "%s\n", 1532 gettext("\t-P d u v\tset copy delay/units for volume")); 1533 (void) fprintf(stdout, "%s\n", 1534 gettext("\t-P v\t\tget copy delay/units for volume")); 1535 (void) fprintf(stdout, "%s\n", 1536 gettext("\t-C tag\t\tcluster resource tag")); 1537 #ifdef DEBUG 1538 (void) fprintf(stdout, "%s\n", 1539 gettext("\t-b v\t\tdisplay bitmap volume")); 1540 (void) fprintf(stdout, "%s\n", 1541 gettext("\t-f f\t\tuse private configuration file")); 1542 #endif 1543 (void) fprintf(stdout, "%s\n", 1544 gettext("\t-v\t\tprint software versions")); 1545 (void) fprintf(stdout, "%s\n", 1546 gettext("\t-n\t\tperform action without question")); 1547 (void) fprintf(stdout, "%s\n", 1548 gettext("\t-p [-c|-u] {m|s}" 1549 "enable PID locking on copy or update")); 1550 (void) fprintf(stdout, "%s\n", 1551 gettext("\t-p -w v\t\tdisable PID locking")); 1552 (void) fprintf(stdout, "%s\n", 1553 gettext("\t-h\t\tiiadm usage summary")); 1554 (void) fprintf(stdout, "%s\n", 1555 gettext("\nUsage summary for options that support " 1556 "grouping (-g g):")); 1557 (void) fprintf(stdout, "%s\n", 1558 gettext("\t-g g -e ind m s b group enable independent " 1559 "master shadow bitmap")); 1560 (void) fprintf(stdout, "%s\n", 1561 gettext("\t-g g -e dep m s b group enable dependent " 1562 "master shadow bitmap")); 1563 (void) fprintf(stdout, "%s\n", 1564 gettext("\t-g g -d\t\tdisable group")); 1565 (void) fprintf(stdout, "%s\n", 1566 gettext("\t-g g -u s\tupdate shadow for all volumes in " 1567 "group")); 1568 (void) fprintf(stdout, "%s\n", 1569 gettext("\t-g g -u m\tupdate master for all volumes in " 1570 "group")); 1571 (void) fprintf(stdout, "%s\n", 1572 gettext("\t-g g -c s\tcopy to shadow for all volumes in " 1573 "group")); 1574 (void) fprintf(stdout, "%s\n", 1575 gettext("\t-g g -c m\tcopy to master for all volumes in " 1576 "group")); 1577 (void) fprintf(stdout, "%s\n", 1578 gettext("\t-g g -a\t\tabort copy for all volumes in " 1579 "group")); 1580 (void) fprintf(stdout, "%s\n", 1581 gettext("\t-g g -w\t\twait for all volumes in group")); 1582 (void) fprintf(stdout, "%s\n", 1583 gettext("\t-g g -i\t\tdisplay status of all volumes in " 1584 "group")); 1585 (void) fprintf(stdout, "%s\n", 1586 gettext("\t-g g -l\t\tlist all volumes in group")); 1587 (void) fprintf(stdout, "%s\n", 1588 gettext("\t-g -L\t\tlist all groups")); 1589 (void) fprintf(stdout, "%s\n", 1590 gettext("\t-g g -m v v\tmove one or more volumes into " 1591 "group")); 1592 (void) fprintf(stdout, "%s\n", 1593 gettext("\t-g \"\" -m v\tremove volume from group")); 1594 (void) fprintf(stdout, "%s\n", 1595 gettext("\t-g g -R\t\treset all volumes in group")); 1596 (void) fprintf(stdout, "%s\n", 1597 gettext("\t-g g -A o\tattach overflow to all volumes in " 1598 "group")); 1599 (void) fprintf(stdout, "%s\n", 1600 gettext("\t-g g -D\t\tdetach overflow from all volumes in " 1601 "group")); 1602 (void) fprintf(stdout, "%s\n", 1603 gettext("\t-g g -E\t\texport shadow volume for all " 1604 "volumes in group")); 1605 (void) fprintf(stdout, "%s\n", 1606 gettext("\t-g g -P d u\tset copy delay/units for all " 1607 "volumes in group")); 1608 (void) fprintf(stdout, "%s\n", 1609 gettext("\t-g g -P\t\tget copy delay/units for all " 1610 "volumes in group")); 1611 (void) fprintf(stdout, "%s\n", 1612 gettext("\nLegend summary:")); 1613 (void) fprintf(stdout, "%s\n", 1614 gettext("\tind\t\tindependent volume set")); 1615 (void) fprintf(stdout, "%s\n", 1616 gettext("\tdep\t\tdependent volume set")); 1617 (void) fprintf(stdout, "%s\n", 1618 gettext("\tall\t\tall configured volumes")); 1619 (void) fprintf(stdout, "%s\n", 1620 gettext("\tm\t\tmaster volume")); 1621 (void) fprintf(stdout, "%s\n", 1622 gettext("\ts\t\tshadow volume")); 1623 (void) fprintf(stdout, "%s\n", 1624 gettext("\tv\t\tshadow volume (reference name)")); 1625 (void) fprintf(stdout, "%s\n", 1626 gettext("\to\t\toverflow volume")); 1627 (void) fprintf(stdout, "%s\n", 1628 gettext("\tb\t\tbitmap volume")); 1629 #ifdef DEBUG 1630 (void) fprintf(stdout, "%s\n", 1631 gettext("\tf\t\tconfiguration file name")); 1632 #endif 1633 (void) fprintf(stdout, "%s\n", 1634 gettext("\td\t\tdelay tick interval")); 1635 (void) fprintf(stdout, "%s\n", 1636 gettext("\tu\t\tunit size")); 1637 (void) fprintf(stdout, "%s\n", 1638 gettext("\tg\t\tgroup name")); 1639 1640 /* assume we came here because user request help text */ 1641 exit(0); 1642 /* NOTREACHED */ 1643 } 1644 1645 } 1646 1647 static char yeschr[MAX_LINE_SIZE + 2]; 1648 static char nochr[MAX_LINE_SIZE + 2]; 1649 1650 static int 1651 yes(void) 1652 { 1653 int i, b; 1654 char ans[MAX_LINE_SIZE + 1]; 1655 1656 for (i = 0; /*CSTYLED*/; i++) { 1657 b = getchar(); 1658 if (b == '\n' || b == '\0' || b == EOF) { 1659 if (i < MAX_LINE_SIZE) 1660 ans[i] = 0; 1661 break; 1662 } 1663 if (i < MAX_LINE_SIZE) 1664 ans[i] = b; 1665 } 1666 if (i >= MAX_LINE_SIZE) { 1667 i = MAX_LINE_SIZE; 1668 ans[MAX_LINE_SIZE] = 0; 1669 } 1670 if ((i == 0) || (strncmp(yeschr, ans, i))) { 1671 if (strncmp(nochr, ans, i) == 0) 1672 return (0); 1673 else if (strncmp(yeschr, ans, i) == 0) 1674 return (1); 1675 else { 1676 (void) fprintf(stderr, "%s %s/%s\n", 1677 gettext("You have to respond with"), 1678 yeschr, nochr); 1679 return (2); 1680 } 1681 } 1682 return (1); 1683 } 1684 1685 static int 1686 convert_int(char *str) 1687 { 1688 int result, rc; 1689 char *buf; 1690 1691 buf = (char *)calloc(strlen(str) + 256, sizeof (char)); 1692 rc = sscanf(str, "%d%s", &result, buf); 1693 1694 if (rc != 1) { 1695 (void) sprintf(buf, gettext("'%s' is not a valid number"), str); 1696 /* dsw_error calls exit which frees 'buf' */ 1697 errno = EINVAL; 1698 dsw_error(buf, NULL); 1699 } 1700 free(buf); 1701 1702 return (result); 1703 } 1704 1705 void 1706 check_action(char *will_happen) 1707 { 1708 int answer; 1709 1710 if (nflg || !isatty(fileno(stdin))) 1711 return; 1712 (void) strncpy(yeschr, nl_langinfo(YESSTR), MAX_LINE_SIZE + 1); 1713 (void) strncpy(nochr, nl_langinfo(NOSTR), MAX_LINE_SIZE + 1); 1714 1715 /*CONSTCOND*/ 1716 while (1) { 1717 (void) printf("%s %s/%s ", will_happen, yeschr, nochr); 1718 answer = yes(); 1719 if (answer == 1 || answer == 0) 1720 break; 1721 } 1722 if (answer == 1) 1723 return; 1724 exit(1); 1725 } 1726 1727 enum child_event {Status, CopyStart}; 1728 1729 /* 1730 * Wait for child process to get to some state, where some state may be: 1731 * 1732 * Status Set up the shadow enough so that it responds 1733 * to status requests. 1734 * CopyStart Start copy/update operations. 1735 */ 1736 1737 int 1738 child_wait(pid_t child, enum child_event event, char *volume) 1739 { 1740 dsw_stat_t args; 1741 int rc; 1742 1743 (void) strlcpy(args.shadow_vol, volume, DSW_NAMELEN); 1744 1745 for (; dead_child != child; (void) sleep(1)) { 1746 1747 /* poll shadow group with a status ioctl() */ 1748 args.status = spcs_s_ucreate(); 1749 errno = 0; 1750 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &args); 1751 1752 spcs_s_ufree(&args.status); 1753 1754 if (event == Status) { 1755 /* keep polling while we fail with DSW_ENOTFOUND */ 1756 if (rc != -1 || errno != DSW_ENOTFOUND) 1757 return (0); 1758 } else { 1759 /* event == CopyStart */ 1760 if (rc == -1) { 1761 return (1); /* something wrong */ 1762 } 1763 if (args.stat & DSW_COPYINGP) 1764 return (0); /* copying underway */ 1765 } 1766 } 1767 /* child died */ 1768 if (WIFEXITED(dead_stat)) 1769 return (WEXITSTATUS(dead_stat)); 1770 else 1771 return (1); 1772 } 1773 1774 int 1775 mounted(char *t) 1776 { 1777 int rdsk; 1778 int i; 1779 FILE *mntfp; 1780 struct mnttab mntref; 1781 struct mnttab mntent; 1782 char target[DSW_NAMELEN]; 1783 char *s; 1784 1785 rdsk = i = 0; 1786 for (s = target; i < DSW_NAMELEN && (*s = *t++); i++) { 1787 if (*s == 'r' && rdsk == 0) 1788 rdsk = 1; 1789 else 1790 s++; 1791 } 1792 *s = '\0'; 1793 1794 mntref.mnt_special = target; 1795 mntref.mnt_mountp = NULL; 1796 mntref.mnt_fstype = NULL; 1797 mntref.mnt_mntopts = NULL; 1798 mntref.mnt_time = NULL; 1799 1800 if ((mntfp = fopen("/etc/mnttab", "r")) == NULL) { 1801 dsw_error(gettext("Can not check volume against mount table"), 1802 NULL); 1803 } 1804 if (getmntany(mntfp, &mntent, &mntref) != -1) { 1805 /* found something before EOF */ 1806 (void) fclose(mntfp); 1807 return (1); 1808 } 1809 (void) fclose(mntfp); 1810 return (0); 1811 } 1812 1813 void 1814 enable(char *master_volume, char *shadow_volume, 1815 char *bitmap_volume, char *copy_type) 1816 { 1817 dsw_config_t parms; 1818 dsw_ioctl_t temp; 1819 char *p; 1820 int rc; 1821 pid_t child; 1822 spcs_s_info_t *sp_info; 1823 struct stat mstat, sstat, bstat; 1824 char mst_dg[DSW_NAMELEN] = {0}; 1825 char shd_dg[DSW_NAMELEN] = {0}; 1826 char bmp_dg[DSW_NAMELEN] = {0}; 1827 int mvol_enabled; 1828 char *altname; 1829 grptag_t *gdata; 1830 1831 bzero(&parms, sizeof (dsw_config_t)); 1832 1833 if (strcmp(copy_type, "independent") == 0 || 1834 strcmp(copy_type, gettext("independent")) == 0) 1835 parms.flag = DSW_GOLDEN; 1836 else if (strcmp(copy_type, "dependent") == 0 || 1837 strcmp(copy_type, gettext("dependent")) == 0) 1838 parms.flag = 0; 1839 else 1840 dsw_error(gettext("don't understand shadow type"), NULL); 1841 1842 /* validate volume names */ 1843 if (perform_autosv()) { 1844 if (cfg_load_svols(cfg) < 0 || cfg_load_dsvols(cfg) < 0 || 1845 cfg_load_shadows(cfg) < 0) { 1846 dsw_error(gettext("Unable to parse config file"), NULL); 1847 } 1848 load_ii_vols(cfg); 1849 reload_vols = LD_SVOLS | LD_DSVOLS | LD_SHADOWS | LD_II; 1850 1851 /* see if it's been used before under a different name */ 1852 conform_name(&master_volume); 1853 conform_name(&shadow_volume); 1854 rc = cfg_get_canonical_name(cfg, bitmap_volume, &altname); 1855 if (rc < 0) { 1856 dsw_error(gettext("Unable to parse config file"), NULL); 1857 } 1858 if (rc) { 1859 errno = EBUSY; 1860 dsw_error(gettext("Bitmap in use"), NULL); 1861 } 1862 } 1863 1864 /* 1865 * If not local, determine disk group names for volumes in II set 1866 */ 1867 switch (check_cluster()) { 1868 case II_CLUSTER: 1869 /* 1870 * Check if none or all volumes are in a disk group 1871 */ 1872 rc = 0; 1873 if (check_diskgroup(master_volume, mst_dg)) rc++; 1874 if (check_diskgroup(shadow_volume, shd_dg)) rc++; 1875 if (check_diskgroup(bitmap_volume, bmp_dg)) rc++; 1876 if ((rc != 0) && (rc != 3)) 1877 dsw_error(gettext( 1878 "Not all Point-in-Time Copy volumes are " 1879 "in a disk group"), NULL); 1880 1881 /* 1882 * If volumes are not in a disk group, but are in a 1883 * cluster, then "-C <tag>", must be set 1884 */ 1885 if (rc == 0 && cfg_cluster_tag == NULL) 1886 dsw_error(gettext( 1887 "Point-in-Time Copy volumes, that are not " 1888 "in a device group which has been " 1889 "registered with SunCluster, " 1890 "require usage of \"-C\""), NULL); 1891 1892 /* 1893 * the same disk group 1894 * If -n, plus mst_dg==bmp_dg, then allow E/I/J in SunCluster 1895 */ 1896 if ((strcmp(mst_dg, bmp_dg)) || 1897 (strcmp(mst_dg, shd_dg) && (!nflg))) 1898 dsw_error(gettext( 1899 "Volumes are not in same disk group"), NULL); 1900 1901 /* 1902 * Can never enable the same shadow twice, regardless of 1903 * exportable shadow device group movement 1904 */ 1905 if (find_shadow_line(shadow_volume)) 1906 dsw_error(gettext( 1907 "Shadow volume is already configured"), NULL); 1908 1909 /* 1910 * Groups cannot span multiple clusters 1911 */ 1912 if (group_name && perform_autosv()) { 1913 gdata = (grptag_t *)nsc_lookup(volhash, group_name); 1914 if (gdata && 1915 strncmp(gdata->ctag, mst_dg, DSW_NAMELEN) != 0) { 1916 errno = EINVAL; 1917 dsw_error(gettext("Group contains sets not " 1918 "in the same cluster resource"), NULL); 1919 } 1920 } 1921 1922 /* 1923 * Check cluster tag and bitmap disk group 1924 * set latter if different 1925 */ 1926 if (check_resource_group(bitmap_volume)) { 1927 /* 1928 * Unload and reload in the event cluster tag has 1929 * changed 1930 */ 1931 if (perform_autosv()) { 1932 unload_ii_vols(); 1933 cfg_unload_shadows(); 1934 cfg_unload_dsvols(); 1935 cfg_unload_svols(); 1936 if (cfg_load_svols(cfg) < 0 || 1937 cfg_load_dsvols(cfg) < 0 || 1938 cfg_load_shadows(cfg) < 0) { 1939 dsw_error(gettext( 1940 "Unable to parse config " 1941 "file"), NULL); 1942 } 1943 load_ii_vols(cfg); 1944 } 1945 } 1946 /* 1947 * Copy cluster name into config 1948 */ 1949 (void) strncpy(parms.cluster_tag, cfg_cluster_tag, DSW_NAMELEN); 1950 break; 1951 1952 case II_CLUSTER_LCL: 1953 /* ensure that the -C local won't interfere with the set */ 1954 if (group_name && perform_autosv()) { 1955 gdata = (grptag_t *)nsc_lookup(volhash, group_name); 1956 if (gdata) { 1957 if (strlen(gdata->ctag) != 0) { 1958 errno = EINVAL; 1959 dsw_error(gettext("Unable to put set " 1960 "into -C local and specified " 1961 "group"), NULL); 1962 } 1963 } 1964 } 1965 break; 1966 } 1967 1968 /* 1969 * If we've got a group name, add it into the config 1970 */ 1971 if (group_name) { 1972 (void) strncpy(parms.group_name, group_name, DSW_NAMELEN); 1973 } 1974 1975 /* 1976 * Determine accessability of volumes 1977 */ 1978 if (stat(master_volume, &mstat) != 0) 1979 dsw_error(gettext( 1980 "Unable to access master volume"), NULL); 1981 if (!S_ISCHR(mstat.st_mode)) 1982 dsw_error(gettext( 1983 "Master volume is not a character device"), NULL); 1984 /* check the shadow_vol hasn't be used as SNDR secondary vol */ 1985 check_iishadow(shadow_volume); 1986 if (stat(shadow_volume, &sstat) != 0) 1987 dsw_error(gettext( 1988 "Unable to access shadow volume"), NULL); 1989 if (!S_ISCHR(sstat.st_mode)) 1990 dsw_error(gettext( 1991 "Shadow volume is not a character device"), NULL); 1992 if (mounted(shadow_volume)) { 1993 errno = EBUSY; 1994 dsw_error(gettext( 1995 "Shadow volume is mounted, unmount it first"), NULL); 1996 } 1997 if (mstat.st_rdev == sstat.st_rdev) { 1998 errno = EINVAL; 1999 dsw_error(gettext( 2000 "Master and shadow are the same device"), NULL); 2001 } 2002 if (stat(bitmap_volume, &bstat) != 0) { 2003 dsw_error(gettext("Unable to access bitmap"), NULL); 2004 } 2005 if (!S_ISCHR(bstat.st_mode)) 2006 dsw_error(gettext( 2007 "Bitmap volume is not a character device"), NULL); 2008 if (S_ISCHR(bstat.st_mode)) { 2009 if (mstat.st_rdev == bstat.st_rdev) { 2010 errno = EINVAL; 2011 dsw_error(gettext( 2012 "Master and bitmap are the same device"), NULL); 2013 } else if (sstat.st_rdev == bstat.st_rdev) { 2014 errno = EINVAL; 2015 dsw_error(gettext( 2016 "Shadow and bitmap are the same device"), NULL); 2017 } 2018 } 2019 2020 (void) strncpy(parms.master_vol, master_volume, DSW_NAMELEN); 2021 (void) strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN); 2022 (void) strncpy(parms.bitmap_vol, bitmap_volume, DSW_NAMELEN); 2023 errno = 0; 2024 parms.status = spcs_s_ucreate(); 2025 2026 /* 2027 * Check that none of the member volumes forms part of another 2028 * InstantImage group. 2029 * 2030 * -- this check has been removed; it is done in the kernel instead 2031 * -- PJW 2032 */ 2033 2034 /* 2035 * Check against overflow volumes 2036 */ 2037 for (p = get_overflow_list(); *p != NULL; p += DSW_NAMELEN) { 2038 if (strncmp(master_volume, p, DSW_NAMELEN) == 0) 2039 dsw_error(gettext( 2040 "Master volume is already an overflow volume"), 2041 NULL); 2042 else if (strncmp(shadow_volume, p, DSW_NAMELEN) == 0) 2043 dsw_error(gettext( 2044 "Shadow volume is already an overflow volume"), 2045 NULL); 2046 else if (strncmp(bitmap_volume, p, DSW_NAMELEN) == 0) 2047 dsw_error(gettext( 2048 "Bitmap volume is already an overflow volume"), 2049 NULL); 2050 } 2051 2052 /* 2053 * Make sure that the shadow volume is not already configured 2054 */ 2055 if (find_shadow_config(shadow_volume, NULL, &temp)) 2056 dsw_error(gettext( 2057 "Shadow volume is already configured"), NULL); 2058 if (perform_autosv()) { 2059 /* 2060 * parse the dsvol entries to see if we need to place 2061 * the master or shadow under SV control 2062 */ 2063 if (nsc_lookup(volhash, master_volume) == NULL) { 2064 if (cfg_vol_enable(cfg, master_volume, cfg_cluster_tag, 2065 "ii") < 0) { 2066 dsw_error( 2067 gettext("Cannot enable master volume"), 2068 NULL); 2069 } 2070 mvol_enabled = 1; 2071 } else { 2072 mvol_enabled = 0; 2073 } 2074 if (nsc_lookup(volhash, shadow_volume) == NULL) { 2075 if (nflg) { 2076 cfg_resource(cfg, shd_dg); 2077 rc = cfg_vol_enable(cfg, shadow_volume, 2078 shd_dg, "ii"); 2079 cfg_resource(cfg, cfg_cluster_tag); 2080 } else { 2081 rc = cfg_vol_enable(cfg, shadow_volume, 2082 cfg_cluster_tag, "ii"); 2083 } 2084 if (rc < 0) { 2085 if (mvol_enabled) { 2086 if (cfg_vol_disable(cfg, 2087 master_volume, cfg_cluster_tag, 2088 "ii") < 0) 2089 dsw_error(gettext( 2090 "SV disable of master " 2091 "failed"), 2092 NULL); 2093 } 2094 dsw_error( 2095 gettext("Cannot enable shadow volume"), 2096 NULL); 2097 } 2098 } 2099 unload_ii_vols(); 2100 cfg_unload_shadows(); 2101 cfg_unload_dsvols(); 2102 cfg_unload_svols(); 2103 reload_vols = 0; 2104 } 2105 2106 add_cfg_entry(&parms); 2107 cfg_unlock(cfg); 2108 config_locked = 0; 2109 2110 (void) sigset(SIGCHLD, sigchild); 2111 switch (child = fork()) { 2112 2113 case (pid_t)-1: 2114 dsw_error(gettext("Unable to fork"), NULL); 2115 break; 2116 2117 case 0: 2118 rc = do_ioctl(dsw_fd, DSWIOC_ENABLE, &parms); 2119 if (rc == -1 && errno != DSW_EABORTED && errno != DSW_EIO) { 2120 /* 2121 * Failed to enable shadow group, log problem and remove 2122 * the shadow group from the config file. 2123 */ 2124 spcs_log("ii", &parms.status, 2125 gettext("Enable failed %s %s %s (%s)"), 2126 master_volume, shadow_volume, bitmap_volume, 2127 parms.flag & DSW_GOLDEN ? 2128 "independent" : "dependent"); 2129 2130 if (!ii_lock(cfg, CFG_WRLOCK) || 2131 !find_shadow_config(shadow_volume, NULL, &temp)) { 2132 dsw_error(gettext( 2133 "Enable failed, can't tidy up cfg"), 2134 &parms.status); 2135 } 2136 config_locked = 1; 2137 remove_iiset(setnumber, shadow_volume, 0); 2138 dsw_error(gettext("Enable failed"), &parms.status); 2139 } 2140 2141 if (rc == -1) 2142 sp_info = &parms.status; 2143 else 2144 sp_info = NULL; 2145 spcs_log("ii", sp_info, gettext("Enabled %s %s %s (%s)"), 2146 master_volume, shadow_volume, bitmap_volume, 2147 parms.flag & DSW_GOLDEN ? "independent" : "dependent"); 2148 spcs_s_ufree(&parms.status); 2149 break; 2150 2151 default: 2152 exit(child_wait(child, Status, shadow_volume)); 2153 break; 2154 } 2155 } 2156 2157 int 2158 reset(char *volume) 2159 { 2160 dsw_ioctl_t args; 2161 dsw_config_t parms; 2162 int rc; 2163 int wait_loc; 2164 pid_t child = (pid_t)0; 2165 enum copy_wait wait_action; 2166 spcs_s_info_t *stat; 2167 dsw_stat_t prev_stat; 2168 int stat_flags; 2169 static int unlocked = 0; 2170 int do_enable = 0; 2171 char key[CFG_MAX_KEY]; 2172 char optval[CFG_MAX_BUF]; 2173 unsigned int flags; 2174 2175 wait_action = WaitForStart; 2176 2177 if (unlocked && !ii_lock(cfg, CFG_RDLOCK)) { 2178 dsw_error(gettext("Unable to set locking on the configuration"), 2179 NULL); 2180 } 2181 config_locked = 1; 2182 if (!find_shadow_config(volume, &parms, &args)) 2183 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 2184 "group"), NULL); 2185 2186 cfg_unlock(cfg); 2187 config_locked = 0; 2188 unlocked = 1; 2189 2190 spcs_log("ii", NULL, gettext("Start reset %s"), volume); 2191 (void) strlcpy(prev_stat.shadow_vol, volume, DSW_NAMELEN); 2192 prev_stat.status = spcs_s_ucreate(); 2193 if (do_ioctl(dsw_fd, DSWIOC_STAT, &prev_stat) == -1) { 2194 /* set is suspended, so we do the enable processing instead */ 2195 do_enable = 1; 2196 2197 /* first check to see whether the set was offline */ 2198 (void) snprintf(key, CFG_MAX_KEY, "ii.set%d.options", 2199 setnumber); 2200 if (!ii_lock(cfg, CFG_RDLOCK)) { 2201 dsw_error(gettext("Unable to set locking on the " 2202 "configuration"), NULL); 2203 } 2204 config_locked = 1; 2205 unlocked = 0; 2206 if (cfg_get_single_option(cfg, CFG_SEC_CONF, key, 2207 NSKERN_II_BMP_OPTION, optval, CFG_MAX_BUF) < 0) { 2208 dsw_error(gettext("unable to read config file"), NULL); 2209 } 2210 cfg_unlock(cfg); 2211 config_locked = 0; 2212 unlocked = 1; 2213 (void) sscanf(optval, "%x", &flags); 2214 if ((flags & DSW_OFFLINE) == 0) { 2215 /* set wasn't offline - don't reset */ 2216 dsw_error(gettext("Set not offline, will not reset"), 2217 NULL); 2218 } 2219 parms.status = spcs_s_ucreate(); 2220 stat = &parms.status; 2221 stat_flags = DSW_BMPOFFLINE; 2222 } else { 2223 args.status = spcs_s_ucreate(); 2224 stat = &args.status; 2225 stat_flags = prev_stat.stat; 2226 } 2227 spcs_s_ufree(&prev_stat.status); 2228 2229 if (wait_action == WaitForStart) 2230 (void) sigset(SIGCHLD, sigchild); 2231 2232 switch (child = fork()) { 2233 2234 case (pid_t)-1: 2235 dsw_error(gettext("Unable to fork"), NULL); 2236 break; 2237 2238 case 0: 2239 if (do_enable) { 2240 rc = do_ioctl(dsw_fd, DSWIOC_ENABLE, &parms); 2241 } else { 2242 rc = do_ioctl(dsw_fd, DSWIOC_RESET, &args); 2243 } 2244 if (rc == -1 && errno != DSW_EABORTED && errno != DSW_EIO) { 2245 spcs_log("ii", stat, gettext("Fail reset %s"), volume); 2246 dsw_error(gettext("Reset shadow failed"), stat); 2247 } 2248 /* last_overflow is set during find_shadow_config */ 2249 if (strlen(last_overflow) > 0 && 2250 (stat_flags & (DSW_SHDOFFLINE | DSW_BMPOFFLINE)) != 0) { 2251 /* reattach it */ 2252 (void) strncpy(parms.bitmap_vol, last_overflow, 2253 DSW_NAMELEN); 2254 do_attach(&parms); 2255 } 2256 spcs_log("ii", stat, gettext("Finish reset %s"), volume); 2257 spcs_s_ufree(stat); 2258 2259 exit(0); 2260 break; 2261 default: 2262 if (wait_action == WaitForStart) { 2263 rc = child_wait(child, CopyStart, args.shadow_vol); 2264 } else { /* wait_action == WaitForEnd */ 2265 wait_loc = 0; 2266 (void) wait(&wait_loc); 2267 if (WIFEXITED(wait_loc) && (WEXITSTATUS(wait_loc) == 0)) 2268 rc = 0; 2269 else 2270 rc = -1; 2271 } 2272 break; 2273 } 2274 /* if successful, remove flags entry from options field */ 2275 if (rc >= 0) { 2276 if (!ii_lock(cfg, CFG_WRLOCK)) { 2277 dsw_error(gettext("Unable to set locking on the " 2278 "configuration"), NULL); 2279 } 2280 config_locked = 1; 2281 if (!find_shadow_config(volume, &parms, &args)) { 2282 dsw_error(gettext("Volume is not in a Point-in-Time " 2283 "Copy group"), NULL); 2284 } 2285 (void) snprintf(key, CFG_MAX_KEY, "ii.set%d.options", 2286 setnumber); 2287 if (cfg_del_option(cfg, CFG_SEC_CONF, key, NSKERN_II_BMP_OPTION) 2288 < 0) { 2289 dsw_error(gettext("Update of config failed"), NULL); 2290 } 2291 (void) cfg_commit(cfg); 2292 cfg_unlock(cfg); 2293 config_locked = 0; 2294 } 2295 2296 return (rc); 2297 } 2298 2299 int 2300 overflow(char *volume) 2301 { 2302 dsw_ioctl_t args; 2303 int rc; 2304 spcs_s_info_t *stat; 2305 2306 check_action(gettext("Initialize this overflow volume?")); 2307 if (find_matching_cf_line(volume, NULL, &args)) 2308 dsw_error(gettext("Volume is part of a Point-in-Time Copy " 2309 "group"), NULL); 2310 args.status = spcs_s_ucreate(); 2311 (void) strncpy(args.shadow_vol, volume, DSW_NAMELEN); 2312 rc = do_ioctl(dsw_fd, DSWIOC_OCREAT, &args); 2313 if (rc == -1) { 2314 spcs_log("ii", &args.status, 2315 gettext("Create overflow failed %s"), volume); 2316 dsw_error(gettext("Create overflow failed"), &args.status); 2317 } 2318 if (rc == -1) 2319 stat = &args.status; 2320 else 2321 stat = NULL; 2322 spcs_log("ii", stat, gettext("Create overflow succeeded %s"), volume); 2323 spcs_s_ufree(&args.status); 2324 2325 return (0); 2326 } 2327 2328 void 2329 bitmap_op(char *master_volume, int print_bitmap, int bitmap_percent, int used, 2330 int is_compact) 2331 { 2332 unsigned char *bitmap; 2333 char *name; 2334 int i, x, y; 2335 unsigned j; 2336 unsigned long n; 2337 unsigned long percent; 2338 2339 bitmap = allocate_bitmap(master_volume); 2340 if (bitmap == NULL) 2341 return; 2342 2343 if (bitmap_percent) { 2344 /* count the number of bits set in bitmap */ 2345 for (i = n = 0; i < bm_size; i++) 2346 for (j = (unsigned)bitmap[i]; j; j &= j -1) 2347 n++; 2348 if (is_compact) 2349 (void) printf(gettext("Chunks in map: %d used: %d\n"), 2350 used, n); 2351 if (bm_actual < 100) { 2352 percent = 0; 2353 } else { 2354 percent = (n * 100) / bm_actual; 2355 } 2356 (void) printf(gettext("Percent of bitmap set: %u\n"), percent); 2357 percent = percent/100; 2358 /* distinguish between 0.0000% and 0.n% of bitmap set */ 2359 if (percent < 1) 2360 (void) printf("\t(%s)\n", n > 0 ? 2361 gettext("bitmap dirty") : gettext("bitmap clean")); 2362 } 2363 2364 if (print_bitmap) { 2365 name = strrchr(master_volume, '/'); 2366 if (name++ == NULL) 2367 name = master_volume; 2368 i = bm_size * 8; 2369 x = (int)ceil(sqrt((double)i)); 2370 x += (8 - (x % 8)); /* round up to nearest multiple of 8 */ 2371 y = i / x; 2372 if (y * x < i) 2373 y++; 2374 (void) printf("#define bm%s_width %d\n#define bm%s_height %d\n", 2375 name, x, name, y); 2376 (void) printf("#define bm%s_x_hot 0\n#define bm%s_y_hot 0\n", 2377 name, name); 2378 (void) printf("static char bm%s_bits[] = {\n", name); 2379 for (i = 0; i < bm_size; i++) { 2380 if (i % 12 == 0) 2381 (void) printf("\n"); 2382 (void) printf("0x%02x, ", bitmap[i]); 2383 } 2384 y = x * y; 2385 for (; i < y; i++) { 2386 if (i % 12 == 0) 2387 (void) printf("\n"); 2388 (void) printf("0x00, "); 2389 } 2390 (void) printf("\n};\n"); 2391 } 2392 2393 free_bitmap(bitmap); 2394 } 2395 2396 static int 2397 validate_group_names(char **vol_list, char *group) 2398 { 2399 ENTRY item, *found; 2400 int i, rc, count; 2401 dsw_aioctl_t *group_list; 2402 char *ptr; 2403 2404 if (group == NULL || *group == NULL) { 2405 /* no group set, just count volume list */ 2406 for (i = 0; *vol_list++ != NULL; i++) 2407 ; 2408 return (i); 2409 } 2410 2411 if ((count = do_ioctl(dsw_fd, DSWIOC_LISTLEN, NULL)) < 0) 2412 dsw_error("DSWIOC_LISTLEN", NULL); 2413 2414 group_list = malloc(sizeof (dsw_aioctl_t) + count * DSW_NAMELEN); 2415 if (group_list == NULL) 2416 dsw_error(gettext("Failed to allocate memory"), NULL); 2417 2418 bzero(group_list, sizeof (dsw_aioctl_t) + count * DSW_NAMELEN); 2419 group_list->count = count; 2420 group_list->flags = 0; 2421 group_list->status = spcs_s_ucreate(); 2422 (void) strncpy(group_list->shadow_vol, group, DSW_NAMELEN); 2423 2424 rc = do_ioctl(dsw_fd, DSWIOC_GLIST, group_list); 2425 if (rc < 0) 2426 dsw_error(gettext("Group list access failure"), 2427 &group_list->status); 2428 2429 group_list->shadow_vol[DSW_NAMELEN * group_list->count] = '\0'; 2430 2431 /* create hash and enter all volumes into it */ 2432 if (hcreate(group_list->count) == 0) 2433 dsw_error(gettext("Failed to allocate memory"), NULL); 2434 ptr = group_list->shadow_vol; 2435 count = group_list->count; 2436 i = 0; 2437 while (i < count) { 2438 ptr[ DSW_NAMELEN - 1 ] = '\0'; 2439 item.key = ptr; 2440 item.data = (void *) 0; 2441 (void) hsearch(item, ENTER); 2442 ++i; 2443 ptr += DSW_NAMELEN; 2444 } 2445 2446 /* now compare the volume list with the hash */ 2447 for (i = 0; vol_list[ i ]; i++) { 2448 item.key = vol_list[ i ]; 2449 found = hsearch(item, FIND); 2450 if (!found) 2451 dsw_error(gettext("Group config does not match kernel"), 2452 NULL); 2453 if (found->data != (void *) 0) 2454 dsw_error(gettext("Duplicate volume specified"), NULL); 2455 found->data = (void *) 1; 2456 } 2457 if (i != count) 2458 dsw_error(gettext("Group config does not match kernel"), NULL); 2459 2460 /* everything checks out */ 2461 free(group_list); 2462 hdestroy(); 2463 2464 return (count); 2465 } 2466 2467 int 2468 do_acopy(char **vol_list, enum copy_update update_mode, 2469 enum copy_direction direction) 2470 { 2471 dsw_aioctl_t *acopy_args; 2472 dsw_ioctl_t copy_args; 2473 dsw_config_t parms; 2474 dsw_stat_t stat_s; 2475 int i; 2476 int rc; 2477 int n_vols; 2478 char *t; 2479 char buf[1024]; 2480 char *sp; 2481 char *ppid; 2482 2483 n_vols = validate_group_names(vol_list, group_name); 2484 2485 acopy_args = calloc(sizeof (dsw_aioctl_t) + n_vols * DSW_NAMELEN, 1); 2486 if (acopy_args == NULL) 2487 dsw_error(gettext("Too many volumes given for update"), NULL); 2488 2489 acopy_args->count = n_vols; 2490 2491 acopy_args->flags = 0; 2492 2493 if (update_mode == Update) 2494 acopy_args->flags |= CV_BMP_ONLY; 2495 if (direction == ToMaster) 2496 acopy_args->flags |= CV_SHD2MST; 2497 if (pflg) { 2498 acopy_args->flags |= CV_LOCK_PID; 2499 #ifdef DEBUG 2500 ppid = getenv("IIADM_PPID"); 2501 if (ppid) { 2502 acopy_args->pid = atoi(ppid); 2503 (void) fprintf(stderr, "(using %s for ppid)\n", ppid); 2504 } else { 2505 acopy_args->pid = getppid(); 2506 } 2507 #else 2508 acopy_args->pid = getppid(); 2509 #endif 2510 } 2511 2512 for (i = 0; i < n_vols; i++) { 2513 if (!find_shadow_config(vol_list[i], &parms, ©_args)) 2514 dsw_error(gettext("Volume is not in a Point-in-Time " 2515 "group"), NULL); 2516 if (direction == ToMaster) { 2517 t = parms.master_vol; 2518 } else { 2519 t = parms.shadow_vol; 2520 } 2521 2522 if (mounted(t)) { 2523 errno = EBUSY; 2524 dsw_error(gettext("Target of copy/update is mounted, " 2525 "unmount it first"), NULL); 2526 } 2527 2528 (void) strlcpy(stat_s.shadow_vol, parms.shadow_vol, 2529 DSW_NAMELEN); 2530 stat_s.status = spcs_s_ucreate(); 2531 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &stat_s); 2532 spcs_s_ufree(&stat_s.status); 2533 if (rc == -1) { 2534 (void) sprintf(buf, 2535 gettext("Shadow group %s is suspended"), 2536 vol_list[i]); 2537 dsw_error(buf, NULL); 2538 } 2539 2540 if (stat_s.stat & DSW_COPYINGP) { 2541 (void) fprintf(stderr, "%s: %s\n", cmdnam, 2542 gettext("Copy already in progress")); 2543 exit(1); 2544 } 2545 } 2546 acopy_args->status = spcs_s_ucreate(); 2547 for (i = 0; i < n_vols; i++) { 2548 spcs_log("ii", NULL, gettext("Atomic %s %s %s"), 2549 update_mode == Update ? gettext("update") : gettext("copy"), 2550 vol_list[i], 2551 direction == ToMaster ? gettext("from shadow") : 2552 gettext("to shadow")); 2553 } 2554 if (group_name == NULL || *group_name == NULL) { 2555 sp = acopy_args->shadow_vol; 2556 for (i = 0; i < n_vols; i++, sp += DSW_NAMELEN) 2557 (void) strncpy(sp, vol_list[i], DSW_NAMELEN); 2558 } else { 2559 (void) strncpy(acopy_args->shadow_vol, group_name, DSW_NAMELEN); 2560 acopy_args->flags |= CV_IS_GROUP; 2561 } 2562 rc = do_ioctl(dsw_fd, DSWIOC_ACOPY, acopy_args); 2563 if (rc == -1) { 2564 i = acopy_args->count; 2565 if (i < 0 || i >= n_vols) { 2566 spcs_log("ii", NULL, gettext("Atomic update failed")); 2567 (void) sprintf(buf, gettext("Update failed")); 2568 } else { 2569 spcs_log("ii", NULL, 2570 gettext("Atomic update of %s failed"), 2571 vol_list[acopy_args->count]); 2572 (void) sprintf(buf, gettext("Update of %s failed"), 2573 vol_list[acopy_args->count]); 2574 } 2575 dsw_error(buf, &(acopy_args->status)); 2576 } 2577 return (rc); 2578 } 2579 2580 int 2581 do_copy(char **vol_list, enum copy_update update_mode, 2582 enum copy_direction direction, enum copy_wait wait_action) 2583 { 2584 dsw_ioctl_t copy_args; 2585 dsw_config_t parms; 2586 dsw_stat_t stat_s; 2587 int rc; 2588 int wait_loc; 2589 char *t; 2590 char *volume; 2591 pid_t child = (pid_t)0; 2592 char *ppid; 2593 2594 if (vol_list[0] && vol_list[1]) 2595 return (do_acopy(vol_list, update_mode, direction)); 2596 2597 volume = vol_list[0]; 2598 if (!find_shadow_config(volume, &parms, ©_args)) 2599 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 2600 "group"), NULL); 2601 2602 cfg_unlock(cfg); 2603 config_locked = 0; 2604 copy_args.flags = 0; 2605 2606 if (update_mode == Update) 2607 copy_args.flags |= CV_BMP_ONLY; 2608 if (direction == ToMaster) { 2609 copy_args.flags |= CV_SHD2MST; 2610 t = parms.master_vol; 2611 } else { 2612 t = parms.shadow_vol; 2613 } 2614 if (pflg) { 2615 copy_args.flags |= CV_LOCK_PID; 2616 #ifdef DEBUG 2617 ppid = getenv("IIADM_PPID"); 2618 if (ppid) { 2619 copy_args.pid = atoi(ppid); 2620 (void) fprintf(stderr, "(using %s for ppid)\n", ppid); 2621 } else { 2622 copy_args.pid = getppid(); 2623 } 2624 #else 2625 copy_args.pid = getppid(); 2626 #endif 2627 } 2628 2629 if (mounted(t)) { 2630 errno = EBUSY; 2631 dsw_error(gettext("Target of copy/update is mounted, " 2632 "unmount it first"), NULL); 2633 } 2634 2635 (void) strlcpy(stat_s.shadow_vol, copy_args.shadow_vol, DSW_NAMELEN); 2636 stat_s.status = spcs_s_ucreate(); 2637 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &stat_s); 2638 spcs_s_ufree(&stat_s.status); 2639 if (rc == -1) 2640 dsw_error(gettext("Shadow group suspended"), NULL); 2641 2642 if (stat_s.stat & DSW_COPYINGP) { 2643 (void) fprintf(stderr, "%s: %s\n", cmdnam, 2644 gettext("Copy already in progress")); 2645 exit(1); 2646 } 2647 2648 copy_args.status = spcs_s_ucreate(); 2649 spcs_log("ii", NULL, gettext("Start %s %s %s"), 2650 update_mode == Update ? gettext("update") : gettext("copy"), 2651 volume, 2652 direction == ToMaster ? gettext("from shadow") : 2653 gettext("to shadow")); 2654 2655 if (wait_action == WaitForStart) 2656 (void) sigset(SIGCHLD, sigchild); 2657 switch (child = fork()) { 2658 2659 case (pid_t)-1: 2660 dsw_error(gettext("Unable to fork"), 2661 NULL); 2662 break; 2663 2664 case 0: 2665 rc = do_ioctl(dsw_fd, DSWIOC_COPY, ©_args); 2666 if (rc == -1) { 2667 spcs_log("ii", ©_args.status, 2668 gettext("Fail %s %s %s"), 2669 update_mode == Update ? 2670 gettext("update") : gettext("copy"), 2671 volume, 2672 direction == ToMaster ? 2673 gettext("from shadow") : gettext("to shadow")); 2674 dsw_error(gettext("Copy failed"), ©_args.status); 2675 } 2676 spcs_s_ufree(©_args.status); 2677 spcs_log("ii", NULL, gettext("Finish %s %s %s"), 2678 update_mode == Update ? gettext("update") : gettext("copy"), 2679 volume, 2680 direction == ToMaster ? gettext("from shadow") : 2681 gettext("to shadow")); 2682 2683 exit(0); 2684 break; 2685 default: 2686 if (wait_action == WaitForStart) { 2687 rc = child_wait(child, CopyStart, copy_args.shadow_vol); 2688 } else { /* wait_action == WaitForEnd */ 2689 wait_loc = 0; 2690 (void) wait(&wait_loc); 2691 if (WIFEXITED(wait_loc) && (WEXITSTATUS(wait_loc) == 0)) 2692 rc = 0; 2693 else 2694 rc = 1; 2695 } 2696 break; 2697 } 2698 return (rc); 2699 } 2700 2701 void 2702 print_status(dsw_config_t *conf, int in_config) 2703 { 2704 dsw_stat_t args; 2705 int stat_flags; 2706 static int need_sep = 0; 2707 time_t tmp_time; 2708 2709 if (need_sep++ > 0) 2710 (void) printf("--------------------------------------" 2711 "----------------------------------------\n"); 2712 (void) strlcpy(args.shadow_vol, conf->shadow_vol, DSW_NAMELEN); 2713 if (in_config) { 2714 (void) printf("%s: %s\n", 2715 conf->master_vol, gettext("(master volume)")); 2716 (void) printf("%s: %s\n", 2717 conf->shadow_vol, gettext("(shadow volume)")); 2718 (void) printf("%s: %s\n", 2719 conf->bitmap_vol, gettext("(bitmap volume)")); 2720 } 2721 2722 /* 2723 * Do special checking on the status of this volume in a Sun Cluster 2724 */ 2725 if (check_cluster() == II_CLUSTER) { 2726 char dgname[CFG_MAX_BUF], *other_node; 2727 2728 if (cfg_dgname(conf->bitmap_vol, dgname, sizeof (dgname))) { 2729 if (strlen(dgname)) { 2730 int rc = cfg_dgname_islocal(dgname, 2731 &other_node); 2732 2733 if (rc < 0) { 2734 (void) printf(gettext( 2735 "Suspended on this node, " 2736 "not active elsewhere\n")); 2737 return; 2738 } else if (rc == 0) { 2739 (void) printf(gettext( 2740 "Suspended on this node, " 2741 "active on %s\n"), other_node); 2742 return; 2743 } 2744 } 2745 } 2746 } 2747 2748 args.status = spcs_s_ucreate(); 2749 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) { 2750 2751 /* Handle Not found or not in config */ 2752 if (errno != DSW_ENOTFOUND || !in_config) 2753 dsw_error(gettext("Stat failed"), &args.status); 2754 2755 /* Just suspend */ 2756 (void) printf(gettext("Suspended.\n")); 2757 return; 2758 } 2759 2760 if (args.overflow_vol[0] != '\0') 2761 (void) printf("%s: %s\n", args.overflow_vol, 2762 gettext("(overflow volume)")); 2763 2764 if (conf->group_name[0] != '\0') 2765 (void) printf(gettext("Group name: %s\n"), 2766 conf->group_name); 2767 2768 if (conf->cluster_tag[0] != '\0') 2769 (void) printf(gettext("Cluster tag: %s\n"), 2770 conf->cluster_tag); 2771 2772 stat_flags = args.stat; 2773 spcs_s_ufree(&args.status); 2774 if (stat_flags & DSW_GOLDEN) 2775 (void) printf(gettext("Independent copy")); 2776 else 2777 (void) printf(gettext("Dependent copy")); 2778 2779 if (stat_flags & DSW_TREEMAP) 2780 (void) printf(gettext(", compacted shadow space")); 2781 2782 if (stat_flags & DSW_COPYINGP) 2783 (void) printf(gettext(", copy in progress")); 2784 else if (stat_flags & DSW_COPYING) 2785 (void) printf(gettext(", copy not active")); 2786 2787 if (stat_flags & DSW_COPYINGM) 2788 (void) printf(gettext(", copying master to shadow")); 2789 2790 if (stat_flags & DSW_COPYINGS) 2791 (void) printf(gettext(", copying shadow to master")); 2792 2793 if (stat_flags & DSW_COPYINGX) 2794 (void) printf(gettext(", abort of copy requested")); 2795 2796 if (stat_flags & DSW_MSTOFFLINE) 2797 (void) printf(gettext(", master volume offline")); 2798 2799 if (stat_flags & DSW_SHDOFFLINE) 2800 (void) printf(gettext(", shadow volume offline")); 2801 2802 if (stat_flags & DSW_BMPOFFLINE) 2803 (void) printf(gettext(", bitmap volume offline")); 2804 2805 if (stat_flags & DSW_OVROFFLINE) 2806 (void) printf(gettext(", overflow volume offline")); 2807 2808 if (stat_flags & DSW_SHDEXPORT) 2809 (void) printf(gettext(", shadow volume exported")); 2810 2811 if (stat_flags & DSW_SHDIMPORT) 2812 (void) printf(gettext(", shadow volume imported")); 2813 2814 if (stat_flags & DSW_OVERFLOW) 2815 (void) printf(gettext(", out of space")); 2816 2817 if (stat_flags & DSW_VOVERFLOW) 2818 (void) printf(gettext(", spilled into overflow volume")); 2819 (void) printf("\n"); 2820 2821 tmp_time = args.mtime; 2822 if (tmp_time != 0) 2823 (void) printf("%s %s", gettext("Latest modified time:"), 2824 ctime(&tmp_time)); 2825 else 2826 (void) printf("%s\n", gettext("Latest modified time: unknown")); 2827 2828 (void) printf("%s %8llu\n", gettext("Volume size:"), args.size); 2829 if (args.shdsize != 0) { 2830 (void) printf("%s %lld %s %lld\n", 2831 gettext("Shadow chunks total:"), args.shdsize, 2832 gettext("Shadow chunks used:"), args.shdused); 2833 } 2834 bitmap_op(args.shadow_vol, 0, 1, 0, 0); 2835 } 2836 2837 int 2838 abort_copy(char *volume) 2839 { 2840 dsw_ioctl_t args; 2841 2842 if (!find_shadow_config(volume, NULL, &args)) 2843 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 2844 "group"), NULL); 2845 args.status = spcs_s_ucreate(); 2846 if (do_ioctl(dsw_fd, DSWIOC_ABORT, &args) == -1) 2847 dsw_error(gettext("Abort failed"), &args.status); 2848 spcs_log("ii", NULL, gettext("Abort %s"), args.shadow_vol); 2849 spcs_s_ufree(&args.status); 2850 return (0); 2851 } 2852 2853 void 2854 iiversion() 2855 { 2856 dsw_version_t args; 2857 2858 args.status = spcs_s_ucreate(); 2859 if (do_ioctl(dsw_fd, DSWIOC_VERSION, &args) == -1) 2860 dsw_error(gettext("Version failed"), &args.status); 2861 spcs_s_ufree(&args.status); 2862 #ifdef DEBUG 2863 (void) printf(gettext("Point in Time Copy version %d.%d.%d.%d\n"), 2864 args.major, args.minor, args.micro, args.baseline); 2865 #else 2866 if (args.micro) { 2867 (void) printf(gettext("Point in Time Copy version %d.%d.%d\n"), 2868 args.major, args.minor, args.micro); 2869 } else { 2870 (void) printf(gettext("Point in Time Copy version %d.%d\n"), 2871 args.major, args.minor); 2872 } 2873 #endif 2874 } 2875 2876 void 2877 list_volumes() 2878 { 2879 dsw_list_t args; 2880 int i, set, found; 2881 dsw_config_t *lp; 2882 ENTRY item, *ip; 2883 dsw_config_t parms; 2884 2885 if ((i = do_ioctl(dsw_fd, DSWIOC_LISTLEN, &args)) == -1) 2886 dsw_error("DSWIOC_LISTLEN", NULL); 2887 2888 args.status = spcs_s_ucreate(); 2889 args.list_used = 0; 2890 args.list_size = i + 4; 2891 lp = args.list = (dsw_config_t *) 2892 malloc(args.list_size * sizeof (dsw_config_t)); 2893 2894 if (args.list == NULL) 2895 dsw_error(gettext("Failed to allocate memory"), NULL); 2896 if (do_ioctl(dsw_fd, DSWIOC_LIST, &args) == -1) 2897 dsw_error(gettext("List failed"), &args.status); 2898 spcs_s_ufree(&args.status); 2899 2900 /* make a hashtable */ 2901 if (args.list_used > 0) { 2902 if (hcreate(args.list_used) == 0) { 2903 dsw_error(gettext("Failed to allocate memory"), NULL); 2904 /*NOTREACHED*/ 2905 } 2906 } 2907 2908 /* populate the hashtable */ 2909 for (i = 0; i < args.list_used; i++, lp++) { 2910 item.key = lp->shadow_vol; 2911 item.data = (char *)lp; 2912 if (hsearch(item, ENTER) == NULL) { 2913 dsw_error(gettext("Failed to allocate memory"), NULL); 2914 /*NOTREACHED*/ 2915 } 2916 } 2917 2918 /* perform action for each line of the stored config file */ 2919 for (set = 1; get_dsw_config(set, &parms) == 0; set++) { 2920 2921 /* Are there any II sets configured on this node? */ 2922 if (args.list_used > 0) { 2923 item.key = parms.shadow_vol; 2924 2925 /* Is this volume configured on this node? */ 2926 if (ip = hsearch(item, FIND)) { 2927 2928 /* Handle Imported Shadows */ 2929 /* LINTED alignment of cast ok */ 2930 lp = (dsw_config_t *)ip->data; 2931 if (strcmp(parms.master_vol, 2932 II_IMPORTED_SHADOW)) 2933 found = !(lp->flag & DSW_SHDIMPORT); 2934 else 2935 found = (lp->flag & DSW_SHDIMPORT); 2936 } 2937 else 2938 found = FALSE; 2939 } 2940 else 2941 found = FALSE; 2942 2943 if ((cfg_cluster_tag) && 2944 strcmp(cfg_cluster_tag, parms.cluster_tag)) 2945 continue; 2946 2947 if ((group_name) && strcmp(group_name, parms.group_name)) 2948 continue; 2949 2950 (void) printf("%s %.*s %.*s %.*s%s\n", 2951 (parms.flag & DSW_GOLDEN) ? "ind" : "dep", 2952 DSW_NAMELEN, parms.master_vol, 2953 DSW_NAMELEN, parms.shadow_vol, 2954 DSW_NAMELEN, parms.bitmap_vol, 2955 found ? "" : gettext(" (suspended)")); 2956 } 2957 hdestroy(); 2958 free(args.list); 2959 } 2960 2961 int 2962 wait_for_copy(char *volume) 2963 { 2964 dsw_ioctl_t parms; 2965 int rc; 2966 static int unlocked = 0; 2967 char *ppid; 2968 2969 if (unlocked && !ii_lock(cfg, CFG_RDLOCK)) { 2970 dsw_error(gettext("Unable to set locking on the configuration"), 2971 NULL); 2972 } 2973 config_locked = 1; 2974 if (!find_shadow_config(volume, NULL, &parms)) 2975 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 2976 "group"), NULL); 2977 cfg_unlock(cfg); 2978 config_locked = 0; 2979 unlocked = 1; 2980 2981 parms.status = spcs_s_ucreate(); 2982 if (pflg) { 2983 #ifdef DEBUG 2984 ppid = getenv("IIADM_PPID"); 2985 if (ppid) { 2986 parms.pid = atoi(ppid); 2987 (void) fprintf(stderr, "(using %s for ppid)\n", ppid); 2988 } else { 2989 parms.pid = (nflg) ? -1 : getppid(); 2990 } 2991 #else 2992 parms.pid = (nflg) ? -1 : getppid(); 2993 #endif 2994 parms.flags |= CV_LOCK_PID; 2995 } 2996 2997 rc = do_ioctl(dsw_fd, DSWIOC_WAIT, &parms); 2998 if (rc == -1) 2999 dsw_error(gettext("Wait failed"), &parms.status); 3000 spcs_s_ufree(&parms.status); 3001 return (0); 3002 } 3003 3004 int 3005 export(char *volume) 3006 { 3007 dsw_ioctl_t parms; 3008 dsw_config_t conf; 3009 char *old_ctag, dgname[DSW_NAMELEN]; 3010 int rc; 3011 3012 if (!find_shadow_config(volume, &conf, &parms)) 3013 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 3014 "group"), NULL); 3015 if (mounted(volume)) 3016 dsw_error(gettext("Can't export a mounted volume"), NULL); 3017 3018 /* If this is an exportable shadow in the cluster, change ctag */ 3019 if (strlen(conf.cluster_tag) && 3020 (cfg_dgname(volume, dgname, sizeof (dgname)))) { 3021 old_ctag = cfg_cluster_tag; 3022 cfg_resource(cfg, cfg_cluster_tag = strdup(dgname)); 3023 } else old_ctag = NULL; 3024 3025 if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) { 3026 dsw_error(gettext("Unable to parse config file"), NULL); 3027 } 3028 reload_vols = LD_DSVOLS | LD_SHADOWS; 3029 conform_name(&volume); 3030 3031 spcs_log("ii", NULL, gettext("Export %s"), volume); 3032 parms.status = spcs_s_ucreate(); 3033 rc = do_ioctl(dsw_fd, DSWIOC_EXPORT, &parms); 3034 if (rc == -1) 3035 dsw_error(gettext("Export failed"), &parms.status); 3036 if (perform_autosv()) { 3037 if (cfg_vol_disable(cfg, volume, cfg_cluster_tag, "ii") < 0) { 3038 dsw_error(gettext("SV-disable failed"), NULL); 3039 } 3040 (void) cfg_commit(cfg); 3041 } 3042 3043 /* restore old cluster tag, if changed */ 3044 if (old_ctag != NULL) 3045 cfg_resource(cfg, cfg_cluster_tag = old_ctag); 3046 3047 spcs_s_ufree(&parms.status); 3048 return (0); 3049 } 3050 3051 int 3052 detach(char *volume) 3053 { 3054 dsw_ioctl_t parms; 3055 int rc; 3056 3057 if (!find_shadow_config(volume, NULL, &parms)) 3058 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 3059 "group"), NULL); 3060 parms.status = spcs_s_ucreate(); 3061 rc = do_ioctl(dsw_fd, DSWIOC_ODETACH, &parms); 3062 if (rc == 0) { 3063 /* remove overflow from cfg line */ 3064 (void) sprintf(key, "ii.set%d.overflow", setnumber); 3065 if (cfg_put_cstring(cfg, key, "-", 1) < 0) { 3066 perror("cfg_put_cstring"); 3067 } 3068 (void) cfg_commit(cfg); 3069 } else { 3070 spcs_log("ii", NULL, gettext("Detach of overflow %s failed"), 3071 parms.shadow_vol); 3072 dsw_error(gettext("Failed to detach overflow volume"), 3073 &parms.status); 3074 } 3075 return (rc); 3076 } 3077 3078 static void 3079 can_disable(char *vol) 3080 { 3081 dsw_stat_t args; 3082 3083 if (mounted(vol)) { 3084 (void) strlcpy(args.shadow_vol, vol, DSW_NAMELEN); 3085 args.status = spcs_s_ucreate(); 3086 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) != -1 && 3087 (args.stat & DSW_GOLDEN) == 0) { 3088 errno = EBUSY; 3089 dsw_error(gettext("Shadow Volume is currently mounted " 3090 "and dependent on the master volume"), NULL); 3091 } 3092 spcs_s_ufree(&args.status); 3093 } 3094 } 3095 3096 static void 3097 clean_up_after_failed_disable(dsw_ioctl_t *parms) 3098 { 3099 char **p; 3100 dsw_stat_t args; 3101 3102 for (p = group_volumes; *p; p++) { 3103 (void) strlcpy(args.shadow_vol, *p, DSW_NAMELEN); 3104 args.status = spcs_s_ucreate(); 3105 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) { 3106 /* set was successfully disabled */ 3107 if (find_shadow_config(*p, NULL, NULL)) 3108 remove_iiset(setnumber, *p, 0); 3109 } 3110 spcs_s_ufree(&args.status); 3111 } 3112 3113 dsw_error(gettext("Some sets in the group failed to disable"), 3114 &parms->status); 3115 } 3116 3117 int 3118 dsw_group_or_single_disable(int argc, char *argv[]) 3119 { 3120 int rc = 0; 3121 char **p; 3122 dsw_ioctl_t parms; 3123 int flags = 0; 3124 dsw_config_t conf; 3125 int shd_exported = 0; 3126 3127 if (argc != 2) 3128 usage(gettext("Incorrect number of arguments")); 3129 3130 if (group_name) { 3131 if (find_group_members(group_name) < 1) 3132 dsw_error(gettext("Group does not exist or " 3133 "has no members"), NULL); 3134 for (p = group_volumes; *p; p++) { 3135 can_disable(*p); 3136 } 3137 3138 (void) strncpy(parms.shadow_vol, group_name, DSW_NAMELEN); 3139 if (*group_name) 3140 flags = CV_IS_GROUP; 3141 } else { 3142 if (!find_shadow_config(argv[1], &conf, &parms)) { 3143 dsw_error(gettext("Volume is not in a Point-in-Time " 3144 "Copy group"), NULL); 3145 } 3146 3147 can_disable(argv[1]); 3148 flags = 0; 3149 } 3150 3151 if (group_name && !*group_name) { 3152 /* user typed iiadm -g "" -d */ 3153 for (p = group_volumes; *p; p++) { 3154 parms.status = spcs_s_ucreate(); 3155 parms.flags = flags; 3156 (void) strncpy(parms.shadow_vol, *p, DSW_NAMELEN); 3157 rc = do_ioctl(dsw_fd, DSWIOC_DISABLE, &parms); 3158 if (rc == -1 && errno != DSW_ENOTFOUND) 3159 dsw_error(gettext("Disable failed"), 3160 &parms.status); 3161 if (!find_shadow_config(*p, NULL, NULL)) 3162 dsw_error(gettext("Volume is not in a Point-in" 3163 "-Time Copy group"), &parms.status); 3164 remove_iiset(setnumber, *p, 0); 3165 spcs_s_ufree(&parms.status); 3166 spcs_log("ii", NULL, gettext("Disabled %s"), 3167 parms.shadow_vol); 3168 } 3169 } else { 3170 if (is_exported(conf.shadow_vol)) { 3171 shd_exported = 1; 3172 } 3173 if ((strcmp(conf.master_vol, II_IMPORTED_SHADOW) == 0) && 3174 is_exported(conf.shadow_vol)) { 3175 dsw_error(gettext( 3176 "Imported shadow not disabled"), NULL); 3177 } 3178 3179 parms.status = spcs_s_ucreate(); 3180 parms.flags = flags; 3181 rc = do_ioctl(dsw_fd, DSWIOC_DISABLE, &parms); 3182 if (rc == -1 && errno != DSW_ENOTFOUND) { 3183 if (errno == DSW_EDISABLE) { 3184 /* 3185 * one or more sets within the group 3186 * couldn't disable 3187 */ 3188 clean_up_after_failed_disable(&parms); 3189 } else { 3190 dsw_error(gettext("Disable failed"), 3191 &parms.status); 3192 } 3193 } 3194 spcs_log("ii", NULL, gettext("Disabled %s"), parms.shadow_vol); 3195 } 3196 3197 3198 if (group_name && *group_name) { 3199 for (p = group_volumes; *p; p++) { 3200 if (!find_shadow_config(*p, NULL, NULL)) { 3201 /* argh! */ 3202 (void) fprintf(stderr, 3203 gettext("Volume '%s' is not " 3204 "in a Point-in-Time Copy group"), *p); 3205 } else { 3206 remove_iiset(setnumber, *p, 0); 3207 } 3208 } 3209 } else if (!group_name) { 3210 if (!find_shadow_config(argv[1], NULL, NULL)) { 3211 /* argh! */ 3212 dsw_error(gettext("Volume is not in a Point-in-Time " 3213 "Copy group"), NULL); 3214 } 3215 3216 remove_iiset(setnumber, argv[1], shd_exported); 3217 } 3218 3219 return (0); 3220 } 3221 3222 int 3223 dsw_group_or_single_op(int argc, char *argv[], int (*op)(char *)) 3224 { 3225 int rc = 0; 3226 3227 if (argc != 2) 3228 usage(gettext("Incorrect number of arguments")); 3229 3230 if (group_name) { 3231 if (find_group_members(group_name) < 1) 3232 dsw_error(gettext("Group does not exist or " 3233 "has no members"), NULL); 3234 for (; *group_volumes; group_volumes++) 3235 rc |= (*op)(*group_volumes); 3236 } else { 3237 rc = (*op)(argv[1]); 3238 } 3239 return (rc); 3240 } 3241 3242 void 3243 dsw_list_clusters(char *cluster) 3244 { 3245 dsw_aioctl_t *acopy_args; 3246 int rc, i, count; 3247 char *ptr; 3248 3249 if ((count = do_ioctl(dsw_fd, DSWIOC_LISTLEN, NULL)) < 0) 3250 dsw_error("DSWIOC_LISTLEN", NULL); 3251 3252 acopy_args = malloc(sizeof (dsw_aioctl_t) + count * DSW_NAMELEN); 3253 if (acopy_args == NULL) 3254 dsw_error(gettext("Can't get memory for list enquiry"), NULL); 3255 3256 bzero(acopy_args, sizeof (dsw_aioctl_t) + count * DSW_NAMELEN); 3257 acopy_args->count = count; 3258 acopy_args->flags = 0; 3259 acopy_args->status = spcs_s_ucreate(); 3260 if (cluster) 3261 (void) strncpy(acopy_args->shadow_vol, cluster, DSW_NAMELEN); 3262 3263 rc = do_ioctl(dsw_fd, DSWIOC_CLIST, acopy_args); 3264 if (rc == -1) 3265 dsw_error(gettext("Cluster list access failure"), 3266 &acopy_args->status); 3267 3268 acopy_args->shadow_vol[DSW_NAMELEN*acopy_args->count] = NULL; 3269 3270 if (cluster) { 3271 (void) printf(gettext("Sets in cluster resource group %s:\n"), 3272 cluster); 3273 } else { 3274 (void) printf( 3275 gettext("Currently configured resource groups\n")); 3276 } 3277 for (i = 0, ptr = acopy_args->shadow_vol; *ptr && 3278 i < acopy_args->count; i++, ptr += DSW_NAMELEN) { 3279 (void) printf(" %-64.64s\n", ptr); 3280 } 3281 } 3282 3283 void 3284 dsw_enable(int argc, char *argv[]) 3285 { 3286 if (argc != 5) 3287 usage(gettext("Incorrect number of arguments")); 3288 3289 enable(argv[1], argv[2], argv[3], argv[4]); 3290 exit(0); 3291 } 3292 3293 3294 void 3295 dsw_disable(int argc, char *argv[]) 3296 { 3297 (void) dsw_group_or_single_disable(argc, argv); 3298 exit(0); 3299 } 3300 3301 3302 void 3303 dsw_copy_to_shadow(int argc, char *argv[]) 3304 { 3305 char **volume_list; 3306 3307 if (argc != 2) 3308 usage(gettext("Incorrect number of arguments")); 3309 if (group_name == NULL) 3310 volume_list = ++argv; 3311 else { 3312 if (find_group_members(group_name) < 1) 3313 dsw_error(gettext("Group does not exist or " 3314 "has no members"), NULL); 3315 volume_list = group_volumes; 3316 } 3317 3318 exit(do_copy(volume_list, Copy, ToShadow, WaitForStart)); 3319 } 3320 3321 3322 void 3323 dsw_update_shadow(int argc, char *argv[]) 3324 { 3325 char **volume_list; 3326 3327 if (argc != 2) 3328 usage(gettext("Incorrect number of arguments")); 3329 if (group_name == NULL) 3330 volume_list = ++argv; 3331 else { 3332 if (find_group_members(group_name) < 1) 3333 dsw_error(gettext("Group does not exist or " 3334 "has no members"), NULL); 3335 volume_list = group_volumes; 3336 } 3337 3338 exit(do_copy(volume_list, Update, ToShadow, WaitForStart)); 3339 } 3340 3341 3342 void 3343 dsw_copy_to_master(int argc, char *argv[]) 3344 { 3345 char **volume_list; 3346 3347 if (argc != 2) 3348 usage(gettext("Incorrect number of arguments")); 3349 if (group_name == NULL) { 3350 volume_list = ++argv; 3351 check_action(gettext("Overwrite master with shadow volume?")); 3352 } else { 3353 check_action(gettext("Overwrite every" 3354 " master in this group with its shadow volume?")); 3355 if (find_group_members(group_name) < 1) 3356 dsw_error(gettext("Group does not exist or " 3357 "has no members"), NULL); 3358 volume_list = group_volumes; 3359 } 3360 3361 exit(do_copy(volume_list, Copy, ToMaster, WaitForStart)); 3362 } 3363 3364 3365 void 3366 dsw_update_master(int argc, char *argv[]) 3367 { 3368 char **volume_list; 3369 3370 if (argc != 2) 3371 usage(gettext("Incorrect number of arguments")); 3372 if (group_name == NULL) { 3373 volume_list = ++argv; 3374 check_action(gettext("Overwrite master with shadow volume?")); 3375 } else { 3376 check_action(gettext("Overwrite every" 3377 " master in this group with its shadow volume?")); 3378 if (find_group_members(group_name) < 1) 3379 dsw_error(gettext("Group does not exist or " 3380 "has no members"), NULL); 3381 volume_list = group_volumes; 3382 } 3383 3384 exit(do_copy(volume_list, Update, ToMaster, WaitForStart)); 3385 } 3386 3387 3388 void 3389 dsw_abort_copy(int argc, char *argv[]) 3390 { 3391 exit(dsw_group_or_single_op(argc, argv, abort_copy)); 3392 } 3393 3394 3395 void 3396 dsw_display_status(int argc, char *argv[]) 3397 { 3398 dsw_config_t parms; 3399 int in_config; 3400 3401 if (argc != 2 && argc != 1) 3402 usage(gettext("Incorrect number of arguments")); 3403 3404 /* "iiadm -i" and "iiadm -i all" are equivalent */ 3405 if (argc == 2 && strcmp("all", argv[1]) != 0) { 3406 in_config = find_shadow_config(argv[1], &parms, NULL); 3407 if (!in_config) { 3408 (void) printf(gettext( 3409 "Volume is not in configuration file\n"), NULL); 3410 (void) fflush(stdout); 3411 (void) strlcpy(parms.shadow_vol, argv[1], DSW_NAMELEN); 3412 } 3413 print_status(&parms, in_config); 3414 } else if (group_name) { 3415 if (find_group_members(group_name) < 1) 3416 dsw_error(gettext("Group does not exist or " 3417 "has no members"), NULL); 3418 for (; *group_volumes; group_volumes++) { 3419 in_config = find_shadow_config(*group_volumes, 3420 &parms, NULL); 3421 if (in_config) 3422 print_status(&parms, in_config); 3423 } 3424 } else { 3425 /* perform action for each line of the stored config file */ 3426 for (setnumber = 1; 3427 !get_dsw_config(setnumber, &parms); setnumber++) { 3428 switch (check_cluster()) { 3429 case II_CLUSTER: 3430 if ((cfg_cluster_tag) && 3431 (strcmp(cfg_cluster_tag, 3432 parms.cluster_tag))) 3433 continue; 3434 break; 3435 case II_CLUSTER_LCL: 3436 if (strlen(parms.cluster_tag)) 3437 continue; 3438 break; 3439 } 3440 print_status(&parms, 1); 3441 } 3442 } 3443 exit(0); 3444 } 3445 3446 void 3447 dsw_display_bitmap(int argc, char *argv[]) 3448 { 3449 dsw_config_t parms; 3450 int in_config; 3451 3452 if (argc != 2) 3453 usage(gettext("Incorrect number of arguments")); 3454 3455 in_config = find_shadow_config(argv[1], &parms, NULL); 3456 if (!in_config) { 3457 (void) printf(gettext( 3458 "Volume is not in configuration file\n"), NULL); 3459 (void) fflush(stdout); 3460 (void) strlcpy(parms.master_vol, argv[1], DSW_NAMELEN); 3461 } 3462 3463 bitmap_op(parms.shadow_vol, 1, 0, 0, 0); 3464 exit(0); 3465 } 3466 3467 3468 /*ARGSUSED*/ 3469 void 3470 dsw_version(int argc, char *argv[]) 3471 { 3472 iiversion(); 3473 exit(0); 3474 } 3475 3476 void 3477 dsw_reset(int argc, char *argv[]) 3478 { 3479 exit(dsw_group_or_single_op(argc, argv, reset)); 3480 } 3481 3482 void 3483 dsw_overflow(int argc, char *argv[]) 3484 { 3485 if (argc != 2) 3486 usage(gettext("Incorrect number of arguments")); 3487 3488 exit(overflow(argv[1])); 3489 } 3490 3491 void 3492 dsw_wait(int argc, char *argv[]) 3493 { 3494 exit(dsw_group_or_single_op(argc, argv, wait_for_copy)); 3495 } 3496 3497 /*ARGSUSED*/ 3498 void 3499 dsw_list_volumes(int argc, char *argv[]) 3500 { 3501 if (argc != 1) 3502 usage(gettext("Incorrect number of arguments")); 3503 3504 list_volumes(); 3505 exit(0); 3506 } 3507 3508 void 3509 dsw_export(int argc, char *argv[]) 3510 { 3511 if (argc != 2) 3512 usage(gettext("Incorrect number of arguments")); 3513 3514 exit(dsw_group_or_single_op(argc, argv, export)); 3515 } 3516 3517 void 3518 dsw_detach(int argc, char *argv[]) 3519 { 3520 (void) dsw_group_or_single_op(argc, argv, detach); 3521 exit(0); 3522 } 3523 3524 void 3525 import(char *shadow_volume, char *bitmap_volume) 3526 { 3527 dsw_config_t parms = {0}; 3528 int rc = 0; 3529 char shd_dg[DSW_NAMELEN]; 3530 char bmp_dg[DSW_NAMELEN]; 3531 3532 /* 3533 * If importing a shadow volume and the shadow volume is already 3534 * configured, we only support this if we are in a Sun Cluster 3535 * and the current user specified a cluster tag of -C local 3536 */ 3537 if (find_shadow_config(shadow_volume, &parms, NULL)) { 3538 dsw_error(gettext("Can't import volume on same node"), NULL); 3539 } 3540 3541 switch (check_cluster()) { 3542 case II_CLUSTER: 3543 case II_CLUSTER_LCL: 3544 (void) check_resource_group(shadow_volume); 3545 if (cfg_cluster_tag) { /* check all volumes are in same dg */ 3546 if (cfg_dgname(shadow_volume, shd_dg, DSW_NAMELEN) 3547 == NULL) 3548 dsw_error(gettext("Shadow volume not in a" 3549 " disk group"), NULL); 3550 if (cfg_dgname(bitmap_volume, bmp_dg, DSW_NAMELEN) 3551 == NULL) 3552 dsw_error(gettext("Bitmap volume not in a" 3553 " disk group"), NULL); 3554 if (strcmp(bmp_dg, shd_dg) != 0) 3555 dsw_error(gettext("Bitmap volume not in" 3556 " same disk group as shadow set members"), 3557 NULL); 3558 } 3559 break; 3560 case II_NOT_CLUSTER: 3561 /* do nothing */ 3562 break; 3563 default: 3564 dsw_error(gettext( 3565 "Unexpected return from check_cluster()"), NULL); 3566 } 3567 3568 /* Local configuration volumes */ 3569 if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) { 3570 dsw_error(gettext("Unable to parse config file"), NULL); 3571 } 3572 3573 reload_vols = LD_DSVOLS | LD_SHADOWS; 3574 conform_name(&shadow_volume); 3575 (void) strcpy(parms.master_vol, II_IMPORTED_SHADOW); 3576 (void) strlcpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN); 3577 (void) strlcpy(parms.bitmap_vol, bitmap_volume, DSW_NAMELEN); 3578 parms.flag = DSW_GOLDEN; 3579 3580 spcs_log("ii", NULL, gettext("Import %s %s"), 3581 parms.shadow_vol, parms.bitmap_vol); 3582 parms.status = spcs_s_ucreate(); 3583 rc = do_ioctl(dsw_fd, DSWIOC_IMPORT, &parms); 3584 if (rc == -1) { 3585 spcs_log("ii", NULL, gettext("Import failed %s %s"), 3586 parms.shadow_vol, parms.bitmap_vol); 3587 dsw_error(gettext("Import failed"), &parms.status); 3588 } 3589 if (perform_autosv()) { 3590 if (cfg_vol_enable(cfg, shadow_volume, cfg_cluster_tag, "ii") 3591 < 0) { 3592 dsw_error(gettext("SV-enable failed"), NULL); 3593 } 3594 /* cfg_commit is called by add_cfg_entry below */ 3595 } 3596 spcs_s_ufree(&parms.status); 3597 add_cfg_entry(&parms); 3598 } 3599 3600 void 3601 dsw_import(int argc, char *argv[]) 3602 { 3603 if (argc != 3) 3604 usage(gettext("Incorrect number of arguments")); 3605 import(argv[1], argv[2]); 3606 3607 exit(0); 3608 } 3609 3610 void 3611 join(char *shadow_volume, char *bitmap_file) 3612 { 3613 dsw_ioctl_t shd; 3614 dsw_config_t conf; 3615 dsw_bitmap_t parms; 3616 int rc = 0; 3617 int size; 3618 FILE *bmpfp; 3619 uchar_t *shd_bitmap = 0; 3620 ii_header_t header; 3621 char dgname[DSW_NAMELEN]; 3622 3623 if (!find_shadow_config(shadow_volume, &conf, &shd)) 3624 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 3625 "group"), NULL); 3626 3627 /* If this is an exportable shadow in the cluster, change ctag */ 3628 if (strlen(conf.cluster_tag) && 3629 (cfg_dgname(shadow_volume, dgname, sizeof (dgname)))) 3630 cfg_resource(cfg, cfg_cluster_tag = strdup(dgname)); 3631 3632 if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) { 3633 dsw_error(gettext("Unable to parse config file"), NULL); 3634 } 3635 reload_vols = LD_DSVOLS | LD_SHADOWS; 3636 conform_name(&shadow_volume); 3637 3638 if ((bmpfp = fopen(bitmap_file, "r")) == NULL) { 3639 perror(bitmap_file); 3640 (void) fprintf(stderr, 3641 gettext("Can't open imported bitmap volume\n")); 3642 exit(1); 3643 } 3644 3645 if (fread(&header, sizeof (header), 1, bmpfp) != 1) { 3646 (void) fprintf(stderr, 3647 gettext("Can't read imported bitmap volume\n")); 3648 exit(1); 3649 } 3650 3651 /* See if this is a bitmap header */ 3652 switch (header.ii_magic) { 3653 case DSW_DIRTY: /* A copy of a enable bitmap volume */ 3654 case DSW_CLEAN: 3655 check_action(gettext("Use the never imported bitmap?")); 3656 break; 3657 case DSW_INVALID: /* A valid diskable secondary bitmap */ 3658 break; 3659 default: 3660 (void) fprintf(stderr, 3661 gettext("Secondary bitmap is not a valid bitmap volume\n")); 3662 exit(1); 3663 } 3664 3665 size = FBA_SIZE(header.ii_copyfba - header.ii_shdfba); 3666 if ((shd_bitmap = malloc(size)) == NULL) { 3667 perror("malloc"); 3668 exit(1); 3669 } 3670 3671 if (fseek(bmpfp, FBA_SIZE(header.ii_shdfba), SEEK_SET)) { 3672 perror("fseek"); 3673 exit(1); 3674 } 3675 3676 if (fread(shd_bitmap, 1, size, bmpfp) != size) { 3677 (void) fprintf(stderr, 3678 gettext("Can't read imported bitmap volume\n")); 3679 exit(1); 3680 } 3681 3682 (void) fclose(bmpfp); 3683 3684 (void) strlcpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN); 3685 parms.shd_bitmap = shd_bitmap; 3686 parms.shd_size = size; 3687 parms.copy_bitmap = NULL; 3688 parms.copy_size = 0; 3689 3690 spcs_log("ii", NULL, gettext("Join %s %s"), 3691 parms.shadow_vol, bitmap_file); 3692 parms.status = spcs_s_ucreate(); 3693 rc = do_ioctl(dsw_fd, DSWIOC_JOIN, &parms); 3694 if (rc == -1) { 3695 spcs_log("ii", NULL, gettext("Join failed %s %s"), 3696 parms.shadow_vol, bitmap_file); 3697 dsw_error(gettext("Join failed"), &parms.status); 3698 } 3699 if (perform_autosv()) { 3700 rc = cfg_vol_enable(cfg, shadow_volume, cfg_cluster_tag, "ii"); 3701 if (rc < 0) { 3702 dsw_error(gettext("SV-enable failed"), NULL); 3703 } 3704 (void) cfg_commit(cfg); 3705 } 3706 spcs_s_ufree(&parms.status); 3707 } 3708 3709 int 3710 params(char *shadow_volume) 3711 { 3712 char *delay = param_delay; 3713 char *unit = param_unit; 3714 dsw_copyp_t parms; 3715 int rc = 0; 3716 int get = 0; 3717 int new_delay; 3718 int new_unit; 3719 3720 (void) strlcpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN); 3721 if (delay == NULL || unit == NULL) { 3722 get = 1; 3723 parms.copy_delay = -1; 3724 parms.copy_unit = -1; 3725 } else { 3726 new_delay = parms.copy_delay = convert_int(delay); 3727 new_unit = parms.copy_unit = convert_int(unit); 3728 } 3729 3730 parms.status = spcs_s_ucreate(); 3731 rc = do_ioctl(dsw_fd, DSWIOC_COPYP, &parms); 3732 if (rc == -1) { 3733 (void) fprintf(stderr, 3734 gettext("Parameter ranges are delay(%d - %d), " 3735 "units(%d - %d)\n"), MIN_THROTTLE_DELAY, MAX_THROTTLE_DELAY, 3736 MIN_THROTTLE_UNIT, MAX_THROTTLE_UNIT); 3737 dsw_error(gettext("Set Copy Parameters failed"), &parms.status); 3738 } 3739 if (!get) 3740 spcs_log("ii", NULL, gettext("Changed copy parameters %s from " 3741 "%d %d to %d %d"), parms.shadow_vol, parms.copy_delay, 3742 parms.copy_unit, new_delay, new_unit); 3743 else 3744 (void) printf(gettext("volume: %s\ncopy delay: %d\ncopy unit:" 3745 " %d\n"), parms.shadow_vol, parms.copy_delay, 3746 parms.copy_unit); 3747 spcs_s_ufree(&parms.status); 3748 return (0); 3749 } 3750 3751 static void 3752 do_attach(dsw_config_t *parms) 3753 { 3754 dsw_config_t io; 3755 int rc; 3756 int check = 0; 3757 3758 spcs_log("ii", NULL, gettext("Attach %s %s"), 3759 parms->shadow_vol, parms->bitmap_vol); 3760 parms->status = spcs_s_ucreate(); 3761 rc = do_ioctl(dsw_fd, DSWIOC_OATTACH, parms); 3762 if (rc == -1) { 3763 check = 1; 3764 /* if overflow() fails, it calls dsw_error to exit */ 3765 (void) overflow(parms->bitmap_vol); 3766 } 3767 spcs_s_ufree(&parms->status); 3768 if (check == 1) { 3769 if (!find_shadow_config(parms->shadow_vol, &io, NULL)) 3770 dsw_error( 3771 gettext("Volume is not in a Point-in-Time Copy " 3772 "group"), NULL); 3773 (void) strlcpy(io.bitmap_vol, parms->bitmap_vol, DSW_NAMELEN); 3774 io.status = spcs_s_ucreate(); 3775 if (do_ioctl(dsw_fd, DSWIOC_OATTACH, &io) == -1) { 3776 spcs_log("ii", NULL, gettext("Attach failed %s %s"), 3777 io.shadow_vol, parms->bitmap_vol); 3778 dsw_error(gettext("Attach failed"), &io.status); 3779 } 3780 spcs_s_ufree(&io.status); 3781 } 3782 } 3783 3784 int 3785 attach(char *shadow_volume) 3786 { 3787 dsw_config_t parms; 3788 dsw_stat_t args; 3789 char shd_dg[DSW_NAMELEN]; 3790 char ovr_dg[DSW_NAMELEN]; 3791 3792 switch (check_cluster()) { 3793 case II_CLUSTER: 3794 case II_CLUSTER_LCL: 3795 (void) check_resource_group(shadow_volume); 3796 if (cfg_cluster_tag) { /* check all volumes are in same dg */ 3797 if (cfg_dgname(shadow_volume, shd_dg, DSW_NAMELEN) 3798 == NULL) 3799 dsw_error(gettext("Shadow volume not in a" 3800 " disk group"), NULL); 3801 if (cfg_dgname(overflow_file, ovr_dg, DSW_NAMELEN) 3802 == NULL) 3803 dsw_error(gettext("Overflow volume not in a" 3804 " disk group"), NULL); 3805 if (strcmp(ovr_dg, shd_dg) != 0) 3806 dsw_error(gettext("Overflow volume not in" 3807 " same disk group as shadow set members"), 3808 NULL); 3809 } 3810 break; 3811 case II_NOT_CLUSTER: 3812 /* do nothing */ 3813 break; 3814 default: 3815 dsw_error(gettext( 3816 "Unexpected return from check_cluster()"), NULL); 3817 } 3818 3819 /* assure that the overflow_file is not an II volume */ 3820 if (find_any_cf_line(overflow_file)) 3821 dsw_error(gettext( 3822 "Overflow volume is already in a Point-in-Time Copy " 3823 "group"), NULL); 3824 3825 /* use find_shadow_config() to find setnumber */ 3826 if (!find_shadow_config(shadow_volume, &parms, NULL)) 3827 dsw_error(gettext("Volume is not in a Point-in-Time Copy " 3828 "group"), NULL); 3829 3830 /* can only attach an overflow volume to dependent, compact shadow */ 3831 (void) strlcpy(args.shadow_vol, shadow_volume, DSW_NAMELEN); 3832 3833 args.status = spcs_s_ucreate(); 3834 if ((do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) || 3835 !(args.stat & DSW_TREEMAP)) 3836 dsw_error(gettext("Not a compact dependent shadow"), NULL); 3837 3838 /* bitmap_vol is overloaded */ 3839 (void) strlcpy(parms.bitmap_vol, overflow_file, DSW_NAMELEN); 3840 3841 do_attach(&parms); 3842 3843 /* add overflow to cfg line */ 3844 (void) sprintf(key, "ii.set%d.overflow", setnumber); 3845 if (cfg_put_cstring(cfg, key, overflow_file, 3846 strlen(overflow_file)) < 0) { 3847 perror("cfg_put_cstring"); 3848 } 3849 (void) cfg_commit(cfg); 3850 return (0); 3851 } 3852 3853 void 3854 dsw_join(int argc, char *argv[]) 3855 { 3856 if (argc != 3) 3857 usage(gettext("Incorrect number of arguments")); 3858 3859 join(argv[1], argv[2]); 3860 exit(0); 3861 } 3862 3863 void 3864 dsw_params(int argc, char *argv[]) 3865 { 3866 if (argc != 4 && argc != 2 && argc != 0) 3867 usage(gettext("Incorrect number of arguments")); 3868 3869 if ((argc == 4) || (argc == 2)) { 3870 param_delay = argv[1]; 3871 param_unit = argv[2]; 3872 if (argc == 4) { 3873 argv[1] = argv[3]; 3874 argv[2] = NULL; 3875 } 3876 } 3877 exit(dsw_group_or_single_op(2, argv, params)); 3878 } 3879 3880 /*ARGSUSED*/ 3881 void 3882 dsw_attach(int argc, char *argv[]) 3883 { 3884 overflow_file = argv[1]; 3885 argv[1] = argv[2]; 3886 (void) dsw_group_or_single_op(2, argv, attach); 3887 exit(0); 3888 } 3889 3890 /*ARGSUSED*/ 3891 void 3892 dsw_olist(int argc, char *argv[]) 3893 { 3894 char *sp, *overflow_list, **vol; 3895 int count, i; 3896 ENTRY item, *found; 3897 char key[ CFG_MAX_KEY ], buf[ CFG_MAX_BUF ]; 3898 3899 overflow_list = get_overflow_list(); 3900 3901 /* count entries */ 3902 count = 0; 3903 for (sp = overflow_list; *sp; sp += DSW_NAMELEN) { 3904 ++count; 3905 } 3906 3907 /* create hash (adding room for suspended overflow volumes) */ 3908 if (hcreate(count + 1024) == 0) { 3909 dsw_error(gettext("Out of memory creating lookup table"), NULL); 3910 /*NOTREACHED*/ 3911 } 3912 3913 if (count > 0) { 3914 /* create memory to store copy of list */ 3915 vol = (char **)calloc(count, sizeof (char *)); 3916 if (!vol) { 3917 dsw_error( 3918 gettext("Out of memory creating lookup table"), 3919 NULL); 3920 /*NOTREACHED*/ 3921 } 3922 3923 /* fill hash */ 3924 for (i = 0, sp = overflow_list; *sp; sp += DSW_NAMELEN, i++) { 3925 3926 /* make copy of string */ 3927 vol[ i ] = (char *)malloc(DSW_NAMELEN + 1); 3928 (void) strlcpy(vol[ i ], sp, DSW_NAMELEN); 3929 3930 item.key = vol[ i ]; 3931 item.data = (char *)0; 3932 (void) hsearch(item, ENTER); 3933 } 3934 } 3935 3936 /* loop through config file entries */ 3937 i = 0; 3938 cfg_rewind(cfg, CFG_SEC_CONF); 3939 3940 /*CONSTCOND*/ 3941 while (1) { 3942 ++i; 3943 (void) snprintf(key, CFG_MAX_KEY, "ii.set%d.overflow", i); 3944 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { 3945 break; 3946 } 3947 3948 /* has this set got an overflow volume? */ 3949 if (!*buf) { 3950 continue; 3951 } 3952 3953 /* look up overflow in hash */ 3954 item.key = buf; 3955 if (count > 0 && (found = hsearch(item, FIND)) != NULL) { 3956 if (0 == (int)found->data) { 3957 (void) printf("%s\n", buf); 3958 found->data = (char *)1; 3959 (void) hsearch(*found, ENTER); 3960 } 3961 } else { 3962 /* must be part of a suspended set */ 3963 (void) printf("%s (attached to suspended set)\n", buf); 3964 item.key = buf; 3965 item.data = (char *)1; 3966 (void) hsearch(item, ENTER); 3967 } 3968 } 3969 3970 exit(0); 3971 } 3972 3973 void 3974 dsw_ostat(int argc, char *argv[]) 3975 { 3976 dsw_ostat_t args; 3977 int stat_flags; 3978 3979 if (argc != 2) 3980 usage(gettext("Incorrect number of arguments")); 3981 3982 (void) strlcpy(args.overflow_vol, argv[1], DSW_NAMELEN); 3983 3984 args.status = spcs_s_ucreate(); 3985 if (do_ioctl(dsw_fd, DSWIOC_OSTAT2, &args) == -1) 3986 dsw_error(gettext("Stat failed"), &args.status); 3987 spcs_s_ufree(&args.status); 3988 3989 if ((args.hversion >= 1) && (args.hmagic == II_OMAGIC)) { 3990 stat_flags = args.flags; 3991 if (stat_flags & IIO_CNTR_INVLD) 3992 (void) printf(gettext("Clean shutdown of volume " 3993 "sets associated with overflow volume " 3994 "did not occur.\n" 3995 "Overflow counters will be inconsistent " 3996 "until new point-in-time(s) are taken.\n")); 3997 } 3998 (void) printf(gettext("Total number of attached shadows: %d\n"), 3999 args.drefcnt); 4000 (void) printf(gettext("Number of currently attached shadows: %d\n"), 4001 args.crefcnt); 4002 (void) printf(gettext("Total number of chunks: %lld\n"), args.nchunks); 4003 (void) printf(gettext("Number of chunks ever allocated: %lld\n"), 4004 args.used); 4005 (void) printf(gettext("Number of used chunks: %lld\n"), 4006 (args.nchunks - args.unused)); 4007 (void) printf(gettext("Number of unused chunks: %lld\n"), args.unused); 4008 exit(0); 4009 } 4010 4011 /*ARGSUSED*/ 4012 void 4013 dsw_move_2_group(int argc, char *argv[]) 4014 { 4015 dsw_config_t parms; 4016 dsw_movegrp_t movegrp; 4017 grptag_t *gdata; 4018 int waserr = 0; 4019 4020 /* handle move to NULL group, or group of all spaces or tabs */ 4021 (void) strncpy(movegrp.new_group, group_name, DSW_NAMELEN); 4022 if ((strlen(group_name) == 0) || (strcspn(group_name, " \t") == 0)) { 4023 group_name = "-"; 4024 bzero(movegrp.new_group, DSW_NAMELEN); 4025 gdata = NULL; 4026 } else { 4027 /* get the ctag for this group (if any) */ 4028 gdata = (grptag_t *)nsc_lookup(volhash, group_name); 4029 } 4030 4031 movegrp.status = spcs_s_ucreate(); 4032 4033 for (++argv; *argv; argv++) { 4034 if (!find_shadow_config(*argv, &parms, NULL)) 4035 dsw_error(gettext("Volume is not in a Point-in-Time " 4036 "Copy group"), NULL); 4037 4038 /* ensure the ctag matches the group */ 4039 if (gdata && *gdata->ctag) { 4040 if (strncmp(parms.cluster_tag, gdata->ctag, 4041 DSW_NAMELEN) != 0) { 4042 (void) fprintf(stderr, "%s: %s %s %s\n", cmdnam, 4043 gettext("unable to move set"), *argv, 4044 gettext("into new group - cluster " 4045 "resource mismatch")); 4046 waserr = 1; 4047 continue; 4048 } 4049 } 4050 4051 /* move the set in the kernel */ 4052 (void) strncpy(movegrp.shadow_vol, parms.shadow_vol, 4053 DSW_NAMELEN); 4054 if (do_ioctl(dsw_fd, DSWIOC_MOVEGRP, &movegrp) < 0) 4055 dsw_error(gettext("Failed to move group in kernel"), 4056 NULL); 4057 4058 /* now update the config */ 4059 (void) sprintf(key, "ii.set%d.group", setnumber); 4060 if (cfg_put_cstring(cfg, key, group_name, 4061 strlen(group_name)) < 0) { 4062 perror("cfg_put_cstring"); 4063 } 4064 (void) cfg_commit(cfg); 4065 } 4066 spcs_s_ufree(&movegrp.status); 4067 cfg_close(cfg); 4068 exit(waserr); 4069 } 4070 4071 void 4072 dsw_list_groups() 4073 { 4074 FILE *pfp; 4075 4076 if ((pfp = popen("/usr/bin/sort -u", "w")) == NULL) { 4077 dsw_error(gettext("Can't open sort program"), NULL); 4078 } 4079 4080 (void) fflush(stdout); 4081 for (setnumber = 1; /*CSTYLED*/; setnumber++) { 4082 (void) snprintf(key, sizeof (key), "ii.set%d.group", setnumber); 4083 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) 4084 break; 4085 4086 /* skip if shadow set is not in any group */ 4087 if (strcmp(buf, "") == 0) 4088 continue; 4089 (void) fprintf(pfp, "%s\n", buf); 4090 } 4091 (void) pclose(pfp); 4092 } 4093 4094 void 4095 dsw_list_group_volumes() 4096 { 4097 FILE *pfp; 4098 4099 if (find_group_members(group_name) < 1) 4100 dsw_error(gettext("Group does not exist or has no members"), 4101 NULL); 4102 4103 if ((pfp = popen("/usr/bin/sort -u", "w")) == NULL) { 4104 dsw_error(gettext("Can't open sort program"), NULL); 4105 } 4106 4107 (void) fflush(stdout); 4108 for (; *group_volumes; group_volumes++) 4109 (void) fprintf(pfp, "%s\n", *group_volumes); 4110 (void) pclose(pfp); 4111 } 4112 4113 static void 4114 load_ii_vols(CFGFILE *cfg) 4115 { 4116 int set, entries; 4117 char *mst, *shd, *buf, **entry; 4118 char *ctag, *group; 4119 mstcount_t *mdata; 4120 shdvol_t *sdata; 4121 grptag_t *gdata; 4122 static int whinged = 0; 4123 4124 if (volhash) { 4125 return; 4126 } 4127 4128 volhash = nsc_create_hash(); 4129 cfg_rewind(cfg, CFG_SEC_CONF); 4130 entries = cfg_get_section(cfg, &entry, "ii"); 4131 for (set = 1; set <= entries; set++) { 4132 buf = entry[set - 1]; 4133 4134 /* grab master volume name */ 4135 mst = strtok(buf, " "); 4136 if (!mst) { 4137 free(buf); 4138 break; 4139 } 4140 4141 /* grab shadow, group & cnode fields */ 4142 shd = strtok(NULL, " "); 4143 (void) strtok(NULL, " "); /* bitmap */ 4144 (void) strtok(NULL, " "); /* mode */ 4145 (void) strtok(NULL, " "); /* overflow */ 4146 ctag = strtok(NULL, " "); /* cnode */ 4147 (void) strtok(NULL, " "); /* options */ 4148 group = strtok(NULL, " "); /* group */ 4149 4150 /* Fix optional tags */ 4151 if (ctag) 4152 ctag += strspn(ctag, "-"); 4153 if (group) 4154 group += strspn(group, "-"); 4155 4156 /* If cluster tags don't match, skip record */ 4157 if ((cfg_cluster_tag && strcmp(ctag, cfg_cluster_tag)) || 4158 (!cfg_cluster_tag && strlen(ctag))) { 4159 free(buf); 4160 continue; 4161 } 4162 4163 /* master volume, may be duplicates */ 4164 mdata = (mstcount_t *)nsc_lookup(volhash, mst); 4165 if (mdata) { 4166 ++mdata->count; 4167 } else { 4168 mdata = (mstcount_t *)malloc(sizeof (mstcount_t)); 4169 mdata->count = 1; 4170 (void) nsc_insert_node(volhash, mdata, mst); 4171 } 4172 4173 /* grab shadow volume name */ 4174 sdata = (shdvol_t *)malloc(sizeof (shdvol_t)); 4175 (void) strncpy(sdata->master, mst, DSW_NAMELEN); 4176 (void) nsc_insert_node(volhash, sdata, shd); 4177 4178 /* No need to continue if no groups or ctags */ 4179 if (!group || !*group || !ctag || !*ctag) { 4180 free(buf); 4181 continue; 4182 } 4183 4184 gdata = (grptag_t *)nsc_lookup(volhash, group); 4185 if (gdata) { 4186 /* group already exists - check ctag */ 4187 if (*ctag && 4188 (strncmp(ctag, gdata->ctag, DSW_NAMELEN) != 0)) { 4189 if (!whinged) { 4190 (void) printf(gettext( 4191 "Warning: multiple " 4192 "cluster resource groups " 4193 "defined within a single " 4194 "I/O group\n")); 4195 whinged = 1; 4196 } 4197 } 4198 } else { 4199 gdata = (grptag_t *)malloc(sizeof (grptag_t)); 4200 (void) strncpy(gdata->ctag, ctag, DSW_NAMELEN); 4201 (void) nsc_insert_node(volhash, gdata, group); 4202 } 4203 4204 free(buf); 4205 } 4206 4207 /* free up any leftovers */ 4208 while (set < entries) 4209 free(entry[set++]); 4210 if (entries) 4211 free(entry); 4212 } 4213 4214 static void 4215 unload_ii_vols() 4216 { 4217 nsc_remove_all(volhash, free); 4218 volhash = 0; 4219 } 4220 4221 static int 4222 perform_autosv() 4223 { 4224 static int result; 4225 static int calculated = 0; 4226 int rc; 4227 4228 #ifdef DEBUG 4229 if (getenv("II_SET_CLUSTER")) 4230 return (1); 4231 #endif 4232 4233 if (calculated) { 4234 return (result); 4235 } 4236 4237 /* 4238 * we only perform auto-sv if we're in a sun cluster or if 4239 * we're on a standalone system. I.e. we don't do auto-sv on Harry 4240 */ 4241 rc = check_cluster(); 4242 4243 if (II_NOT_CLUSTER == rc) { 4244 result = 1; 4245 } else { 4246 result = cfg_issuncluster(); 4247 } 4248 4249 calculated = 1; 4250 return (result); 4251 } 4252 4253 /* 4254 * Returns true if set has had the shadow volume exported. 4255 * Returns false if shadow volume is not exported, or set is suspended. 4256 */ 4257 static int 4258 is_exported(char *set) 4259 { 4260 dsw_stat_t args; 4261 int rc; 4262 4263 (void) strlcpy(args.shadow_vol, set, DSW_NAMELEN); 4264 args.status = spcs_s_ucreate(); 4265 4266 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &args); 4267 spcs_s_ufree(&args.status); 4268 4269 if (-1 == rc) { 4270 /* set must be suspended, or being disabled */ 4271 return (0); 4272 } 4273 4274 return ((args.stat & DSW_SHDEXPORT) == DSW_SHDEXPORT); 4275 } 4276 4277 static void 4278 conform_name(char **path) 4279 { 4280 char *cfgname; 4281 int rc = cfg_get_canonical_name(cfg, *path, &cfgname); 4282 4283 if (rc < 0) { 4284 dsw_error(gettext("Unable to parse config file"), NULL); 4285 } 4286 if (rc) { 4287 (void) printf(" '%s'\n%s\n '%s'\n", *path, 4288 gettext("is currently configured as"), cfgname); 4289 check_action(gettext("Perform operation with indicated volume" 4290 " name?")); 4291 *path = cfgname; 4292 /* 4293 * NOTE: *path ought to be deallocated ('free(*path)') after 4294 * we're done with it, but since this routine is called just 4295 * before we exit, it doesn't really matter 4296 */ 4297 } 4298 } 4299 4300 /* 4301 * verify_groupname(char *, int); 4302 * 4303 * Check the group name for the following rules: 4304 * 1. The name does not start with a '-' 4305 * 2. The name does not contain any space characters as defined by 4306 * isspace(3C). 4307 * If either of these rules are broken, error immediately. The check for a 4308 * leading dash can be skipped if the 'testDash' argument is false. This is to 4309 * allow for the '-g -L' functionality. 4310 * 4311 */ 4312 static void 4313 verify_groupname(char *grp, int testDash) 4314 { 4315 int i; 4316 4317 if (testDash && grp[0] == '-') { 4318 errno = EINVAL; 4319 dsw_error(gettext("group name cannot start with a '-'"), NULL); 4320 } 4321 4322 for (i = 0; grp[i] != '\0'; i++) { 4323 if (isspace(grp[i])) { 4324 errno = EINVAL; 4325 dsw_error(gettext("group name cannot contain a space"), 4326 NULL); 4327 } 4328 } 4329 } 4330 4331 void 4332 check_iishadow(char *shadow_vol) { 4333 int i; 4334 int entries; 4335 char **entry; 4336 char *shost; 4337 char *svol; 4338 char *buf; 4339 void *librdc; 4340 4341 /* 4342 * See if librdc is around 4343 * If not, we can just return 4344 */ 4345 if (librdc = dlopen(RDC_LIB, RTLD_LAZY | RTLD_GLOBAL)) 4346 self_check = (int (*)(char *)) dlsym(librdc, "self_check"); 4347 else { 4348 return; 4349 } 4350 4351 entry = NULL; 4352 entries = cfg_get_section(cfg, &entry, "sndr"); 4353 for (i = 0; i < entries; i++) { 4354 buf = entry[i]; 4355 4356 (void) strtok(buf, " "); /* phost */ 4357 (void) strtok(NULL, " "); /* primary */ 4358 (void) strtok(NULL, " "); /* pbitmap */ 4359 shost = strtok(NULL, " "); /* shost */ 4360 svol = strtok(NULL, " "); /* secondary */ 4361 4362 if (self_check(shost) && (strcmp(shadow_vol, svol) == 0)) { 4363 free(buf); 4364 if (entries) 4365 free(entry); 4366 errno = EINVAL; 4367 dsw_error(gettext( 4368 "shadow volume is in use as SNDR secondary volume"), 4369 NULL); 4370 } 4371 free(buf); 4372 } 4373 4374 (void) dlclose(librdc); 4375 if (entries) 4376 free(entry); 4377 }