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 }