xref: /titanic_44/usr/src/lib/librdc/common/rdcpersist.c (revision 6e91bba0d6c6bdabbba62cefae583715a4a58e2a)
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 }
717