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