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