xref: /titanic_41/usr/src/cmd/avs/rdc/sndrboot.c (revision dd49f125507979bb2ab505a8daf2a46d1be27051)
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 }
882