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 
  28 #include <sys/types.h>
  29 #include <sys/wait.h>
  30 #include <stdio.h>
  31 #include <sys/mnttab.h>
  32 #include <errno.h>
  33 #include <limits.h>
  34 #include <fcntl.h>
  35 #include <strings.h>
  36 #include <stdlib.h>
  37 #include <unistd.h>
  38 
  39 #include <locale.h>
  40 #include <langinfo.h>
  41 #include <libintl.h>
  42 #include <stdarg.h>
  43 #include <netdb.h>
  44 #include <ctype.h>
  45 #include <sys/utsname.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 #include <sys/nsctl/cfg_cluster.h>
  53 
  54 #include <sys/unistat/spcs_s.h>
  55 #include <sys/unistat/spcs_s_u.h>
  56 #include <sys/unistat/spcs_errors.h>
  57 
  58 #include "rdcadm.h"
  59 
  60 /*
  61  * Special re-use of sndrboot to fix SNDR set IDs during post-patch processing
  62  */
  63 #define RDC_CMD_FIXSETIDS       0xFEEDFACE
  64 
  65 /*
  66  * config file user level Dual copy pair structure
  67  */
  68 typedef struct _sd_dual_pair {
  69         char fhost[MAX_RDC_HOST_SIZE];  /* Hostname for primary device */
  70         char fnetaddr[RDC_MAXADDR];     /* Host netaddr for primary device */
  71         char ffile[NSC_MAXPATH];        /* Primary device */
  72         char fbitmap[NSC_MAXPATH];      /* Primary bitmap device */
  73         char thost[MAX_RDC_HOST_SIZE];  /* Hostname for secondary device */
  74         char tnetaddr[RDC_MAXADDR];     /* Host netaddr for secondary device */
  75         char tfile[NSC_MAXPATH];        /* Secondary device */
  76         char tbitmap[NSC_MAXPATH];      /* Secondary bitmap device */
  77         char directfile[NSC_MAXPATH];   /* Local FCAL direct IO volume */
  78         char diskqueue[NSC_MAXPATH];    /* Disk Queue volume */
  79         char group[NSC_MAXPATH];        /* Group name */
  80         char lhost[MAX_RDC_HOST_SIZE];  /* Logical hostname for cluster */
  81         int  doasync;                   /* Device is in sync/async mode */
  82         int  setid;                     /* unique setid of this set */
  83 } _sd_dual_pair_t;
  84 
  85 #include <sys/socket.h>
  86 #include <netinet/in.h>
  87 #include <arpa/inet.h>
  88 #include <netinet/tcp.h>
  89 #include <rpc/rpc_com.h>
  90 #include <rpc/rpc.h>
  91 
  92 #include <sys/nsctl/librdc.h>
  93 
  94 char *ctag = NULL;
  95 
  96 int parseopts(int, char **, int *);
  97 static int rdc_operation(char *, char *, char *, char *, char *, char *, int,
  98     char *, char *, char *, int, char *, int setid);
  99 static int read_libcfg(int);
 100 static void usage(void);
 101 
 102 extern char *basename(char *);
 103 
 104 int rdc_maxsets;
 105 static _sd_dual_pair_t *pair_list;
 106 char *program;
 107 
 108 struct netbuf svaddr;
 109 struct netbuf *svp;
 110 struct netconfig nconf;
 111 struct netconfig *conf;
 112 struct knetconfig knconf;
 113 static int clustered = 0;
 114 static int proto_test = 0;
 115 
 116 #ifdef lint
 117 int
 118 sndrboot_lintmain(int argc, char *argv[])
 119 #else
 120 int
 121 main(int argc, char *argv[])
 122 #endif
 123 {
 124         char fromhost[MAX_RDC_HOST_SIZE];
 125         char tohost[MAX_RDC_HOST_SIZE];
 126         char fromfile[NSC_MAXPATH];
 127         char tofile[NSC_MAXPATH];
 128         char frombitmap[NSC_MAXPATH];
 129         char tobitmap[NSC_MAXPATH];
 130         char directfile[NSC_MAXPATH];
 131         char diskqueue[NSC_MAXPATH];
 132         char group[NSC_MAXPATH];
 133         char lhost[MAX_RDC_HOST_SIZE];
 134         int pairs;
 135         int pid;
 136         int flag = 0;
 137         int doasync;
 138         int rc;
 139         char *required;
 140         int setid;
 141 
 142         (void) setlocale(LC_ALL, "");
 143         (void) textdomain("rdc");
 144 
 145         program = basename(argv[0]);
 146 
 147         rc = rdc_check_release(&required);
 148         if (rc < 0) {
 149                 rdc_err(NULL,
 150                     gettext("unable to determine the current "
 151                     "Solaris release: %s\n"), strerror(errno));
 152         } else if (rc == FALSE) {
 153                 rdc_err(NULL,
 154                     gettext("incorrect Solaris release (requires %s)\n"),
 155                     required);
 156         }
 157 
 158         rdc_maxsets = rdc_get_maxsets();
 159         if (rdc_maxsets == -1) {
 160                 spcs_log("sndr", NULL,
 161                     gettext("%s unable to get maxsets value from kernel"),
 162                     program);
 163 
 164                 rdc_err(NULL,
 165                     gettext("unable to get maxsets value from kernel"));
 166         }
 167 
 168         pair_list = calloc(rdc_maxsets, sizeof (*pair_list));
 169         if (pair_list == NULL) {
 170                 rdc_err(NULL,
 171                     gettext(
 172                         "unable to allocate pair_list"
 173                         " array for %d sets"),
 174                         rdc_maxsets);
 175         }
 176 
 177         if (parseopts(argc, argv, &flag))
 178                 return (1);
 179         pairs = read_libcfg(flag);
 180 
 181         if (flag == RDC_CMD_FIXSETIDS) {
 182                 if (pairs) {
 183                         spcs_log("sndr", NULL, gettext("Fixed %d Remote Mirror"
 184                                     " set IDs"), pairs);
 185 #ifdef DEBUG
 186                         rdc_warn(NULL, gettext("Fixed %d Remote Mirror set "
 187                                     "IDs"), pairs);
 188 #endif
 189                 }
 190                 return (0);
 191         }
 192 
 193         if (pairs == 0) {
 194 #ifdef DEBUG
 195                 rdc_err(NULL,
 196                     gettext("Config contains no dual copy sets"));
 197 #else
 198                 return (0);
 199 #endif
 200         }
 201 
 202         while (pairs--) {
 203                 pid = fork();
 204                 if (pid == -1) {                /* error forking */
 205                         perror("fork");
 206                         continue;
 207                 }
 208 
 209                 if (pid > 0)         /* this is parent process */
 210                         continue;
 211 
 212 /*
 213  * At this point, this is the child process.  Do the operation
 214  */
 215 
 216                 (void) strncpy(fromfile,
 217                     pair_list[pairs].ffile, NSC_MAXPATH);
 218                 (void) strncpy(tofile,
 219                     pair_list[pairs].tfile, NSC_MAXPATH);
 220                 (void) strncpy(frombitmap,
 221                     pair_list[pairs].fbitmap, NSC_MAXPATH);
 222                 (void) strncpy(fromhost,
 223                     pair_list[pairs].fhost, MAX_RDC_HOST_SIZE);
 224                 (void) strncpy(tohost,
 225                     pair_list[pairs].thost, MAX_RDC_HOST_SIZE);
 226                 (void) strncpy(tobitmap,
 227                     pair_list[pairs].tbitmap, NSC_MAXPATH);
 228                 (void) strncpy(directfile,
 229                     pair_list[pairs].directfile, NSC_MAXPATH);
 230                 (void) strncpy(diskqueue,
 231                     pair_list[pairs].diskqueue, NSC_MAXPATH);
 232                 (void) strncpy(group,
 233                     pair_list[pairs].group, NSC_MAXPATH);
 234                 (void) strncpy(lhost,
 235                     pair_list[pairs].lhost, MAX_RDC_HOST_SIZE);
 236 
 237                 doasync = pair_list[pairs].doasync;
 238                 setid = pair_list[pairs].setid;
 239                 if (rdc_operation(fromhost, fromfile, frombitmap,
 240                     tohost, tofile, tobitmap, flag, directfile, group,
 241                     diskqueue, doasync, lhost, setid)
 242                     < 0) {
 243                         exit(255);
 244                 }
 245 
 246                 exit(0);
 247         }
 248 
 249         while ((wait((int *)0) > 0))
 250                 ;
 251         return (0);
 252 }
 253 
 254 static int
 255 rdc_operation(fromhost, fromfile, frombitmap, tohost, tofile,
 256     tobitmap, flag, directfile, group, diskqueue, doasync,
 257     lhost, setid)
 258 char *fromhost, *fromfile, *frombitmap;
 259 char *tohost, *tofile, *tobitmap;
 260 int flag, doasync;
 261 char *directfile;
 262 char *group, *diskqueue;
 263 int setid;
 264 char *lhost;
 265 {
 266         const int getaddr = (flag == RDC_CMD_RESUME);
 267         const int rpcbind = !getaddr;
 268         rdc_config_t parms;
 269         int ret;
 270         spcs_s_info_t ustatus;
 271         struct hostent *hp;
 272         char fromname[MAXHOSTNAMELEN], toname[MAXHOSTNAMELEN];
 273         struct t_info tinfo;
 274         int i;
 275 
 276         conf = &nconf;
 277         bzero(&fromname, MAXHOSTNAMELEN);
 278         bzero(&toname, MAXHOSTNAMELEN);
 279 
 280         hp = gethost_byname(fromhost);
 281         if (hp == NULL) {
 282                 spcs_log("sndr", NULL,
 283                     gettext("%s gethost_byname failed for %s"),
 284                     program, fromhost);
 285         }
 286         if (strcmp(hp->h_name, fromhost) == 0)
 287                 (void) strncpy(fromname, hp->h_name, MAXHOSTNAMELEN);
 288         else {
 289         for (i = 0; hp->h_aliases[i] != NULL; i++) {
 290                 if (strcmp(hp->h_aliases[i], fromhost) == 0)
 291                         (void) strncpy(fromname, hp->h_aliases[i],
 292                             MAXHOSTNAMELEN);
 293                 }
 294         }
 295         if (fromname[0] == '\0') {
 296                 spcs_log("sndr", NULL,
 297                     gettext("%s host %s is not local"),
 298                     program, fromhost);
 299                 rdc_err(NULL, gettext("Host %s is not local"),
 300                     fromhost);
 301         }
 302         hp = gethost_byname(tohost);
 303         if (hp == NULL) {
 304                 spcs_log("sndr", NULL,
 305                     gettext("%s gethost_byname failed for %s"),
 306                     program, tohost);
 307         }
 308         if (strcmp(hp->h_name, tohost) == 0)
 309                 (void) strncpy(toname, hp->h_name, MAXHOSTNAMELEN);
 310         else {
 311         for (i = 0; hp->h_aliases[i] != NULL; i++) {
 312                 if (strcmp(hp->h_aliases[i], tohost) == 0)
 313                         (void) strncpy(toname, hp->h_aliases[i],
 314                             MAXHOSTNAMELEN);
 315                 }
 316         }
 317         if (toname[0] == '\0') {
 318                 spcs_log("sndr", NULL,
 319                     gettext("%s host %s is not local"),
 320                     program, tohost);
 321                 rdc_err(NULL, gettext("Host %s is not local"),
 322                     tohost);
 323         }
 324 
 325         if (self_check(fromname) && self_check(toname)) {
 326                 spcs_log("sndr", NULL,
 327                     gettext("%s Both %s and %s are local"),
 328                     program, fromhost, tohost);
 329                 rdc_err(NULL, gettext("Both %s and %s are local"),
 330                     fromhost, tohost);
 331         }
 332 
 333         /*
 334          * Now build up the address for each host including port and transport
 335          */
 336         if (getaddr) {
 337                 svp = get_addr(toname, RDC_PROGRAM, RDC_VERS_MIN,
 338                         &conf, proto_test?NC_UDP: NULL, "rdc", &tinfo, rpcbind);
 339 
 340                 if (svp == NULL) {
 341 #ifdef DEBUG
 342                         (void) printf("get_addr failed for Ver 4 %s\n", toname);
 343 #endif
 344                         spcs_log("sndr", NULL,
 345                             gettext("%s get_addr failed for Ver 4"),
 346                             program);
 347                         return (-1);
 348                 }
 349                 svaddr = *svp;
 350         } else {
 351                 bzero(&svaddr, sizeof (svaddr));
 352         }
 353 
 354         parms.rdc_set->secondary.addr.len = svaddr.len;
 355         parms.rdc_set->secondary.addr.maxlen = svaddr.maxlen;
 356         parms.rdc_set->secondary.addr.buf = (void *)svaddr.buf;
 357 
 358 #ifdef DEBUG_ADDR
 359         (void) fprintf(stderr,
 360                 "secondary buf %x len %d\n", svaddr.buf, svaddr.len);
 361 
 362         for (i = 0; i < svaddr.len; i++)
 363                 (void) printf("%u ", svaddr.buf[i]);
 364         (void) printf("\n");
 365 #endif
 366 
 367         if (getaddr) {
 368                 svp = get_addr(fromname, RDC_PROGRAM, RDC_VERS_MIN,
 369                         &conf, proto_test?NC_UDP: NULL, "rdc", &tinfo, rpcbind);
 370                 if (svp == NULL) {
 371 #ifdef DEBUG
 372                         (void) printf("get_addr failed for Ver 4 %s\n",
 373                             fromname);
 374 #endif
 375                         return (-1);
 376                 }
 377                 svaddr = *svp;
 378         } else {
 379                 ;
 380                 /*EMPTY*/
 381         }
 382         parms.rdc_set->primary.addr.len = svaddr.len;
 383         parms.rdc_set->primary.addr.maxlen = svaddr.maxlen;
 384         parms.rdc_set->primary.addr.buf =
 385                                 (void *)svaddr.buf;
 386 
 387 #ifdef DEBUG_ADDR
 388         (void) fprintf(stderr, "primary buf %x len %d\n",
 389             svaddr.buf, svaddr.len);
 390         for (i = 0; i < svaddr.len; i++)
 391                 (void) printf("%u ", svaddr.buf[i]);
 392         (void) printf("\n");
 393 #endif
 394 
 395         if (getaddr) {
 396                 (void) convert_nconf_to_knconf(conf, &knconf);
 397 #ifdef DEBUG_ADDR
 398                 (void) printf("knconf %x %s %s %x\n", knconf.knc_semantics,
 399                     knconf.knc_protofmly, knconf.knc_proto, knconf.knc_rdev);
 400 #endif
 401                 parms.rdc_set->netconfig = &knconf;
 402         } else {
 403                 parms.rdc_set->netconfig = NULL;
 404         }
 405         if (!clustered && !self_check(fromname) && !self_check(toname)) {
 406                 spcs_log("sndr", NULL,
 407                     gettext("%s Neither %s nor %s is local"),
 408                     program, fromhost, tohost);
 409                 rdc_err(NULL, gettext("Neither %s nor %s is local"),
 410                     fromhost, tohost);
 411         }
 412         (void) strncpy(parms.rdc_set->primary.intf, fromhost,
 413             MAX_RDC_HOST_SIZE);
 414         (void) strncpy(parms.rdc_set->primary.file, fromfile, NSC_MAXPATH);
 415         (void) strncpy(parms.rdc_set->primary.bitmap, frombitmap, NSC_MAXPATH);
 416 
 417         (void) strncpy(parms.rdc_set->secondary.intf, tohost,
 418             MAX_RDC_HOST_SIZE);
 419         (void) strncpy(parms.rdc_set->secondary.file, tofile, NSC_MAXPATH);
 420         (void) strncpy(parms.rdc_set->secondary.bitmap, tobitmap, NSC_MAXPATH);
 421 
 422         (void) strncpy(parms.rdc_set->group_name, group, NSC_MAXPATH);
 423         (void) strncpy(parms.rdc_set->disk_queue, diskqueue, NSC_MAXPATH);
 424 
 425         parms.rdc_set->maxqfbas = maxqfbas;
 426         parms.rdc_set->maxqitems = maxqitems;
 427         parms.rdc_set->autosync = autosync;
 428         parms.rdc_set->asyncthr = asyncthr;
 429         parms.rdc_set->setid = setid;
 430 
 431         /* gethostid(3c) is defined to return a 32bit value */
 432         parms.rdc_set->syshostid = (int32_t)gethostid();
 433 
 434         parms.command = 0;
 435         parms.options = 0;
 436         parms.command = flag;
 437 
 438         if (flag == RDC_CMD_RESUME) {
 439                 if (doasync)
 440                         parms.options |= RDC_OPT_ASYNC;
 441                 else
 442                         parms.options |= RDC_OPT_SYNC;
 443         }
 444         if (clustered) {
 445                 if (!ctag)
 446                         goto noconfig;
 447                 if (strcmp(ctag, "-") == 0)
 448                         goto noconfig;
 449 
 450 #ifdef DEBUG
 451                 (void) fprintf(stderr, "logical hostname: %s\n", lhost);
 452 #endif
 453 
 454                 if (strcmp(lhost, fromname) == 0) {
 455                         parms.options |= RDC_OPT_PRIMARY;
 456                         (void) strncpy(parms.rdc_set->direct_file, directfile,
 457                             NSC_MAXPATH);
 458 
 459                 } else {
 460                         parms.options |= RDC_OPT_SECONDARY;
 461                         parms.rdc_set->direct_file[0] = 0; /* no fcal direct */
 462                 }
 463         } else {
 464 noconfig:
 465                 /*
 466                  * If not clustered, don't resume sndr sets with lhost
 467                  */
 468                 if ((flag == RDC_CMD_RESUME) && lhost && strlen(lhost))
 469                         return (0);
 470 
 471                 if (self_check(fromname)) {
 472                         parms.options |= RDC_OPT_PRIMARY;
 473                         (void) strncpy(parms.rdc_set->direct_file, directfile,
 474                             NSC_MAXPATH);
 475                 } else {
 476                         parms.options |= RDC_OPT_SECONDARY;
 477                         parms.rdc_set->direct_file[0] = 0; /* no fcal direct */
 478                 }
 479         }
 480 
 481         ustatus = spcs_s_ucreate();
 482 
 483         errno = 0;
 484         ret = RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus);
 485         if (ret != SPCS_S_OK) {
 486 
 487                 /* Surpress error messages for suspend on cluster elements */
 488                 if ((flag == RDC_CMD_SUSPEND) && (errno == RDC_EALREADY) &&
 489                         !clustered && lhost && strlen(lhost)) {
 490                         spcs_s_ufree(&ustatus);
 491                         return (0);
 492                 }
 493 
 494                 (void) fprintf(stderr,
 495                         gettext("Remote Mirror: %s %s %s %s %s %s\n"),
 496                         fromhost, fromfile,
 497                         frombitmap, tohost, tofile, tobitmap);
 498 
 499                 if (errno == RDC_EEINVAL) {
 500                         spcs_log("sndr", NULL,
 501                             gettext("%s %s %s %s %s %s %s %s\n%s"),
 502                             program, rdc_decode_flag(flag, parms.options),
 503                             fromhost, fromfile, frombitmap,
 504                             tohost, tofile, tobitmap,
 505                             gettext("invalid command option"));
 506                         rdc_err(&ustatus,
 507                             gettext("Remote Mirror: invalid command option "
 508                                     "'%s'"), rdc_decode_flag(flag,
 509                                     parms.options));
 510                 } else {
 511                         spcs_log("sndr", &ustatus,
 512                             gettext("%s %s %s %s %s %s %s %s"),
 513                             program, rdc_decode_flag(flag, parms.options),
 514                             fromhost, fromfile, frombitmap,
 515                             tohost, tofile, tobitmap);
 516                         rdc_err(&ustatus, 0);
 517                 }
 518         }
 519 
 520         spcs_log("sndr", NULL,
 521             gettext("%s %s %s %s %s %s %s %s\nSuccessful"),
 522             program, rdc_decode_flag(flag, parms.options),
 523             fromhost, fromfile, frombitmap, tohost, tofile, tobitmap);
 524 
 525         spcs_s_ufree(&ustatus);
 526         return (0);
 527 }
 528 /*
 529  * assign setid's to any existing
 530  * sets without setids, making sure of course NOT to re-use a setid
 531  */
 532 int
 533 update_setids(CFGFILE *cfg, int *no_id, int highest)
 534 {
 535         int setid;
 536         char buf[CFG_MAX_BUF];
 537         char key[CFG_MAX_KEY];
 538         char *ctag;
 539 
 540         /* If in a Sun Cluster, SetIDs need to have a ctag */
 541         if ((ctag = cfg_get_resource(cfg)) != NULL) {
 542                 ctag = strdup(ctag);
 543                 cfg_resource(cfg, "setid-ctag");
 544         }
 545 
 546         /*
 547          * Paranoia. IF there are any sets with setids, we don't
 548          * want to re-use their number.
 549          */
 550         if (highest > get_new_cfg_setid(cfg)) {
 551                 bzero(&buf, sizeof (buf));
 552                 (void) sprintf(buf, "%d", highest);
 553                 if (cfg_put_cstring(cfg, "setid.set1.value", buf,
 554                     sizeof (buf)) < 0)
 555                         rdc_warn(NULL, gettext("sndrboot: Unable to store "
 556                             "new setid"));
 557         }
 558 
 559         for (setid = 0; no_id[setid]; setid++) {
 560                 bzero(&buf, sizeof (buf));
 561                 bzero(&key, sizeof (key));
 562                 (void) sprintf(buf, "%d", get_new_cfg_setid(cfg));
 563                 (void) sprintf(key, "sndr.set%d.options", no_id[setid]);
 564                 if (cfg_put_options(cfg, CFG_SEC_CONF, key, "setid", buf) < 0)
 565                         rdc_warn(NULL, gettext("sndrboot: Unable to store "
 566                             "unique setid"));
 567 
 568                 pair_list[no_id[setid] - 1].setid = atoi(buf);
 569         }
 570 
 571         /* Restore old ctag if in a Sun Cluster */
 572         if (ctag) {
 573                 cfg_resource(cfg, ctag);
 574                 free(ctag);
 575         }
 576 
 577         if (cfg_commit(cfg) < 0)
 578                 rdc_err(NULL, gettext("sndrboot: Failed to commit setids"));
 579 
 580         return (setid);
 581 }
 582 
 583 /*
 584  * this is called when the option lghn is no available in libdscfg
 585  * that should only happen on an upgrade.
 586  * cfg write lock must be held across this function
 587  */
 588 char *
 589 get_lghn(CFGFILE *cfg, char *ctag, int setnum, int flag)
 590 {
 591         FILE *pipe;
 592         char rsgrp[SCCONF_MAXSTRINGLEN];
 593         char cmd[SCCONF_MAXSTRINGLEN];
 594         static char lhostname[MAX_RDC_HOST_SIZE];
 595         char key[CFG_MAX_KEY];
 596         int rc;
 597 
 598         if (ctag == NULL)
 599                 goto fail;
 600 
 601         bzero(&lhostname, sizeof (lhostname));
 602 
 603         (void) sprintf(rsgrp, "%s-stor-rg", ctag);
 604 /* BEGIN CSTYLED */
 605         rc = snprintf(cmd, SCCONF_MAXSTRINGLEN,
 606             "/usr/cluster/bin/scrgadm -pvv | fgrep HostnameList \
 607 | fgrep %s | fgrep value | awk -F: '{ print $4 }'", rsgrp);
 608 /* END CSTYLED */
 609 
 610         if (rc < 0) {
 611                 rdc_err(NULL, gettext("Error getting scrgadm output"));
 612         }
 613 
 614         pipe = popen(cmd, "r");
 615 
 616         if (pipe == NULL) {
 617                 rdc_err(NULL, gettext("Error opening pipe"));
 618         }
 619         rc = fscanf(pipe, "%s", lhostname);
 620         (void) pclose(pipe);
 621 
 622         if (rc != 1) {
 623                 rdc_err(NULL, gettext("Unable to get logical host"));
 624         }
 625 
 626         /* not really failing, but suspend does not have the config lock */
 627         if (flag == RDC_CMD_SUSPEND)
 628                 goto fail;
 629 
 630         bzero(&key, sizeof (key));
 631         (void) snprintf(key, sizeof (key), "sndr.set%d.options", setnum);
 632         if (cfg_put_options(cfg, CFG_SEC_CONF, key, "lghn", lhostname) < 0)
 633                 rdc_warn(NULL, gettext("sndrboot: Unable to store logical "
 634                     "host name in configuration database"));
 635 
 636         if (cfg_commit(cfg) < 0)
 637                 rdc_err(NULL,
 638                     gettext("sndrboot: Failed to commit logical host name"));
 639 
 640 fail:
 641         return (lhostname);
 642 
 643 }
 644 
 645 /*
 646  * read_libcfg()
 647  *
 648  * DESCRIPTION: Read the relevant config info via libcfg
 649  *
 650  * Outputs:
 651  *      int i                   Number of pairs of devices
 652  *
 653  * Side Effects: The 0 to i-1 entries in the pair_list are filled.
 654  *
 655  */
 656 static int
 657 read_libcfg(int flag)
 658 {
 659         char fromhost[MAX_RDC_HOST_SIZE];
 660         char fromfile[NSC_MAXPATH];
 661         char frombitmap[NSC_MAXPATH];
 662         char tohost[MAX_RDC_HOST_SIZE];
 663         char tofile[NSC_MAXPATH];
 664         char tobitmap[NSC_MAXPATH];
 665         char directfile[NSC_MAXPATH];
 666         char diskqueue[NSC_MAXPATH];
 667         char group[NSC_MAXPATH];
 668         char lhost[MAX_RDC_HOST_SIZE];
 669         char sync[16];
 670         char setid[64];
 671         int doasync;
 672         CFGFILE *cfg;
 673         int i, j = 0;
 674         int rc;
 675         char buf[CFG_MAX_BUF];
 676         char key[CFG_MAX_KEY];
 677         char dummy[NSC_MAXPATH];
 678         int setnumber;
 679         int numsets;
 680         int highest = 0;
 681         char lghn[5];
 682         int *no_id;
 683 
 684 
 685         if ((cfg = cfg_open("")) == NULL)
 686                 rdc_err(NULL, gettext("Error opening config"));
 687 
 688         /*
 689          * If RDC_CMD_FIXSETIDS, we were called during post-patch install
 690          * Acquire a write-lock on the cfg_lock(), so the code can attempt
 691          * to fix setIDs
 692          */
 693         if (flag == RDC_CMD_FIXSETIDS) {
 694                 if (!cfg_lock(cfg, CFG_WRLOCK))
 695                         rdc_err(NULL, gettext("Error write locking config"));
 696                 cfg_resource(cfg, NULL);
 697         } else {
 698                 if (!cfg_lock(cfg, CFG_RDLOCK))
 699                         rdc_err(NULL, gettext("Error locking config"));
 700                 cfg_resource(cfg, ctag);
 701         }
 702 
 703         if ((numsets = cfg_get_num_entries(cfg, "sndr")) < 0)
 704                 rdc_err(NULL, gettext("Unable to get set info from config"));
 705 
 706         no_id = (int *)calloc(numsets + 1, sizeof (int));
 707         if (!no_id)
 708                 rdc_err(NULL, gettext("No memory"));
 709 
 710 
 711         (void) snprintf(lghn, sizeof (lghn), "lghn");
 712 
 713         for (i = 0; i < rdc_maxsets; i++) {
 714                 setnumber = i + 1;
 715 
 716                 bzero(buf, CFG_MAX_BUF);
 717                 (void) snprintf(key, sizeof (key), "sndr.set%d", setnumber);
 718                 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
 719                         break;
 720 
 721                 rc = sscanf(buf, "%s %s %s %s %s %s %s %s %s %s %s %s",
 722                     fromhost, fromfile, frombitmap, tohost, tofile, tobitmap,
 723                         directfile, sync, group, dummy, dummy, diskqueue);
 724                 if (rc != 12)
 725                         rdc_err(NULL, gettext("cfg input error (%d)"), rc);
 726 
 727                 if (strcmp(directfile, "ip") == 0)
 728                         (void) strcpy(directfile, "");
 729 
 730                 if (strcmp(group, "-") == 0)
 731                         (void) strcpy(group, "");
 732 
 733                 if (strcmp(diskqueue, "-") == 0)
 734                         (void) strcpy(diskqueue, "");
 735 
 736                 (void) snprintf(key, sizeof (key),
 737                         "sndr.set%d.options", setnumber);
 738 
 739                 if (cfg_get_single_option(cfg, CFG_SEC_CONF, key,
 740                         lghn, lhost, MAX_RDC_HOST_SIZE) < 0)
 741                         (void) strcpy(lhost,
 742                             get_lghn(cfg, ctag, setnumber, flag));
 743 
 744                 if (strcmp(sync, "sync") == 0)
 745                         doasync = 0;
 746                 else if (strcmp(sync, "async") == 0)
 747                         doasync = 1;
 748                 else {
 749                         cfg_close(cfg);
 750                         rdc_err(NULL,
 751                             gettext("Set %s:%s neither sync nor async"),
 752                             tohost, tofile);
 753                 }
 754 
 755                 (void) strncpy(pair_list[i].fhost, fromhost,
 756                     MAX_RDC_HOST_SIZE);
 757                 (void) strncpy(pair_list[i].ffile, fromfile, NSC_MAXPATH);
 758                 (void) strncpy(pair_list[i].fbitmap, frombitmap, NSC_MAXPATH);
 759                 (void) strncpy(pair_list[i].thost, tohost, MAX_RDC_HOST_SIZE);
 760                 (void) strncpy(pair_list[i].tfile, tofile, NSC_MAXPATH);
 761                 (void) strncpy(pair_list[i].tbitmap, tobitmap, NSC_MAXPATH);
 762                 (void) strncpy(pair_list[i].directfile, directfile,
 763                     NSC_MAXPATH);
 764                 (void) strncpy(pair_list[i].diskqueue, diskqueue,
 765                     NSC_MAXPATH);
 766                 (void) strncpy(pair_list[i].group, group, NSC_MAXPATH);
 767                 (void) strncpy(pair_list[i].lhost, lhost, MAX_RDC_HOST_SIZE);
 768                 pair_list[i].doasync = doasync;
 769 
 770                 if (cfg_get_single_option(cfg, CFG_SEC_CONF, key, "setid",
 771                     setid, sizeof (setid)) < 0) {
 772                         no_id[j++] = setnumber;
 773                 }
 774                 pair_list[i].setid = atoi(setid);
 775 
 776                 if (pair_list[i].setid > highest)
 777                         highest = pair_list[i].setid;
 778 
 779                 if (gethost_netaddrs(fromhost, tohost,
 780                     (char *)pair_list[i].fnetaddr,
 781                     (char *)pair_list[i].tnetaddr) < 0) {
 782                         cfg_close(cfg);
 783                         spcs_log("sndr", NULL,
 784                             gettext("%s unable to determine IP addresses "
 785                             "for hosts %s %s"), program, fromhost, tohost);
 786                         rdc_err(NULL, gettext("unable to determine IP "
 787                             "addresses for hosts %s, %s"), fromhost, tohost);
 788                 }
 789         }
 790         /*
 791          * fix any lost set ids if possible, also deal with upgrade
 792          */
 793         if (j > 0 && flag == RDC_CMD_FIXSETIDS) {
 794                 (void) update_setids(cfg, no_id, highest);
 795                 i = j;  /* Set number of fixups */
 796         }
 797         free(no_id);
 798         cfg_close(cfg);
 799         return (i);
 800 }
 801 
 802 
 803 int
 804 parseopts(argc, argv, flag)
 805 int argc;
 806 char **argv;
 807 int *flag;
 808 {
 809         int  errflag = 0;
 810         char c;
 811         char inval = 0;
 812 #ifdef DEBUG
 813         while ((c = getopt(argc, argv, "C:Urs")) != -1) {
 814 #else
 815         while ((c = getopt(argc, argv, "C:rs")) != -1) {
 816 #endif
 817                 switch (c) {
 818                 case 'C':
 819                         clustered = TRUE;
 820                         ctag = optarg;
 821                         break;
 822 #ifdef DEBUG
 823                 case 'U':
 824                         proto_test = 1;
 825                         break;
 826 #endif
 827                 case 'r':
 828                         if (*flag)
 829                                 inval = 1;
 830                         *flag = RDC_CMD_RESUME;
 831                         break;
 832                 case 's':
 833                         if (*flag)
 834                                 inval = 1;
 835                         *flag = RDC_CMD_SUSPEND;
 836                         break;
 837                 case '?':
 838                         errflag++;
 839                 }
 840         }
 841 
 842         /*
 843          * Special fix to address no SetIds in AVS 3.1 to 3.2 install + patch
 844          * Adjust set IDs, if someone invokes the following invalid command
 845          *
 846          *      /use/sbin/sndrboot -C post-patch-setids -r -s
 847          *
 848          * Command will be called in post-install of the patch containing fix
 849          *
 850          */
 851         if (clustered && (strcmp(ctag, "post-patch-setids") == 0) &&
 852             *flag && inval) {
 853                 *flag = RDC_CMD_FIXSETIDS;
 854                 return (0);
 855         }
 856 
 857         if (inval) {
 858                 rdc_warn(NULL, gettext("Invalid argument combination"));
 859                 errflag = 1;
 860         }
 861 
 862         if (!*flag || errflag) {
 863                 usage();
 864                 return (-1);
 865         }
 866 
 867         return (0);
 868 }
 869 
 870 static void
 871 usage()
 872 {
 873         (void) fprintf(stderr, gettext("usage:\n"));
 874         (void) fprintf(stderr,
 875                 gettext("\t%s -r [-C tag]\t\t"
 876                         "resume\n"), program);
 877 
 878         (void) fprintf(stderr,
 879                 gettext("\t%s -s [-C tag]\t\t"
 880                         "suspend\n"), program);
 881 }