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