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 *
config2buf(char * buf,rdcconfig_t * rdc)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
load_rdc_vols(CFGFILE * cfg)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
sv_enable_one_nocfg(char * vol)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
sv_enable_nocfg(rdcconfig_t * rdc)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
do_autosv_enable(CFGFILE * cfg,rdcconfig_t * rdc)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
do_autosv_disable(CFGFILE * cfg,rdcconfig_t * rdc)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
sv_enable(CFGFILE * cfg,rdcconfig_t * rdcs)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
sv_disable(CFGFILE * cfg,rdcconfig_t * rdcs)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
sv_reconfig(CFGFILE * cfg,rdcconfig_t * rdc,char * oldbmp,char * newbmp)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
add_to_rdc_cfg(rdcconfig_t * rdcs)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
cfg_lookup(CFGFILE * cfg,char * shost,char * sfile)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
remove_from_rdc_cfg(rdcconfig_t * rdcs)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
replace_entry(int offset,char * entry)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
replace_cfgfield(rdcconfig_t * rdc,char * field,char * entry)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
reverse_in_cfg(rdcconfig_t * rdc)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 }
717