1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/stat.h>
  28 #include <sys/mkdev.h>
  29 #include <fcntl.h>
  30 #include <unistd.h>
  31 #include <stropts.h>
  32 #include <stdio.h>
  33 #include <errno.h>
  34 #include <libintl.h>
  35 #include <locale.h>
  36 #include <stdlib.h>
  37 
  38 #include <sys/nsctl/rdcerr.h>
  39 #include <sys/nsctl/rdc_ioctl.h>
  40 #include <sys/nsctl/librdc.h>
  41 #include <sys/nsctl/cfg.h>
  42 #include <sys/nsctl/nsc_hash.h>
  43 #include <sys/nsctl/sv.h>
  44 
  45 #include <sys/unistat/spcs_dtrinkets.h>
  46 #include <sys/unistat/spcs_etrinkets.h>
  47 #include <sys/unistat/spcs_s.h>
  48 #include <sys/unistat/spcs_s_u.h>
  49 #include <sys/unistat/spcs_s_impl.h>
  50 #include <sys/unistat/spcs_errors.h>
  51 
  52 typedef struct volcount_s {
  53         int count;
  54 } volcount_t;
  55 
  56 hash_node_t **volhash = NULL;
  57 
  58 char *
  59 config2buf(char *buf, rdcconfig_t *rdc)
  60 {
  61         snprintf(buf, CFG_MAX_BUF, "%s %s %s %s %s %s %s %s %s %s %s",
  62             rdc->phost, rdc->pfile, rdc->pbmp, rdc->shost, rdc->sfile,
  63             rdc->sbmp, rdc->direct, rdc->mode, rdc->group ? rdc->group : "",
  64             rdc->ctag ? rdc->ctag : "", rdc->options ? rdc->options : "");
  65         return (buf);
  66 
  67 }
  68 
  69 /*
  70  * SV type functions.
  71  */
  72 
  73 static void
  74 load_rdc_vols(CFGFILE *cfg)
  75 {
  76         int set;
  77         char key[ CFG_MAX_KEY ];
  78         char buf[ CFG_MAX_BUF ];
  79         char *vol, *bmp, *host1, *host2;
  80         volcount_t *volcount;
  81 
  82         if (volhash) {
  83                 return;
  84         }
  85 
  86         cfg_rewind(cfg, CFG_SEC_CONF);
  87         volhash = nsc_create_hash();
  88         for (set = 1; /*CSTYLED*/; set++) {
  89                 snprintf(key, CFG_MAX_KEY, "sndr.set%d", set);
  90                 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF)) {
  91                         break;
  92                 }
  93 
  94                 host1 = strtok(buf, " ");
  95                 vol = strtok(NULL, " ");
  96                 bmp = strtok(NULL, " ");
  97 
  98                 if (!self_check(host1)) {
  99                         /* next one had better be ours */
 100                         host2 = strtok(NULL, " ");
 101                         vol = strtok(NULL, " ");
 102                         bmp = strtok(NULL, " ");
 103 
 104                         if (!self_check(host2)) {
 105                                 continue;
 106                         }
 107                 }
 108 
 109                 /* primary vol may be used more than once */
 110                 volcount = (volcount_t *)nsc_lookup(volhash, vol);
 111                 if (volcount) {
 112                         volcount->count++;
 113                 } else {
 114                         volcount = (volcount_t *)malloc(sizeof (volcount_t));
 115                         volcount->count = 1;
 116                         nsc_insert_node(volhash, volcount, vol);
 117                 }
 118 
 119                 /* bitmap ought to be only used once */
 120                 volcount = (volcount_t *)nsc_lookup(volhash, bmp);
 121                 if (volcount) {
 122                         /* argh */
 123                         volcount->count++;
 124                 } else {
 125                         volcount = (volcount_t *)malloc(sizeof (volcount_t));
 126                         volcount->count = 1;
 127                         nsc_insert_node(volhash, volcount, bmp);
 128                 }
 129         }
 130 }
 131 
 132 int
 133 sv_enable_one_nocfg(char *vol)
 134 {
 135         struct stat sb;
 136         sv_conf_t svc;
 137         int fd;
 138 
 139         bzero(&svc, sizeof (svc));
 140         if (stat(vol, &sb) != 0) {
 141                 rdc_set_error(NULL, RDC_OS, 0, "unable to stat %s", vol);
 142                 return (-1);
 143         }
 144         if (!S_ISCHR(sb.st_mode)) {
 145                 rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL, "%s is not"
 146                     " a character device", vol);
 147                 return (-1);
 148         }
 149 
 150         svc.svc_major = major(sb.st_rdev);
 151         svc.svc_minor = minor(sb.st_rdev);
 152         strncpy(svc.svc_path, vol, sizeof (svc.svc_path));
 153 
 154         fd = open(SV_DEVICE, O_RDONLY);
 155         if (fd < 0) {
 156                 rdc_set_error(NULL, RDC_OS, 0, 0);
 157                 return (-1);
 158         }
 159 
 160         svc.svc_flag = (NSC_DEVICE | NSC_CACHE);
 161         svc.svc_error = spcs_s_ucreate();
 162 
 163         if (ioctl(fd, SVIOC_ENABLE, &svc) < 0) {
 164                 if (errno != SV_EENABLED) {
 165                         rdc_set_error(&svc.svc_error, RDC_INTERNAL,
 166                             RDC_NONFATAL, 0);
 167                         return (-1);
 168                 }
 169         }
 170 
 171         spcs_log("sv", NULL, gettext("enabled %s"), svc.svc_path);
 172 
 173         close(fd);
 174         return (1);
 175 }
 176 
 177 int
 178 sv_enable_nocfg(rdcconfig_t *rdc)
 179 {
 180         struct stat stbv;
 181         struct stat stbb;
 182         sv_conf_t svcv;
 183         sv_conf_t svcb;
 184         char    vol[NSC_MAXPATH];
 185         char    bmp[NSC_MAXPATH];
 186         int fd = -1;
 187 
 188 
 189         if (self_check(rdc->phost)) {
 190                 strncpy(vol, rdc->pfile, NSC_MAXPATH);
 191                 strncpy(bmp, rdc->pbmp, NSC_MAXPATH);
 192         } else {
 193                 strncpy(vol, rdc->sfile, NSC_MAXPATH);
 194                 strncpy(bmp, rdc->sbmp, NSC_MAXPATH);
 195         }
 196 
 197         bzero(&svcv, sizeof (svcv));
 198         bzero(&svcb, sizeof (svcb));
 199 
 200         if ((stat(vol, &stbv) != 0) || (stat(bmp, &stbb) != 0))
 201                 return (-1);
 202 
 203         if ((!S_ISCHR(stbv.st_mode)) || (!S_ISCHR(stbb.st_mode)))
 204                 return (-1);
 205 
 206         svcv.svc_major = major(stbv.st_rdev);
 207         svcb.svc_minor = minor(stbb.st_rdev);
 208 
 209         strncpy(svcv.svc_path, vol, sizeof (svcv.svc_path));
 210         strncpy(svcb.svc_path, bmp, sizeof (svcb.svc_path));
 211 
 212         fd = open(SV_DEVICE, O_RDONLY);
 213         if (fd < 0)
 214                 return (-1);
 215 
 216         /* SV enable the volume */
 217         svcv.svc_flag = (NSC_DEVICE | NSC_CACHE);
 218         svcv.svc_error = spcs_s_ucreate();
 219 
 220         if (ioctl(fd, SVIOC_ENABLE, &svcv) < 0) {
 221                 if (errno != SV_EENABLED) {
 222                         spcs_log("sv", &svcv.svc_error,
 223                             gettext("unable to enable %s"),
 224                             svcv.svc_path);
 225                         spcs_s_ufree(&svcv.svc_error);
 226                         return (-1);
 227                 }
 228         }
 229 
 230         /* SV enable the bitmap disable the vol on error */
 231         svcb.svc_flag = (NSC_DEVICE | NSC_CACHE);
 232         svcb.svc_error = spcs_s_ucreate();
 233 
 234         if (ioctl(fd, SVIOC_ENABLE, &svcb) < 0) {
 235                 if (errno != SV_EENABLED) {
 236                         spcs_log("sv", &svcb.svc_error,
 237                             gettext("unable to enable %s"),
 238                             svcb.svc_path);
 239                         if (ioctl(fd, SVIOC_DISABLE, &svcv) < 0)
 240                                 spcs_log("sv", &svcv.svc_error,
 241                                     gettext("unable to disable %s"),
 242                                     svcv.svc_path);
 243 
 244                         spcs_s_ufree(&svcv.svc_error);
 245                         spcs_s_ufree(&svcb.svc_error);
 246                         return (-1);
 247                 }
 248         }
 249 
 250 
 251         spcs_log("sv", NULL, gettext("enabled %s"), svcv.svc_path);
 252         spcs_log("sv", NULL, gettext("enabled %s"), svcb.svc_path);
 253         spcs_s_ufree(&svcv.svc_error);
 254         spcs_s_ufree(&svcb.svc_error);
 255 
 256 
 257         if (fd >= 0)
 258                 (void) close(fd);
 259 
 260         return (1);
 261 }
 262 
 263 int
 264 do_autosv_enable(CFGFILE *cfg, rdcconfig_t *rdc)
 265 {
 266         char vol[NSC_MAXPATH];
 267         char bmp[NSC_MAXPATH];
 268 
 269         cfg_load_svols(cfg);
 270         cfg_load_dsvols(cfg);
 271         cfg_load_shadows(cfg);
 272         load_rdc_vols(cfg);
 273 
 274         if (self_check(rdc->phost)) {
 275                 strncpy(vol, rdc->pfile, NSC_MAXPATH);
 276                 strncpy(bmp, rdc->pbmp, NSC_MAXPATH);
 277         } else {
 278                 strncpy(vol, rdc->sfile, NSC_MAXPATH);
 279                 strncpy(bmp, rdc->sbmp, NSC_MAXPATH);
 280         }
 281         if (nsc_lookup(volhash, vol) == NULL) {
 282                 if (cfg_vol_enable(cfg, vol, rdc->ctag, "sndr") < 0) {
 283                         rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
 284                             "auto sv enable failed for %s", vol);
 285                         return (-1);
 286                 }
 287         }
 288         if (nsc_lookup(volhash, bmp) == NULL) {
 289                 if (cfg_vol_enable(cfg, bmp, rdc->ctag, "sndr") < 0) {
 290                         rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
 291                             "auto sv enable failed for %s", vol);
 292                         return (-1);
 293                 }
 294         }
 295 
 296         nsc_remove_all(volhash, free);
 297         volhash = NULL;
 298 
 299         cfg_unload_shadows();
 300         cfg_unload_dsvols();
 301         cfg_unload_svols();
 302 
 303         return (1);
 304 }
 305 
 306 int
 307 do_autosv_disable(CFGFILE *cfg, rdcconfig_t *rdc)
 308 {
 309         char vol[NSC_MAXPATH];
 310         char bmp[NSC_MAXPATH];
 311         volcount_t *vc;
 312 
 313         cfg_load_svols(cfg);
 314         cfg_load_dsvols(cfg);
 315         cfg_load_shadows(cfg);
 316         load_rdc_vols(cfg);
 317 
 318         if (self_check(rdc->phost)) {
 319                 strncpy(vol, rdc->pfile, NSC_MAXPATH);
 320                 strncpy(bmp, rdc->pbmp, NSC_MAXPATH);
 321         } else {
 322                 strncpy(vol, rdc->sfile, NSC_MAXPATH);
 323                 strncpy(bmp, rdc->sbmp, NSC_MAXPATH);
 324         }
 325 
 326         vc = nsc_lookup(volhash, vol);
 327         if (vc && (vc->count == 1)) {
 328                 if (cfg_vol_disable(cfg, vol, rdc->ctag, "sndr") < 0)
 329                         rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
 330                                 "auto sv disable failed for %s", vol);
 331         } else if (!vc) {
 332                 rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
 333                     "Unable to find %s in config", vol);
 334         }
 335         vc = nsc_lookup(volhash, bmp);
 336         if (vc && (vc->count == 1)) {
 337                 if (cfg_vol_disable(cfg, bmp, rdc->ctag, "sndr") < 0)
 338                         rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
 339                                 "auto sv disable failed for %s", bmp);
 340 
 341         } else if (!vc) {
 342                 rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
 343                     "Unable to find %s in config", bmp);
 344         }
 345 
 346         return (1);
 347 
 348 }
 349 
 350 /*
 351  * do sv enables for the appropriate vol
 352  * and bitmap. If called without persistance
 353  * it will follow a chain and sv enable all
 354  * otherwise, it will enable only the one
 355  * set.
 356  */
 357 int
 358 sv_enable(CFGFILE *cfg, rdcconfig_t *rdcs)
 359 {
 360         rdcconfig_t *rdcp = NULL;
 361 
 362         rdcp = rdcs;
 363         if (!rdcp->persist) {
 364 
 365                 return (sv_enable_nocfg(rdcp));
 366 
 367         } else if (cfg == NULL) {
 368 
 369                 return (-1);
 370 
 371         }
 372 
 373         do_autosv_enable(cfg, rdcp);
 374 
 375         return (1);
 376 }
 377 
 378 int
 379 sv_disable(CFGFILE *cfg, rdcconfig_t *rdcs)
 380 {
 381         rdcconfig_t *rdcp;
 382 
 383         rdcp = rdcs;
 384         if (!rdcp->persist) { /* don't disable */
 385 
 386                 return (1);
 387 
 388         } else if (cfg == NULL) {
 389 
 390                 return (-1);
 391 
 392         }
 393 
 394         do_autosv_disable(cfg, rdcp);
 395 
 396         return (1);
 397 
 398 }
 399 
 400 /*
 401  * disable the appropriate bitmap in rdc
 402  * and replace it with bitmap
 403  */
 404 int
 405 sv_reconfig(CFGFILE *cfg, rdcconfig_t *rdc, char *oldbmp, char *newbmp)
 406 {
 407         rdcconfig_t *rdcp;
 408         int fail = 0;
 409 
 410         rdcp = rdc;
 411         if (!rdcp->persist) { /* just enable, don't disable */
 412 
 413                 sv_enable_one_nocfg(newbmp);
 414 
 415         } else if (rdcp->persist) { /* do sv disable and enable */
 416                 volcount_t *vc;
 417 
 418                 cfg_load_svols(cfg);
 419                 cfg_load_dsvols(cfg);
 420                 cfg_load_shadows(cfg);
 421                 load_rdc_vols(cfg);
 422 
 423                 vc = (volcount_t *)nsc_lookup(volhash, oldbmp);
 424                 if (vc && (vc->count == 1)) {
 425                         if (cfg_vol_disable(cfg, oldbmp, rdc->ctag, "sndr") < 0)
 426                                 rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
 427                                     "auto sv disable failed for %s", oldbmp);
 428 
 429                 }
 430                 if (nsc_lookup(volhash, newbmp) == NULL) {
 431                         if (cfg_vol_enable(cfg,
 432                             newbmp, rdc->ctag, "sndr") < 0) {
 433 
 434                                 rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
 435                                     "auto sv enable failed for %s", newbmp);
 436                                 fail++;
 437                         }
 438                 }
 439                 nsc_remove_all(volhash, free);
 440                 volhash = NULL;
 441 
 442                 cfg_unload_shadows();
 443                 cfg_unload_dsvols();
 444                 cfg_unload_svols();
 445                 if (fail)
 446                         return (-1);
 447 
 448         }
 449         return (1);
 450 
 451 }
 452 
 453 /*
 454  * SNDR functions
 455  */
 456 
 457 /*
 458  * add_to_rdc_cfg
 459  * this adds the successfully created rdc sets to libdscfg,
 460  * also, as auto_sv stuff is part of libdscfg, it does the
 461  * auto_sv stuff and enables the correct volumes
 462  */
 463 int
 464 add_to_rdc_cfg(rdcconfig_t *rdcs)
 465 {
 466         CFGFILE *cfg;
 467         rdcconfig_t *rdcp;
 468         char *buf;
 469 
 470 
 471         buf = calloc(CFG_MAX_BUF, sizeof (char));
 472         if (!buf) {
 473                 rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
 474                 return (NULL);
 475         }
 476 
 477         if ((cfg = cfg_open(NULL)) == NULL) {
 478                 rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 479                 return (-1);
 480         }
 481         if ((cfg_lock(cfg, CFG_WRLOCK)) < 0) {
 482                 rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 483                 return (-1);
 484         }
 485 
 486         rdcp = rdcs;
 487         while (rdcp)  {
 488                 buf = config2buf(buf, rdcp);
 489                 if ((sv_enable(cfg, rdcp) < 0) ||
 490                     (cfg_put_cstring(cfg, "sndr", buf, CFG_MAX_BUF) < 0)) {
 491                         rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 492                         free(buf);
 493                         return (-1);
 494                 }
 495                 rdcp = rdcp->next;
 496         }
 497         if (!cfg_commit(cfg)) {
 498                 rdc_set_error(NULL, RDC_DSCFG, 0, NULL);
 499                 return (-1);
 500         }
 501 
 502         cfg_close(cfg);
 503 
 504         return (0);
 505 }
 506 
 507 int
 508 cfg_lookup(CFGFILE *cfg, char *shost, char *sfile)
 509 {
 510         char buf[CFG_MAX_BUF];
 511         char key[CFG_MAX_KEY];
 512         int setnum;
 513         int numsets = 0;
 514 
 515         numsets = cfg_get_num_entries(cfg, "sndr");
 516         for (setnum = 1; setnum <= numsets; setnum++) {
 517                 bzero(key, CFG_MAX_KEY);
 518                 snprintf(key, CFG_MAX_KEY, "sndr.set%d.shost", setnum);
 519                 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
 520                         rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 521                         return (-1);
 522                 }
 523                 if (strncmp(buf, shost, strlen(shost)))
 524                         continue;
 525 
 526                 bzero(key, CFG_MAX_KEY);
 527                 snprintf(key, CFG_MAX_KEY, "sndr.set%d.secondary", setnum);
 528                 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
 529                         rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 530                         return (-1);
 531                 }
 532                 if (strncmp(buf, sfile, strlen(sfile)))
 533                         continue;
 534                 break;
 535         }
 536         return (setnum);
 537 }
 538 
 539 void
 540 remove_from_rdc_cfg(rdcconfig_t *rdcs)
 541 {
 542         CFGFILE *cfg;
 543         rdcconfig_t *rdcp;
 544         char key[CFG_MAX_KEY];
 545 
 546         rdcp = rdcs;
 547         cfg = cfg_open(NULL);
 548         cfg_lock(cfg, CFG_WRLOCK);
 549 
 550         while (rdcp) {
 551                 snprintf(key, CFG_MAX_KEY, "sndr.set%d",
 552                     cfg_lookup(cfg, rdcp->shost, rdcp->sfile));
 553                 if ((sv_disable(cfg, rdcp) < 0) ||
 554                     (cfg_put_cstring(cfg, key, NULL, 0)) < 0) {
 555                         rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 556                 }
 557 
 558                 rdcp = rdcp->next;
 559         }
 560         cfg_commit(cfg);
 561         cfg_close(cfg);
 562 }
 563 /*ARGSUSED*/
 564 int
 565 replace_entry(int offset, char *entry)
 566 {
 567         return (1);
 568 }
 569 
 570 /*
 571  * this will set the value at "field" in dscfg to the
 572  * value contained in entry.
 573  * for things like bitmap reconfigs, only pass one rdc
 574  * not a chain
 575  */
 576 int
 577 replace_cfgfield(rdcconfig_t *rdc, char *field, char *entry)
 578 {
 579         CFGFILE *cfg;
 580         rdcconfig_t *rdcp;
 581         char key[CFG_MAX_KEY];
 582         char newentry[CFG_MAX_BUF];
 583         char oldbmp[CFG_MAX_BUF];
 584         int setnum;
 585         int ispbmp = 0;
 586         int issbmp = 0;
 587 
 588         if (strncmp(field, "pbitmap", NSC_MAXPATH) == 0)
 589                 ispbmp++;
 590         if (strncmp(field, "sbitmap", NSC_MAXPATH) == 0)
 591                 issbmp++;
 592 
 593         bzero(newentry, sizeof (newentry));
 594         if (!entry || strlen(entry) == 0)
 595                 *newentry = '-';
 596         else
 597                 strncpy(newentry, entry, CFG_MAX_BUF);
 598 
 599 
 600         if ((cfg = cfg_open(NULL)) == NULL) {
 601                 rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 602                 return (-1);
 603         }
 604         if ((cfg_lock(cfg, CFG_WRLOCK)) < 0) {
 605                 rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 606                 return (-1);
 607         }
 608 
 609         rdcp = rdc;
 610         while (rdcp) {
 611                 if ((setnum = cfg_lookup(cfg, rdcp->shost, rdcp->sfile)) < 0) {
 612                         rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 613                         return (-1);
 614                 }
 615                 snprintf(key, CFG_MAX_KEY, "sndr.set%d.%s", setnum, field);
 616                 if (!((ispbmp || issbmp) &&
 617                     (cfg_get_cstring(cfg, key, oldbmp, CFG_MAX_BUF)) == 0)) {
 618                         rdc_set_error(NULL, RDC_DSCFG, 0, "unable to get %s",
 619                             key);
 620                 }
 621                 if (((ispbmp && self_check(rdcp->phost)) ||
 622                     (issbmp && self_check(rdcp->shost))) &&
 623                     (sv_reconfig(cfg, rdcp, oldbmp, newentry) < 0)) {
 624                         rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
 625                             "unable to sv reconfig %s to %s", oldbmp, newentry);
 626                         return (-1);
 627                 }
 628 
 629                 if ((cfg_put_cstring(cfg, key, newentry, CFG_MAX_BUF)) < 0) {
 630                         rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 631                         return (-1);
 632                 }
 633                 rdcp = rdcp->next;
 634         }
 635         cfg_commit(cfg);
 636         cfg_close(cfg);
 637         return (1);
 638 }
 639 
 640 /*
 641  * reverse_in_cfg
 642  * used by RDC_OPT_REVERSE_ROLE
 643  * swaps primary info and secondary info
 644  */
 645 int
 646 reverse_in_cfg(rdcconfig_t *rdc)
 647 {
 648         CFGFILE *cfg;
 649         rdcconfig_t *rdcp = NULL;
 650         char key[CFG_MAX_KEY];
 651         int setnum;
 652 
 653         if ((cfg = cfg_open(NULL)) == NULL) {
 654                 rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 655                 return (-1);
 656         }
 657         if ((cfg_lock(cfg, CFG_WRLOCK)) < 0) {
 658                 rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 659                 return (-1);
 660         }
 661 
 662         rdcp = rdc;
 663         while (rdcp) {
 664                 if ((setnum = cfg_lookup(cfg, rdcp->shost, rdcp->sfile)) < 0) {
 665                         rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 666                         goto badconfig;
 667                 }
 668                 bzero(key, CFG_MAX_KEY);
 669                 snprintf(key, CFG_MAX_KEY, "sndr.set%d.phost", setnum);
 670                 if ((cfg_put_cstring(cfg, key, rdcp->shost, CFG_MAX_BUF)) < 0) {
 671                         rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 672                         goto badconfig;
 673                 }
 674                 bzero(key, CFG_MAX_KEY);
 675                 snprintf(key, CFG_MAX_KEY, "sndr.set%d.primary", setnum);
 676                 if ((cfg_put_cstring(cfg, key, rdcp->sfile, CFG_MAX_BUF)) < 0) {
 677                         rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 678                         goto badconfig;
 679                 }
 680                 bzero(key, CFG_MAX_KEY);
 681                 snprintf(key, CFG_MAX_KEY, "sndr.set%d.pbitmap", setnum);
 682                 if ((cfg_put_cstring(cfg, key, rdcp->sbmp, CFG_MAX_BUF)) < 0) {
 683                         rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 684                         goto badconfig;
 685                 }
 686                 bzero(key, CFG_MAX_KEY);
 687                 snprintf(key, CFG_MAX_KEY, "sndr.set%d.shost", setnum);
 688                 if ((cfg_put_cstring(cfg, key, rdcp->phost, CFG_MAX_BUF)) < 0) {
 689                         rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 690                         goto badconfig;
 691                 }
 692                 bzero(key, CFG_MAX_KEY);
 693                 snprintf(key, CFG_MAX_KEY, "sndr.set%d.secondary", setnum);
 694                 if ((cfg_put_cstring(cfg, key, rdcp->pfile, CFG_MAX_BUF)) < 0) {
 695                         rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 696                         goto badconfig;
 697                 }
 698                 bzero(key, CFG_MAX_KEY);
 699                 snprintf(key, CFG_MAX_KEY, "sndr.set%d.sbitmap", setnum);
 700                 if ((cfg_put_cstring(cfg, key, rdcp->pbmp, CFG_MAX_BUF)) < 0) {
 701                         rdc_set_error(NULL, RDC_DSCFG, 0, 0);
 702                         goto badconfig;
 703                 }
 704                 rdcp = rdcp->next;
 705         }
 706         if (!cfg_commit(cfg)) {
 707                 cfg_close(cfg);
 708                 return (-1);
 709         }
 710         cfg_close(cfg);
 711         return (0);
 712 
 713 badconfig:
 714         cfg_close(cfg);
 715         return (-1);
 716 }