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 #include <sys/types.h>
28 #include <sys/utsname.h>
29 #include <sys/wait.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <values.h>
33 #include <limits.h>
34 #include <fcntl.h>
35 #include <strings.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <sys/stat.h>
39
40 #include <locale.h>
41 #include <langinfo.h>
42 #include <libintl.h>
43 #include <stdarg.h>
44 #include <netdb.h>
45 #include <ctype.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
53 #include <sys/unistat/spcs_s.h>
54 #include <sys/unistat/spcs_s_u.h>
55 #include <sys/unistat/spcs_errors.h>
56
57 #include <sys/socket.h>
58 #include <netinet/in.h>
59 #include <arpa/inet.h>
60 #include <netinet/tcp.h>
61 #include <rpc/rpc_com.h>
62 #include <rpc/rpc.h>
63
64 #include <sys/nsctl/librdc.h>
65 #include <sys/nsctl/nsc_hash.h>
66
67 #include "rdcadm.h"
68
69 /*
70 * support for the special cluster tag "local" to be used with -C in a
71 * cluster for local volumes.
72 */
73
74 #define RDC_LOCAL_TAG "local"
75
76 typedef struct volcount_s {
77 int count;
78 } volcount_t;
79 hash_node_t **volhash = NULL;
80
81 /*
82 * rdc_islocal is only pertinent while creating the pairs array.
83 * after all the pairs are set, its value is useless, retaining
84 * the last value it was set to.
85 * its only reason in life is to suppress an error message in 2
86 * places where the inappropriate becomes appropriate (a supplied
87 * ctag which does not match an implied one cfg_dgame()). This
88 * happens when C "local" is supplied. It is then used to make an
89 * error message clearer. A
90 * gettext("set %s does not match", rdc_islocal < 1?dga:dgb) situation
91 */
92 static int rdc_islocal = 0;
93
94 char *program;
95
96 #define min(a, b) ((a) > (b) ? (b) : (a))
97
98 static char place_holder[] = "-"; /* cfg place holder value */
99
100 /*
101 * config file user level Dual copy pair structure
102 */
103 typedef struct _sd_dual_pair {
104 char fhost[MAX_RDC_HOST_SIZE]; /* Hostname for primary device */
105 char fnetaddr[RDC_MAXADDR]; /* Host netaddr for primary device */
106 char ffile[NSC_MAXPATH]; /* Primary device */
107 char fbitmap[NSC_MAXPATH]; /* Primary bitmap device */
108 char thost[MAX_RDC_HOST_SIZE]; /* Hostname for secondary device */
109 char tnetaddr[RDC_MAXADDR]; /* Host netaddr for secondary device */
110 char tfile[NSC_MAXPATH]; /* Secondary device */
111 char tbitmap[NSC_MAXPATH]; /* Secondary bitmap device */
112 char directfile[NSC_MAXPATH]; /* Local FCAL direct IO volume */
113 char group[NSC_MAXPATH]; /* Group name */
114 char ctag[MAX_RDC_HOST_SIZE]; /* Cluster resource name tag */
115 char diskqueue[NSC_MAXPATH]; /* Disk Queue volume */
116 int doasync; /* Device is in sync/async mode */
117 } _sd_dual_pair_t;
118
119 #define EXTRA_ARGS 6 /* g grp C ctag q diskqueue */
120
121 static int rdc_operation(
122 CFGFILE *, char *, char *, char *, char *, char *, char *,
123 int, int, char *, char *, char *, char *, int *, int);
124 int read_config(int, char *, char *, char *);
125 static int read_libcfg(int, char *, char *);
126 int prompt_user(int, int);
127 static void rdc_check_dgislocal(char *);
128 void process_clocal(char *);
129 static void usage(void);
130 void q_usage(int);
131 static void load_rdc_vols(CFGFILE *);
132 static void unload_rdc_vols();
133 static int perform_autosv();
134 static void different_devs(char *, char *);
135 static void validate_name(CFGFILE *, char *);
136 static void set_autosync(int, char *, char *, char *);
137 static int autosync_is_on(char *tohost, char *tofile);
138 static void enable_autosync(char *fhost, char *ffile, char *thost, char *tfile);
139 static void checkgfields(CFGFILE *, int, char *, char *, char *, char *,
140 char *, char *, char *, char *, char *);
141 static void checkgfield(CFGFILE *, int, char *, char *, char *);
142 static int rdc_bitmapset(char *, char *, char *, int, nsc_off_t);
143 static int parse_cfg_buf(char *, _sd_dual_pair_t *, char *);
144 static void verify_groupname(char *grp);
145 extern char *basename(char *);
146
147 int rdc_maxsets;
148 static _sd_dual_pair_t *pair_list;
149
150 struct netbuf svaddr;
151 struct netbuf *svp;
152 struct netconfig nconf;
153 struct netconfig *conf;
154 struct knetconfig knconf;
155
156 static char *reconfig_pbitmap = NULL;
157 static char *reconfig_sbitmap = NULL;
158 #ifdef _RDC_CAMPUS
159 static char *reconfig_direct = NULL;
160 #endif
161 static char *reconfig_group = NULL;
162 static char reconfig_ctag[MAX_RDC_HOST_SIZE];
163 static int reconfig_doasync = -1;
164
165 static int clustered = 0;
166 static int proto_test = 0;
167 int allow_role = 0;
168
169
170 static char *
rdc_print_state(rdc_set_t * urdc)171 rdc_print_state(rdc_set_t *urdc)
172 {
173 if (!urdc)
174 return ("");
175
176 if (urdc->sync_flags & RDC_VOL_FAILED)
177 return (gettext("volume failed"));
178 else if (urdc->sync_flags & RDC_FCAL_FAILED)
179 return (gettext("fcal failed"));
180 else if (urdc->bmap_flags & RDC_BMP_FAILED)
181 return (gettext("bitmap failed"));
182 else if (urdc->flags & RDC_DISKQ_FAILED)
183 return (gettext("disk queue failed"));
184 else if (urdc->flags & RDC_LOGGING) {
185 if (urdc->sync_flags & RDC_SYNC_NEEDED)
186 return (gettext("need sync"));
187 else if (urdc->sync_flags & RDC_RSYNC_NEEDED)
188 return (gettext("need reverse sync"));
189 else if (urdc->flags & RDC_QUEUING)
190 return (gettext("queuing"));
191 else
192 return (gettext("logging"));
193 } else if ((urdc->flags & RDC_SLAVE) && (urdc->flags & RDC_SYNCING)) {
194 if (urdc->flags & RDC_PRIMARY)
195 return (gettext("reverse syncing"));
196 else
197 return (gettext("syncing"));
198 } else if (urdc->flags & RDC_SYNCING) {
199 if (urdc->flags & RDC_PRIMARY)
200 return (gettext("syncing"));
201 else
202 return (gettext("reverse syncing"));
203 }
204
205 return (gettext("replicating"));
206 }
207
208
209 static int
rdc_print(int file_format,int verbose,char * group_arg,char * ctag_arg,char * user_shost,char * user_sdev,CFGFILE * cfgp)210 rdc_print(int file_format, int verbose, char *group_arg, char *ctag_arg,
211 char *user_shost, char *user_sdev, CFGFILE *cfgp)
212 {
213 rdc_status_t *rdc_status;
214 spcs_s_info_t ustatus;
215 rdc_set_t *urdc;
216 size_t size;
217 int i, rc, max;
218 char *tohost, *tofile;
219 _sd_dual_pair_t pair;
220 char *tmptohost = pair.thost;
221 char *tmptofile = pair.tfile;
222 char *fromhost = pair.fhost;
223 char *fromfile = pair.ffile;
224 char *frombitmap = pair.fbitmap;
225 char *tobitmap = pair.tbitmap;
226 char *directfile = pair.directfile;
227 char *group = pair.group;
228 char *diskqueue = pair.diskqueue;
229 char *ctag = pair.ctag;
230 CFGFILE *cfg;
231 int j;
232 int setnumber;
233 char key[CFG_MAX_KEY];
234 char buf[CFG_MAX_BUF];
235 char sync[16];
236 int match, found;
237
238 size = sizeof (rdc_status_t) + (sizeof (rdc_set_t) * (rdc_maxsets - 1));
239 match = (user_shost != NULL || user_sdev != NULL);
240 found = 0;
241
242 if (user_shost == NULL && user_sdev != NULL)
243 user_shost = "";
244 else if (user_shost != NULL && user_sdev == NULL)
245 user_sdev = "";
246
247 rdc_status = malloc(size);
248 if (!rdc_status) {
249 rdc_err(NULL,
250 gettext("unable to allocate %ld bytes"), size);
251 }
252
253 rdc_status->nset = rdc_maxsets;
254 ustatus = spcs_s_ucreate();
255
256 rc = RDC_IOCTL(RDC_STATUS, rdc_status, 0, 0, 0, 0, ustatus);
257 if (rc == SPCS_S_ERROR) {
258 rdc_err(&ustatus, gettext("statistics error"));
259 }
260
261 spcs_s_ufree(&ustatus);
262
263 max = min(rdc_status->nset, rdc_maxsets);
264
265 if (cfgp != NULL) {
266 cfg = cfgp;
267 cfg_rewind(cfg, CFG_SEC_CONF);
268 } else {
269 if ((cfg = cfg_open(NULL)) == NULL)
270 rdc_err(NULL,
271 gettext("unable to access configuration"));
272
273 if (!cfg_lock(cfg, CFG_RDLOCK))
274 rdc_err(NULL, gettext("unable to lock configuration"));
275 }
276
277 for (i = 0; i < max; i++) {
278 urdc = &rdc_status->rdc_set[i];
279
280 if (!(urdc->flags & RDC_ENABLED))
281 continue;
282
283 if (match &&
284 (strcmp(user_shost, urdc->secondary.intf) != 0 ||
285 strcmp(user_sdev, urdc->secondary.file) != 0))
286 continue;
287
288 tohost = urdc->secondary.intf;
289 tofile = urdc->secondary.file;
290 found = 1;
291
292 /* get sndr entries until shost, sfile match */
293 for (j = 0; j < rdc_maxsets; j++) {
294 setnumber = j + 1;
295 (void) snprintf(key, sizeof (key),
296 "sndr.set%d", setnumber);
297 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
298 break;
299 }
300
301 if (parse_cfg_buf(buf, &pair, NULL))
302 rdc_err(NULL, gettext("cfg input error"));
303
304 if (strcmp(tmptofile, tofile) != 0)
305 continue;
306 if (strcmp(tmptohost, tohost) != 0)
307 continue;
308
309 if (pair.doasync == 0)
310 (void) strcpy(sync, "sync");
311 else
312 (void) strcpy(sync, "async");
313
314 /* Got the matching entry */
315
316 break;
317 }
318
319 if (j == rdc_maxsets)
320 continue; /* not found in config */
321
322 if (strcmp(group_arg, "") != 0 &&
323 strncmp(group_arg, group, NSC_MAXPATH) != 0)
324 continue;
325
326 if (strcmp(ctag_arg, "") != 0 &&
327 strncmp(ctag_arg, ctag, MAX_RDC_HOST_SIZE) != 0)
328 continue;
329
330 if (file_format) {
331 (void) printf("%s %s %s %s %s %s %s %s",
332 fromhost, fromfile, frombitmap,
333 tohost, tofile, tobitmap,
334 directfile, sync);
335 if (strlen(group) != 0)
336 (void) printf(" g %s", group);
337 if ((strlen(ctag) != 0) && (ctag[0] != '-'))
338 (void) printf(" C %s", ctag);
339 if (strlen(diskqueue) != 0)
340 (void) printf(" q %s", diskqueue);
341 (void) printf("\n");
342 continue;
343 }
344
345 if (strcmp(group_arg, "") != 0 &&
346 strncmp(group_arg, urdc->group_name, NSC_MAXPATH) != 0)
347 continue;
348
349 if (!(urdc->flags & RDC_PRIMARY)) {
350 (void) printf(gettext("%s\t<-\t%s:%s\n"),
351 urdc->secondary.file, urdc->primary.intf,
352 urdc->primary.file);
353 } else {
354 (void) printf(gettext("%s\t->\t%s:%s\n"),
355 urdc->primary.file, urdc->secondary.intf,
356 urdc->secondary.file);
357 }
358 if (!verbose)
359 continue;
360
361 if (urdc->autosync)
362 (void) printf(gettext("autosync: on"));
363 else
364 (void) printf(gettext("autosync: off"));
365
366 (void) printf(gettext(", max q writes: %lld"), urdc->maxqitems);
367 (void) printf(gettext(", max q fbas: %lld"), urdc->maxqfbas);
368 (void) printf(gettext(", async threads: %d"),
369 urdc->asyncthr);
370 (void) printf(gettext(", mode: %s"),
371 pair.doasync ? "async" : "sync");
372
373 if (strlen(urdc->group_name) != 0)
374 (void) printf(gettext(", group: %s"), urdc->group_name);
375 if ((strlen(ctag) != 0) && (ctag[0] != '-'))
376 (void) printf(gettext(", ctag: %s"), ctag);
377 if (strlen(urdc->disk_queue) != 0) {
378 (void) printf(gettext(", %s diskqueue: %s"),
379 (urdc->flags & RDC_QNOBLOCK) ? gettext("non blocking") :
380 gettext("blocking"), urdc->disk_queue);
381 }
382
383 (void) printf(gettext(", state: %s"), rdc_print_state(urdc));
384 (void) printf(gettext("\n"));
385
386 }
387
388 if (!cfgp)
389 cfg_close(cfg);
390
391 free(rdc_status);
392
393 if (match && !found) {
394 rdc_warn(NULL, gettext("unable to find set %s:%s"),
395 user_shost, user_sdev);
396 }
397
398 return (0);
399 }
400
401
402 int
parse_extras(int argc,char * args[],int i)403 parse_extras(int argc, char *args[], int i)
404 {
405 int gflag = 0;
406 int Cflag = 0;
407 int qflag = 0;
408 int j;
409
410 (void) strcpy(pair_list[i].ctag, "");
411 (void) strcpy(pair_list[i].group, "");
412 (void) strcpy(pair_list[i].diskqueue, "");
413
414 if (argc == 0)
415 return (0);
416
417 if (argc != 2 && argc != 4 && argc != 6)
418 return (-1);
419
420 for (j = 0; j < argc; j += 2) {
421 if (strcmp(args[j], "g") == 0) {
422 if (gflag)
423 return (-1);
424 (void) strncpy(pair_list[i].group, args[j + 1],
425 NSC_MAXPATH);
426 gflag = 1;
427 }
428 if (strcmp(args[j], "C") == 0) {
429 if (!clustered)
430 return (-1);
431 if (Cflag)
432 return (-1);
433 (void) strncpy(pair_list[i].ctag, args[j + 1],
434 MAX_RDC_HOST_SIZE);
435 process_clocal(pair_list[i].ctag);
436 Cflag = 1;
437 }
438 if (strcmp(args[j], "q") == 0) {
439 if (qflag)
440 return (-1);
441 (void) strncpy(pair_list[i].diskqueue, args[j + 1],
442 NSC_MAXPATH);
443 qflag = 1;
444 }
445 }
446
447 return (0);
448 }
449
450 static int
parse_cfg_buf(char * buf,_sd_dual_pair_t * pair,char * lghn)451 parse_cfg_buf(char *buf, _sd_dual_pair_t *pair, char *lghn)
452 {
453 int rc = 0;
454 char sync[16];
455 char options[64], *p, *q;
456 int len;
457
458 rc = sscanf(buf, "%s %s %s %s %s %s %s %s %s %s %s %s", pair->fhost,
459 pair->ffile, pair->fbitmap, pair->thost, pair->tfile,
460 pair->tbitmap, pair->directfile, sync, pair->group,
461 pair->ctag, options, pair->diskqueue);
462
463 if (rc != 12)
464 rdc_err(NULL, gettext("cfg input error"));
465
466 if (strcmp(pair->diskqueue, place_holder) == 0)
467 (void) strcpy(pair->diskqueue, "");
468
469 if (strcmp(pair->group, place_holder) == 0)
470 (void) strcpy(pair->group, "");
471
472 if (strcmp(sync, "sync") == 0)
473 pair->doasync = 0;
474 else if (strcmp(sync, "async") == 0)
475 pair->doasync = 1;
476 else {
477 rdc_err(NULL,
478 gettext("set %s:%s neither sync nor async"),
479 pair->thost, pair->tfile);
480 }
481
482 if (lghn && (p = strstr(options, "lghn="))) {
483 p += 5;
484 q = strchr(p, ';');
485 if (q) {
486 /* LINTED p & q limited to options[64] */
487 len = q - p;
488 } else {
489 len = strlen(p);
490 }
491 (void) strncpy(lghn, p, len);
492 lghn[len] = '\0';
493 } else if (lghn) {
494 *lghn = '\0';
495 }
496
497 return (0);
498 }
499
500 static int
ctag_check(char * fromhost,char * fromfile,char * frombitmap,char * tohost,char * tofile,char * tobitmap,char * ctag,char * diskq)501 ctag_check(char *fromhost, char *fromfile, char *frombitmap, char *tohost,
502 char *tofile, char *tobitmap, char *ctag, char *diskq)
503 {
504 char *file_dgname;
505 char *bmp_dgname;
506 char *que_dgname;
507 char *localfile;
508 char file_buf[MAX_RDC_HOST_SIZE];
509 char bmp_buf[MAX_RDC_HOST_SIZE];
510 char que_buf[NSC_MAXPATH];
511 int is_primary;
512 struct hostent *hp;
513 char fromname[MAXHOSTNAMELEN], toname[MAXHOSTNAMELEN];
514
515 if (!clustered)
516 return (0);
517
518 hp = gethost_byname(fromhost);
519 (void) strncpy(fromname, hp->h_name, MAXHOSTNAMELEN);
520 hp = gethost_byname(tohost);
521 (void) strncpy(toname, hp->h_name, MAXHOSTNAMELEN);
522 if (!self_check(fromname) && !self_check(toname)) {
523 /*
524 * If we could get a list of logical hosts on this cluster
525 * then we could print something intelligent about where
526 * the volume is mastered. For now, just print some babble
527 * about the fact that we have no idea.
528 */
529 rdc_err(NULL,
530 gettext("either %s:%s or %s:%s is not local"),
531 fromhost, fromfile, tohost, tofile);
532 }
533
534 is_primary = self_check(fromname);
535
536 /*
537 * If implicit disk group name and no ctag specified by user,
538 * we set the ctag to it.
539 * If implicit disk group name, it must match any supplied ctag.
540 */
541 localfile = is_primary ? fromfile : tofile;
542 file_dgname = cfg_dgname(localfile, file_buf, sizeof (file_buf));
543 if (file_dgname && strlen(file_dgname))
544 rdc_check_dgislocal(file_dgname);
545
546 /*
547 * Autogenerate a ctag, if not "-C local" or no "-C " specified
548 */
549 if (!rdc_islocal && !strlen(ctag) && file_dgname && strlen(file_dgname))
550 (void) strncpy(ctag, file_dgname, MAX_RDC_HOST_SIZE);
551
552 /*
553 * making an exception here for users giving the "local"tag
554 * this overrides this error message. (rdc_islocal ! = 1)
555 */
556 if (!rdc_islocal && strlen(ctag) &&
557 file_dgname && strlen(file_dgname) &&
558 strncmp(ctag, file_dgname, MAX_RDC_HOST_SIZE)) {
559 rdc_warn(NULL, gettext("ctag \"%s\" does not "
560 "match disk group name \"%s\" of volume %s"), ctag,
561 file_dgname, localfile);
562 return (-1);
563 }
564
565 /*
566 * Do we have a non-volume managed disk without -C local specified?
567 */
568 if (!rdc_islocal && (!file_dgname || !strlen(file_dgname))) {
569 rdc_err(NULL, gettext("volume \"%s\" is not part"
570 " of a disk group,\nplease specify resource ctag\n"),
571 localfile);
572 }
573
574 /*
575 * Do we have a volume managed disk with -C local?
576 */
577 if (rdc_islocal && file_dgname && (strlen(file_dgname) > 0)) {
578 rdc_err(NULL, gettext(
579 "volume \"%s\" is part of a disk group\n"), localfile);
580 }
581
582 /*
583 * Local bitmap must also have same ctag.
584 */
585 localfile = is_primary ? frombitmap : tobitmap;
586 bmp_dgname = cfg_dgname(localfile, bmp_buf, sizeof (bmp_buf));
587 if (bmp_dgname && strlen(bmp_dgname))
588 rdc_check_dgislocal(bmp_dgname);
589
590 /*
591 * Assure that if the primary has a device group, so must the bitmap
592 */
593 if ((file_dgname && strlen(file_dgname)) &&
594 (!bmp_dgname || !strlen(bmp_dgname))) {
595 rdc_warn(NULL, gettext("bitmap %s is not in disk group \"%s\""),
596 localfile, rdc_islocal < 1?file_dgname:ctag);
597 return (-1);
598 }
599
600 /*
601 * Assure that if the if there is a ctag, it must match the bitmap
602 */
603 if (!rdc_islocal && strlen(ctag) &&
604 bmp_dgname && strlen(bmp_dgname) &&
605 strncmp(ctag, bmp_dgname, MAX_RDC_HOST_SIZE)) {
606 rdc_warn(NULL, gettext("ctag \"%s\" does not "
607 "match disk group name \"%s\" of bitmap %s"), ctag,
608 bmp_dgname, localfile);
609 return (-1);
610 }
611
612 /*
613 * If this is the SNDR primary and there is a local disk queue
614 */
615 if (is_primary && diskq[0]) {
616
617 /*
618 * Local disk queue must also have same ctag.
619 */
620 que_dgname = cfg_dgname(diskq, que_buf, sizeof (que_buf));
621 if (que_dgname && strlen(que_dgname))
622 rdc_check_dgislocal(que_dgname);
623
624 /*
625 * Assure that if the primary has a device group, so must
626 * the disk queue
627 */
628 if ((file_dgname && strlen(file_dgname)) &&
629 (!que_dgname || !strlen(que_dgname))) {
630 rdc_warn(NULL, gettext("disk queue %s is not in disk "
631 "group \"%s\""), diskq,
632 rdc_islocal < 1?file_dgname:ctag);
633 return (-1);
634 }
635
636 /*
637 * Assure that if the if there is a ctag, it must match
638 * the disk queue
639 */
640 if (!rdc_islocal && strlen(ctag) &&
641 que_dgname && strlen(que_dgname) &&
642 strncmp(ctag, que_dgname, MAX_RDC_HOST_SIZE)) {
643 rdc_warn(NULL, gettext("ctag \"%s\" does not "
644 "match disk group name \"%s\" of disk queue %s"),
645 ctag, que_dgname, diskq);
646 return (-1);
647 }
648 }
649
650 return (0);
651 }
652
653 #define DISKQ_OKAY 0
654 #define DISKQ_FAIL 1
655 #define DISKQ_REWRITEG 2
656 /*
657 * check that newq is compatable with the groups current disk queue.
658 * Newq is incompatable if it is set and the groups queue is set and the queues
659 * are different.
660 *
661 * if newq is not set but should be, it will be set to the correct value.
662 * returns:
663 * DISK_REWRITEG entire group needs to take new value of disk_queue
664 * DISKQ_OKAY newq contains a value that matches the group.
665 * DISKQ_FAIL disk queues are incompatible.
666 */
667 static int
check_diskqueue(CFGFILE * cfg,char * newq,char * newgroup)668 check_diskqueue(CFGFILE *cfg, char *newq, char *newgroup)
669 {
670 int i, setnumber;
671 _sd_dual_pair_t pair;
672 char *group = pair.group;
673 char *diskqueue = pair.diskqueue;
674 char buf[CFG_MAX_BUF];
675 char key[CFG_MAX_KEY];
676 int open_cfg = cfg == NULL ? 1 : 0;
677
678
679 if (newgroup == NULL || *newgroup == '\0') {
680 if (*newq == '\0')
681 return (DISKQ_OKAY); /* okay, */
682 newgroup = "--nomatch--";
683 }
684
685 if (open_cfg) {
686 if ((cfg = cfg_open(NULL)) == NULL)
687 rdc_err(NULL,
688 gettext("unable to access configuration"));
689 if (!cfg_lock(cfg, CFG_RDLOCK))
690 rdc_err(NULL, gettext("unable to lock configuration"));
691 }
692
693 /*CSTYLED*/
694 for (i = 0; ; i++) {
695 setnumber = i + 1;
696 (void) snprintf(key, sizeof (key), "sndr.set%d", setnumber);
697 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
698 break;
699 /*
700 * I think this is quicker than
701 * having to double dip into the config
702 */
703 if (parse_cfg_buf(buf, &pair, NULL))
704 rdc_err(NULL, gettext("cfg input error"));
705
706 if (strncmp(group, newgroup, NSC_MAXPATH) != 0) {
707 if (((strncmp(diskqueue, newq, NSC_MAXPATH) == 0)) &&
708 (diskqueue[0] != '\0')) {
709 if (open_cfg)
710 cfg_close(cfg);
711 return (DISKQ_FAIL);
712 }
713 continue;
714 }
715 if (*newq == '\0') {
716 if (diskqueue[0] != '\0')
717 (void) strncpy(newq, diskqueue, NSC_MAXPATH);
718 if (open_cfg)
719 cfg_close(cfg);
720 return (DISKQ_OKAY); /* okay, */
721 }
722
723 if (open_cfg)
724 cfg_close(cfg);
725 if (diskqueue[0] == '\0') /* no queue here */
726 return (DISKQ_REWRITEG);
727 return (strncmp(diskqueue, newq, NSC_MAXPATH)
728 == 0 ? DISKQ_OKAY : DISKQ_FAIL);
729 }
730 if (open_cfg)
731 cfg_close(cfg);
732 return (DISKQ_OKAY);
733 }
734
735
736 int
pair_diskqueue_check(int newpair)737 pair_diskqueue_check(int newpair)
738 {
739 int i, j;
740 int rc;
741
742 for (i = 0; i < newpair; i++) {
743 if (strcmp(pair_list[i].group, pair_list[newpair].group) != 0)
744 continue;
745 if (strcmp(pair_list[i].diskqueue, pair_list[newpair].diskqueue)
746 == 0)
747 return (DISKQ_OKAY); /* matches existing group */
748 if ((pair_list[newpair].group[0] != '\0') &&
749 (pair_list[newpair].diskqueue[0] != '\0') &&
750 (pair_list[i].diskqueue[0] != '\0')) {
751 rdc_warn(NULL,
752 gettext("disk queue %s does not match %s "
753 "skipping set"), pair_list[newpair].diskqueue,
754 pair_list[i].diskqueue);
755 return (DISKQ_FAIL);
756 }
757
758 if ((strcmp(pair_list[newpair].diskqueue, "") == 0) &&
759 pair_list[newpair].group[0] != '\0') {
760 (void) strncpy(pair_list[newpair].diskqueue,
761 pair_list[i].diskqueue, NSC_MAXPATH);
762 return (DISKQ_OKAY); /* changed to existing group que */
763 }
764 if (strcmp(pair_list[i].diskqueue, "") == 0) {
765 for (j = 0; j < newpair; j++) {
766 if ((pair_list[j].group[0] != '\0') &&
767 (strncmp(pair_list[j].group,
768 pair_list[newpair].group,
769 NSC_MAXPATH) == 0)) {
770 (void) strncpy(pair_list[j].diskqueue,
771 pair_list[newpair].diskqueue,
772 NSC_MAXPATH);
773 }
774 }
775 return (DISKQ_OKAY);
776 }
777 break; /* no problem with pair_list sets */
778
779 }
780
781 /* now check with already configured sets */
782 rc = check_diskqueue(NULL, pair_list[newpair].diskqueue,
783 pair_list[newpair].group);
784 if (rc == DISKQ_REWRITEG) {
785 for (i = 0; i < newpair; i++) {
786 if (strcmp(pair_list[i].group,
787 pair_list[newpair].group) != 0)
788 continue;
789
790 (void) strncpy(pair_list[i].diskqueue,
791 pair_list[newpair].diskqueue, NSC_MAXPATH);
792 }
793 }
794 return (rc);
795 }
796
797 int
ii_set_exists(CFGFILE * cfg,char * ma,char * sh,char * bm)798 ii_set_exists(CFGFILE *cfg, char *ma, char *sh, char *bm)
799 {
800 char buf[CFG_MAX_BUF];
801 char key[CFG_MAX_KEY];
802 char master[NSC_MAXPATH];
803 char shadow[NSC_MAXPATH];
804 char bitmap[NSC_MAXPATH];
805 int i;
806
807 for (i = 1; ; i++) {
808 (void) snprintf(key, sizeof (key), "ii.set%d", i);
809 bzero(&master, sizeof (master));
810 bzero(&shadow, sizeof (shadow));
811 bzero(&bitmap, sizeof (bitmap));
812 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
813 break;
814 (void) sscanf(buf, "%s %s %s", master, shadow, bitmap);
815 if (strcmp(master, ma) != 0)
816 continue;
817 if (strcmp(shadow, sh) != 0)
818 continue;
819 if (strcmp(bitmap, bm) != 0)
820 continue;
821 return (1);
822 }
823 return (0);
824 }
825
826 void
rdc_ii_config(int argc,char ** argv)827 rdc_ii_config(int argc, char **argv)
828 {
829 char *master;
830 char *shadow;
831 char *bitmap;
832 char c;
833 CFGFILE *cfg;
834 int i;
835 int setnumber;
836 char key[CFG_MAX_KEY];
837 char buf[CFG_MAX_BUF];
838 int found;
839 int sev;
840
841 /* Parse the rest of the arguments to see what to do */
842
843 if (argc - optind != 4) {
844 usage();
845 exit(1);
846 }
847
848 c = *argv[optind];
849 switch (c) {
850 case 'd':
851 /* Delete an ndr_ii entry */
852
853 master = argv[++optind];
854 shadow = argv[++optind];
855 bitmap = argv[++optind];
856
857 if ((cfg = cfg_open(NULL)) == NULL)
858 rdc_err(NULL,
859 gettext("unable to access configuration"));
860 if (!cfg_lock(cfg, CFG_WRLOCK))
861 rdc_err(NULL, gettext("unable to lock configuration"));
862
863 found = 0;
864 /* get ndr_ii entries until a match is found */
865 /*CSTYLED*/
866 for (i = 0; ; i++) {
867 setnumber = i + 1;
868
869 (void) snprintf(key, sizeof (key),
870 "ndr_ii.set%d.secondary",
871 setnumber);
872 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
873 break;
874 if (strcmp(buf, master) != 0)
875 continue;
876
877 /* Got a matching entry */
878
879 (void) snprintf(key, sizeof (key),
880 "ndr_ii.set%d.shadow",
881 setnumber);
882 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
883 break;
884 if (strcmp(buf, shadow) != 0)
885 continue;
886
887 (void) snprintf(key, sizeof (key),
888 "ndr_ii.set%d.bitmap",
889 setnumber);
890 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
891 break;
892 if (strcmp(buf, bitmap) != 0)
893 continue;
894
895 (void) snprintf(key, sizeof (key),
896 "ndr_ii.set%d", setnumber);
897 if (cfg_put_cstring(cfg, key, NULL, 0) < 0) {
898 rdc_warn(NULL,
899 gettext("unable to remove \"%s\" "
900 "from configuration storage: %s"),
901 key, cfg_error(&sev));
902 } else {
903 if (cfg_commit(cfg) < 0)
904 rdc_err(NULL,
905 gettext("ndr_ii set %s %s %s "
906 "not deconfigured."),
907 master, shadow, bitmap);
908 else
909 spcs_log("sndr", NULL,
910 gettext("ndr_ii set %s %s %s "
911 "has been deconfigured."),
912 master, shadow, bitmap);
913 }
914 found = 1;
915 break;
916 }
917
918 if (!found) {
919 rdc_err(NULL,
920 gettext("did not find matching ndr_ii "
921 "entry for %s %s %s"), master, shadow, bitmap);
922 }
923
924 cfg_close(cfg);
925
926 break;
927
928 case 'a':
929 /* Add an ndr_ii entry */
930
931 master = argv[++optind];
932 shadow = argv[++optind];
933 bitmap = argv[++optind];
934
935 if ((cfg = cfg_open(NULL)) == NULL)
936 rdc_err(NULL,
937 gettext("unable to access configuration"));
938 if (!cfg_lock(cfg, CFG_WRLOCK))
939 rdc_err(NULL, gettext("unable to lock configuration"));
940
941 found = 0;
942 /* get ndr_ii entries in case a match is found */
943 /*CSTYLED*/
944 for (i = 0; ; i++) {
945 setnumber = i + 1;
946
947 (void) snprintf(key, sizeof (key),
948 "ndr_ii.set%d.secondary",
949 setnumber);
950 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
951 break;
952 if (strcmp(buf, master) == 0) {
953 rdc_err(NULL,
954 gettext("found matching ndr_ii "
955 "entry for %s"), master);
956 }
957 }
958 /*
959 * check to see if this is using a sndr bitmap.
960 * kind of a courtesy check, as the ii copy would fail anyway
961 * excepting the case where they had actually configured
962 * ii/sndr that way, in which case they are broken
963 * before we get here
964 */
965 /*CSTYLED*/
966 for (i = 0; ; i++) {
967 setnumber = i + 1;
968
969 /*
970 * Checking local bitmaps
971 */
972 (void) snprintf(key, sizeof (key), "sndr.set%d.phost",
973 setnumber);
974
975 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
976 break;
977 if (self_check(buf)) {
978 (void) snprintf(key, sizeof (key),
979 "sndr.set%d.pbitmap",
980 setnumber);
981 } else {
982 (void) snprintf(key, sizeof (key),
983 "sndr.set%d.sbitmap",
984 setnumber);
985 }
986
987 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
988 break;
989
990 if ((strcmp(buf, bitmap) == 0) ||
991 (strcmp(buf, master) == 0) ||
992 (strcmp(buf, shadow) == 0)) {
993 rdc_err(NULL,
994 gettext("%s is already configured "
995 "as a Remote Mirror bitmap"), buf);
996 }
997 }
998 if (!ii_set_exists(cfg, master, shadow, bitmap)) {
999 rdc_warn(NULL, gettext("Point-in-Time Copy set "
1000 "%s %s %s is not already configured. Remote "
1001 "Mirror will attempt to configure this set when "
1002 "a sync is issued to it. The results of that "
1003 "operation will be in /var/adm/ds.log"),
1004 master, shadow, bitmap);
1005 spcs_log("sndr", NULL, gettext("Point-in-Time Copy set "
1006 "%s %s %s is not already configured. Remote "
1007 "Mirror will attempt to configure this set when "
1008 "a sync is issued to it. The results of that "
1009 "operation will be in /var/adm/ds.log"),
1010 master, shadow, bitmap);
1011 } else {
1012 spcs_log("sndr", NULL, gettext("ndr_ii set "
1013 "%s %s %s has been configured."),
1014 master, shadow, bitmap);
1015 }
1016
1017 /*
1018 * Prior to insertion in ndr_ii entry, if in a Sun Cluster
1019 * assure device groups are the same and cluster tag is set
1020 */
1021 if (clustered && !rdc_islocal) {
1022 char mst_dg[NSC_MAXPATH] = {0};
1023 char shd_dg[NSC_MAXPATH] = {0};
1024 char bmp_dg[NSC_MAXPATH] = {0};
1025
1026 if (!(cfg_dgname(master, mst_dg, sizeof (mst_dg)) &&
1027 cfg_dgname(shadow, shd_dg, sizeof (shd_dg)) &&
1028 cfg_dgname(bitmap, bmp_dg, sizeof (bmp_dg))))
1029 rdc_warn(NULL, gettext("ndr_ii: %s %s %s are "
1030 "not in a device group"),
1031 master, shadow, bitmap);
1032 else if (strcmp(mst_dg, bmp_dg) ||
1033 strcmp(mst_dg, shd_dg))
1034 rdc_warn(NULL, gettext("ndr_ii: %s %s %s are "
1035 "not in different device groups"),
1036 master, shadow, bitmap);
1037 else {
1038 cfg_resource(cfg, shd_dg);
1039 (void) snprintf(buf, sizeof (buf),
1040 "%s %s %s update %s",
1041 master, shadow, bitmap, shd_dg);
1042 }
1043 } else {
1044 (void) snprintf(buf, sizeof (buf), "%s %s %s update",
1045 master, shadow, bitmap);
1046 }
1047
1048 if ((cfg_put_cstring(cfg, "ndr_ii", buf, strlen(buf)) < 0) ||
1049 (cfg_commit(cfg) < 0))
1050 rdc_warn(NULL, gettext("unable to add \"%s\" to "
1051 "configuration storage: %s"),
1052 buf, cfg_error(&sev));
1053
1054 cfg_close(cfg);
1055
1056 break;
1057
1058 default:
1059 usage();
1060 exit(1);
1061 }
1062 }
1063
1064 void
check_rdcbitmap(int cmd,char * hostp,char * bmp)1065 check_rdcbitmap(int cmd, char *hostp, char *bmp)
1066 {
1067 int i;
1068 CFGFILE *cfg;
1069 int entries;
1070 char **entry;
1071 char *host, *pri, *sec, *sbm, *bit, *mas, *sha, *ovr;
1072 char *shost, *buf, *que;
1073
1074 if ((cfg = cfg_open(NULL)) == NULL)
1075 rdc_err(NULL,
1076 gettext("unable to access configuration"));
1077 if (!cfg_lock(cfg, CFG_RDLOCK))
1078 rdc_err(NULL, gettext("unable to lock configuration"));
1079
1080 /*
1081 * look into II config to see if this is being used elsewhere
1082 */
1083 entry = NULL;
1084 entries = cfg_get_section(cfg, &entry, "ii");
1085 for (i = 0; i < entries; i++) {
1086 buf = entry[i];
1087
1088 mas = strtok(buf, " "); /* master */
1089 sha = strtok(NULL, " "); /* shadow */
1090 bit = strtok(NULL, " "); /* bitmap */
1091 (void) strtok(NULL, " "); /* mode */
1092 ovr = strtok(NULL, " "); /* overflow */
1093
1094 /*
1095 * got master, shadow, overflow, and bitmap, now compare
1096 */
1097 if ((strcmp(bmp, mas) == 0) ||
1098 (strcmp(bmp, sha) == 0) ||
1099 (strcmp(bmp, ovr) == 0) ||
1100 (strcmp(bmp, bit) == 0)) {
1101 rdc_err(NULL,
1102 gettext("bitmap %s is in use by"
1103 " Point-in-Time Copy"), bmp);
1104 }
1105 free(buf);
1106 }
1107 if (entries)
1108 free(entry);
1109
1110
1111 /*
1112 * and last but not least, make sure sndr is not using vol for anything
1113 */
1114 entry = NULL;
1115 entries = cfg_get_section(cfg, &entry, "sndr");
1116 for (i = 0; i < entries; i++) {
1117 buf = entry[i];
1118
1119 /*
1120 * I think this is quicker than
1121 * having to double dip into the config
1122 */
1123 host = strtok(buf, " "); /* phost */
1124 pri = strtok(NULL, " "); /* primary */
1125 bit = strtok(NULL, " "); /* pbitmap */
1126 shost = strtok(NULL, " "); /* shost */
1127 sec = strtok(NULL, " "); /* secondary */
1128 sbm = strtok(NULL, " "); /* sbitmap */
1129 (void) strtok(NULL, " "); /* type */
1130 (void) strtok(NULL, " "); /* mode */
1131 (void) strtok(NULL, " "); /* group */
1132 (void) strtok(NULL, " "); /* cnode */
1133 (void) strtok(NULL, " "); /* options */
1134 que = strtok(NULL, " "); /* diskq */
1135
1136 if (cmd == RDC_CMD_ENABLE) {
1137 if (self_check(host)) {
1138 if ((strcmp(bmp, pri) == 0) ||
1139 (strcmp(bmp, que) == 0) ||
1140 (strcmp(bmp, bit) == 0)) {
1141 rdc_err(NULL,
1142 gettext("bitmap %s is already "
1143 "in use by StorEdge Network Data "
1144 "Replicator"), bmp);
1145 }
1146 } else {
1147 if ((strcmp(bmp, sec) == 0) ||
1148 (strcmp(bmp, sbm) == 0)) {
1149 rdc_err(NULL,
1150 gettext("bitmap %s is already "
1151 "in use by StorEdge Network Data "
1152 "Replicator"), bmp);
1153 }
1154 }
1155 } else if (cmd == RDC_CMD_RECONFIG) {
1156
1157 /*
1158 * read this logic 1000 times and consider
1159 * multi homed, one to many, many to one (marketing)
1160 * etc, etc, before changing
1161 */
1162 if (self_check(hostp)) {
1163 if (self_check(host)) {
1164 if ((strcmp(bmp, pri) == 0) ||
1165 (strcmp(bmp, que) == 0) ||
1166 (strcmp(bmp, bit) == 0)) {
1167 rdc_err(NULL,
1168 gettext("bitmap %s is already "
1169 "in use by StorEdge Network "
1170 "Data Replicator"), bmp);
1171 }
1172 } else {
1173 if ((strcmp(hostp, shost) == 0) &&
1174 (strcmp(bmp, sec) == 0) ||
1175 (strcmp(bmp, sbm) == 0)) {
1176 rdc_err(NULL,
1177 gettext("bitmap %s is already "
1178 "in use by StorEdge Network "
1179 "Data Replicator"), bmp);
1180
1181 }
1182 }
1183 } else { /* self_check(hostp) failed */
1184 if (self_check(host)) {
1185 if ((strcmp(shost, hostp) == 0) &&
1186 (strcmp(bmp, sec) == 0) ||
1187 (strcmp(bmp, sbm) == 0)) {
1188 rdc_err(NULL,
1189 gettext("bitmap %s is already "
1190 "in use by StorEdge Network "
1191 "Data Replicator"), bmp);
1192 }
1193 } else {
1194 if ((strcmp(host, hostp) == 0) &&
1195 (strcmp(bmp, pri) == 0) ||
1196 (strcmp(bmp, que) == 0) ||
1197 (strcmp(bmp, bit) == 0)) {
1198 rdc_err(NULL,
1199 gettext("bitmap %s is already "
1200 "in use by StorEdge Network "
1201 "Data Replicator"), bmp);
1202 }
1203 }
1204 }
1205
1206 }
1207
1208 free(buf);
1209 }
1210 cfg_close(cfg);
1211
1212 if (entries)
1213 free(entry);
1214 }
1215 int
check_intrange(char * arg)1216 check_intrange(char *arg) {
1217 int i;
1218
1219 for (i = 0; i < strlen(arg); i++) {
1220 if (arg[i] < '0' || arg[i] > '9') {
1221 rdc_warn(NULL, "not a valid number, must be a "
1222 "decimal between 1 and %d", MAXINT);
1223 return (0);
1224 }
1225 }
1226 errno = 0;
1227 i = (int)strtol(arg, NULL, 10);
1228 if ((errno) || (i < 1) || (i > MAXINT)) {
1229 rdc_warn(NULL, "not a valid number, must be a decimal "
1230 "between 1 and %d", MAXINT);
1231 return (0);
1232 }
1233 return (1);
1234 }
1235
1236 void
rewrite_group_diskqueue(CFGFILE * cfg,_sd_dual_pair_t * pair,char * diskqueue)1237 rewrite_group_diskqueue(CFGFILE *cfg, _sd_dual_pair_t *pair, char *diskqueue)
1238 {
1239 int set;
1240 char buf[CFG_MAX_BUF];
1241 char key[CFG_MAX_KEY];
1242 _sd_dual_pair_t tmpair;
1243
1244 for (set = 1; /*CSTYLED*/; set++) {
1245 bzero(buf, CFG_MAX_BUF);
1246 bzero(&tmpair, sizeof (tmpair));
1247
1248 (void) snprintf(key, sizeof (key), "sndr.set%d", set);
1249 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
1250 break;
1251 }
1252 if (parse_cfg_buf(buf, &tmpair, NULL))
1253 continue;
1254 if (pair->group && pair->group[0]) {
1255 if (strcmp(pair->group, tmpair.group) != 0)
1256 continue; /* not the group we want */
1257
1258 } else { /* no group specified */
1259 if (strcmp(pair->thost, tmpair.thost) != 0)
1260 continue;
1261 if (strcmp(pair->tfile, tmpair.tfile) != 0)
1262 continue;
1263 }
1264
1265 (void) sprintf(key, "sndr.set%d.diskq", set);
1266
1267 if (cfg_put_cstring(cfg, key, diskqueue,
1268 strlen(diskqueue)) < 0) {
1269 perror(cfg_error(NULL));
1270 }
1271 }
1272 }
1273
1274 void
diskq_subcmd(int subcmd,char * qvol,char * group_arg,char * ctag_arg,char * tohost_arg,char * tofile_arg)1275 diskq_subcmd(int subcmd, char *qvol, char *group_arg, char *ctag_arg,
1276 char *tohost_arg, char *tofile_arg)
1277 {
1278 int found = 0;
1279 int setnumber = 0;
1280 char key[CFG_MAX_KEY];
1281 char buf[CFG_MAX_BUF];
1282 int i;
1283 int rc;
1284 int option = 0;
1285 _sd_dual_pair_t pair;
1286 CFGFILE *cfg;
1287 char *ctag = NULL;
1288 int resourced = 0;
1289
1290 if ((cfg = cfg_open(NULL)) == NULL)
1291 rdc_err(NULL,
1292 gettext("unable to access configuration"));
1293
1294 if (!cfg_lock(cfg, CFG_WRLOCK))
1295 rdc_err(NULL,
1296 gettext("unable to lock configuration"));
1297
1298 redo:
1299 if (cfg_load_svols(cfg) < 0 ||
1300 cfg_load_dsvols(cfg) < 0 ||
1301 cfg_load_shadows(cfg) < 0)
1302 rdc_err(NULL,
1303 gettext("Unable to parse config filer"));
1304 load_rdc_vols(cfg);
1305
1306 /*CSTYLED*/
1307 for (i = 0; i < rdc_maxsets;) {
1308 setnumber++;
1309
1310 bzero(buf, CFG_MAX_BUF);
1311 (void) snprintf(key, sizeof (key),
1312 "sndr.set%d", setnumber);
1313 rc = cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF);
1314 if (rc < 0)
1315 break;
1316 if (parse_cfg_buf(buf, &pair, NULL))
1317 continue;
1318
1319 if (strlen(group_arg) == 0) {
1320 if (strcmp(tohost_arg, pair.thost) == 0 &&
1321 strcmp(tofile_arg, pair.tfile) == 0) {
1322 (void) strcpy(group_arg, pair.group);
1323 found = 1;
1324 break;
1325 }
1326
1327 } else {
1328 if (strcmp(group_arg, pair.group) == 0) {
1329 found = 1;
1330 break;
1331 }
1332 }
1333 }
1334
1335 if (!found) {
1336 if (strlen(group_arg) == 0) {
1337 rdc_err(NULL,
1338 gettext("Unable to find %s:%s in "
1339 "configuration storage"),
1340 tohost_arg, tofile_arg);
1341 } else {
1342 rdc_err(NULL,
1343 gettext("Unable to find group %s in "
1344 "configuration storage"), group_arg);
1345 }
1346 }
1347 if (!resourced && strlen(pair.ctag)) { /* uh-oh... */
1348 cfg_unload_svols(cfg);
1349 cfg_unload_dsvols(cfg);
1350 cfg_unload_shadows(cfg);
1351 unload_rdc_vols();
1352 cfg_resource(cfg, pair.ctag);
1353 ctag = strdup(pair.ctag);
1354 resourced = 1;
1355 setnumber = 0;
1356 goto redo;
1357 }
1358
1359 if (clustered && !rdc_islocal) {
1360 if (strcmp(ctag_arg, "") &&
1361 strncmp(ctag_arg, pair.ctag, MAX_RDC_HOST_SIZE))
1362 rdc_warn(NULL, gettext("ctags %s and %s "
1363 "do not match, proceeding with operation based "
1364 "on existing set information"), ctag_arg, ctag);
1365 }
1366 switch (subcmd) {
1367 case RDC_CMD_ADDQ:
1368 if (clustered && (ctag_check(pair.fhost, pair.ffile,
1369 pair.fbitmap, pair.thost, pair.tfile, pair.tbitmap,
1370 pair.ctag, qvol) < 0))
1371 exit(1);
1372
1373 if (strlen(pair.diskqueue) > 0) {
1374 rdc_err(NULL, gettext("Remote Mirror set already "
1375 "has a disk queue"));
1376 }
1377 if (check_diskqueue(cfg, qvol, group_arg) == DISKQ_FAIL) {
1378 rdc_err(NULL,
1379 gettext("diskqueue %s is incompatible"), qvol);
1380 }
1381 if (rdc_operation(cfg, pair.fhost, pair.ffile, pair.fbitmap,
1382 pair.thost, pair.tfile, pair.tbitmap, subcmd, 0,
1383 pair.directfile, pair.group, pair.ctag, qvol, &pair.doasync,
1384 0) < 0) {
1385 if (cfg_vol_disable(cfg, qvol, ctag, "sndr") < 0)
1386 rdc_warn(NULL, gettext("Failed to remove disk "
1387 "queue [%s] from configuration"), qvol);
1388 rdc_err(NULL, gettext("Add disk queue operation "
1389 "failed"));
1390 }
1391 if (nsc_lookup(volhash, qvol) == NULL) {
1392 if (cfg_vol_enable(cfg, qvol, ctag, "sndr") < 0) {
1393 rdc_err(NULL, gettext("Add disk queue "
1394 "operation failed"));
1395 }
1396 }
1397 rewrite_group_diskqueue(cfg, &pair, qvol);
1398
1399 spcs_log("sndr", NULL, gettext("Remote Mirror: added "
1400 "diskqueue %s to set %s:%s and its group"), qvol,
1401 pair.thost, pair.tfile);
1402 break;
1403 case RDC_OPT_FORCE_QINIT:
1404 if (strlen(pair.diskqueue) == 0) {
1405 rdc_err(NULL, gettext("Remote Mirror set does not "
1406 "have a disk queue"));
1407 }
1408 subcmd = RDC_CMD_INITQ;
1409 option = RDC_OPT_FORCE_QINIT;
1410 if (rdc_operation(cfg, pair.fhost, pair.ffile, pair.fbitmap,
1411 pair.thost, pair.tfile, pair.tbitmap, subcmd, option,
1412 pair.directfile, pair.group, pair.ctag, qvol, &pair.doasync,
1413 0) < 0) {
1414 exit(1);
1415 }
1416 break;
1417 case RDC_CMD_INITQ:
1418 if (strlen(pair.diskqueue) == 0) {
1419 rdc_err(NULL, gettext("Remote Mirror set does not "
1420 "have a disk queue"));
1421 }
1422 if (rdc_operation(cfg, pair.fhost, pair.ffile, pair.fbitmap,
1423 pair.thost, pair.tfile, pair.tbitmap, subcmd, 0,
1424 pair.directfile, pair.group, pair.ctag, qvol, &pair.doasync,
1425 0) < 0) {
1426 exit(1);
1427 }
1428 break;
1429 case RDC_CMD_REMQ:
1430 if (strlen(pair.diskqueue) == 0) {
1431 rdc_err(NULL, gettext("Remote Mirror set does not "
1432 "have a disk queue"));
1433 }
1434 if (rdc_operation(cfg, pair.fhost, pair.ffile, pair.fbitmap,
1435 pair.thost, pair.tfile, pair.tbitmap, subcmd, 0,
1436 pair.directfile, pair.group, pair.ctag, qvol, &pair.doasync,
1437 0) < 0) {
1438 exit(1);
1439 }
1440 if (cfg_vol_disable(cfg, pair.diskqueue, ctag, "sndr") < 0)
1441 rdc_warn(NULL, gettext("Failed to remove disk queue "
1442 "[%s] from configuration"), pair.diskqueue);
1443 rewrite_group_diskqueue(cfg, &pair, place_holder);
1444
1445 spcs_log("sndr", NULL, gettext("Remote Mirror: removed "
1446 "diskqueue from set %s:%s and its group"), pair.thost,
1447 pair.tfile);
1448 break;
1449 case RDC_CMD_KILLQ:
1450 if (strlen(pair.diskqueue) == 0) {
1451 rdc_err(NULL, gettext("Remote Mirror set does not "
1452 "have a disk queue"));
1453 }
1454 if (rdc_operation(cfg, pair.fhost, pair.ffile, pair.fbitmap,
1455 pair.thost, pair.tfile, pair.tbitmap, subcmd, 0,
1456 pair.directfile, pair.group, pair.ctag, qvol, &pair.doasync,
1457 0) < 0) {
1458 rdc_err(NULL, gettext("Failed to remove disk queue"));
1459 }
1460 if (cfg_vol_disable(cfg, pair.diskqueue, ctag, "sndr") < 0)
1461 rdc_warn(NULL, gettext("Failed to remove disk queue "
1462 "[%s] from configuration"), pair.diskqueue);
1463
1464 rewrite_group_diskqueue(cfg, &pair, place_holder);
1465
1466 spcs_log("sndr", NULL, gettext("Remote Mirror: forcibly "
1467 "removed diskqueue from set %s:%s and its group "),
1468 pair.thost, pair.tfile);
1469 break;
1470 case RDC_CMD_REPQ:
1471 if (clustered && (ctag_check(pair.fhost, pair.ffile,
1472 pair.fbitmap, pair.thost, pair.tfile, pair.tbitmap,
1473 pair.ctag, qvol) < 0))
1474 exit(1);
1475
1476 if (strlen(pair.diskqueue) == 0) {
1477 rdc_err(NULL, gettext("Remote Mirror set does not "
1478 "have a disk queue"));
1479 }
1480 if (rdc_operation(cfg, pair.fhost, pair.ffile, pair.fbitmap,
1481 pair.thost, pair.tfile, pair.tbitmap, RDC_CMD_REMQ, 0,
1482 pair.directfile, pair.group, pair.ctag, qvol, &pair.doasync,
1483 0) < 0) {
1484 rdc_err(NULL, gettext("Failed to remove disk queue"));
1485 }
1486 if (cfg_vol_disable(cfg, pair.diskqueue, ctag, "sndr") < 0)
1487 rdc_warn(NULL, gettext("Failed to remove disk queue "
1488 "[%s] from configuration"), pair.diskqueue);
1489
1490 rewrite_group_diskqueue(cfg, &pair, place_holder);
1491
1492 /* commit here, enable may fail */
1493 if (cfg_commit(cfg) < 0) {
1494 rdc_err(NULL, gettext("commit replace disk queue %s "
1495 "with %s failed"), pair.diskqueue, qvol);
1496 }
1497
1498 if (check_diskqueue(cfg, qvol, group_arg) == DISKQ_FAIL) {
1499 rdc_err(NULL,
1500 gettext("cannot replace disk queue %s with %s"),
1501 pair.diskqueue, qvol);
1502 }
1503 if (rdc_operation(cfg, pair.fhost, pair.ffile, pair.fbitmap,
1504 pair.thost, pair.tfile, pair.tbitmap, RDC_CMD_ADDQ, 0,
1505 pair.directfile, pair.group, pair.ctag, qvol, &pair.doasync,
1506 0) < 0) {
1507 if (cfg_vol_disable(cfg, qvol, ctag, "sndr") < 0)
1508 rdc_warn(NULL, gettext("Failed to remove disk "
1509 "queue [%s] from configuration"), qvol);
1510 rdc_err(NULL, gettext("Failed to add new disk queue"));
1511 }
1512 if (nsc_lookup(volhash, qvol) == NULL)
1513 if (cfg_vol_enable(cfg, qvol, ctag, "sndr") < 0) {
1514 rdc_err(NULL, gettext("Replace disk queue "
1515 "operation failed"));
1516 }
1517
1518 rewrite_group_diskqueue(cfg, &pair, qvol);
1519
1520 spcs_log("sndr", NULL, gettext("Remote Mirror: replaced "
1521 "diskqueue for set %s:%s and its group with %s"),
1522 pair.thost, pair.tfile, qvol);
1523 break;
1524 }
1525
1526 cfg_unload_svols(cfg);
1527 cfg_unload_dsvols(cfg);
1528 cfg_unload_shadows(cfg);
1529 unload_rdc_vols();
1530
1531 if (cfg_commit(cfg) < 0)
1532 rdc_err(NULL, gettext("commit failed on disk queue operation"));
1533
1534 cfg_close(cfg);
1535 if (ctag)
1536 free(ctag);
1537 }
1538 void
spcslog_sync(rdcconfig_t * sets,int start,int type)1539 spcslog_sync(rdcconfig_t *sets, int start, int type)
1540 {
1541 rdcconfig_t *setp = sets;
1542
1543 while (setp) {
1544 if (start) {
1545 spcs_log("sndr", NULL,
1546 gettext("%s %s %s %s %s %s %s %s\nSync Started"),
1547 program, rdc_decode_flag(RDC_CMD_COPY, type),
1548 setp->phost, setp->pfile, setp->pbmp,
1549 setp->shost, setp->sfile, setp->sbmp);
1550 } else {
1551 spcs_log("sndr", NULL,
1552 gettext("%s %s %s %s %s %s %s %s\nSync Ended"),
1553 program, rdc_decode_flag(RDC_CMD_COPY, type),
1554 setp->phost, setp->pfile, setp->pbmp,
1555 setp->shost, setp->sfile, setp->sbmp);
1556 }
1557 setp = setp->next;
1558 }
1559 }
1560
1561 void
spcslog_tunable(char * shost,char * svol)1562 spcslog_tunable(char *shost, char *svol)
1563 {
1564 if (qblock == RDC_OPT_SET_QNOBLOCK)
1565 spcs_log("sndr", NULL, gettext("diskqueue "
1566 "set to non blocking for %s:%s and any members "
1567 "of it's group"), shost, svol);
1568 else if (qblock == RDC_OPT_CLR_QNOBLOCK)
1569 spcs_log("sndr", NULL, gettext("diskqueue "
1570 "set to blocking for %s:%s and any members "
1571 "of it's group"), shost, svol);
1572
1573 if (maxqfbas)
1574 spcs_log("sndr", NULL, gettext("maxqfbas set to %d for %s:%s"),
1575 maxqfbas, shost, svol);
1576 if (maxqitems)
1577 spcs_log("sndr", NULL, gettext("maxwrites set to %d for %s:%s"),
1578 maxqitems, shost, svol);
1579 if (asyncthr)
1580 spcs_log("sndr", NULL, gettext("%d async threads configured "
1581 "for %s:%s"), asyncthr, shost, svol);
1582 }
1583
1584 int
set_qblock(char * blockarg)1585 set_qblock(char *blockarg)
1586 {
1587 if (strcmp(blockarg, "block") == 0)
1588 qblock = RDC_OPT_CLR_QNOBLOCK;
1589 else if (strcmp(blockarg, "noblock") == 0)
1590 qblock = RDC_OPT_SET_QNOBLOCK;
1591 else
1592 return (1);
1593
1594 return (0);
1595 }
1596
1597 static void
rdc_force_disable(CFGFILE * cfg,char * phost,char * pvol,char * pbmp,char * shost,char * svol,char * sbmp,char * ctag,char * lhname)1598 rdc_force_disable(CFGFILE *cfg, char *phost, char *pvol, char *pbmp,
1599 char *shost, char *svol, char *sbmp, char *ctag, char *lhname)
1600 {
1601 rdc_config_t parms;
1602 spcs_s_info_t ustatus;
1603 volcount_t *vc;
1604 char *datavol = NULL;
1605 char *bmpvol = NULL;
1606 int on_pri = 0;
1607 int on_sec = 0;
1608
1609 /* are we on the primary or secondary host? */
1610 if (ctag && *ctag && *lhname) {
1611 if (strcmp(phost, lhname) == 0) {
1612 on_pri = 1;
1613 } else if (strcmp(shost, lhname) == 0) {
1614 on_sec = 1;
1615 }
1616 } else if (self_check(phost)) {
1617 on_pri = 1;
1618 } else if (self_check(shost)) {
1619 on_sec = 1;
1620 }
1621
1622 if (on_pri) {
1623 datavol = pvol;
1624 bmpvol = pbmp;
1625 } else if (on_sec) {
1626 datavol = svol;
1627 bmpvol = sbmp;
1628 } else {
1629 rdc_err(NULL, gettext("Unable to determine whether current "
1630 "node is primary or secondary"));
1631 }
1632
1633 /* set up parms structure */
1634 parms.command = RDC_CMD_DISABLE;
1635 (void) strncpy(parms.rdc_set->primary.intf, phost, MAX_RDC_HOST_SIZE);
1636 (void) strncpy(parms.rdc_set->primary.file, pvol, NSC_MAXPATH);
1637 (void) strncpy(parms.rdc_set->secondary.intf, shost, MAX_RDC_HOST_SIZE);
1638 (void) strncpy(parms.rdc_set->secondary.file, svol, NSC_MAXPATH);
1639 ustatus = spcs_s_ucreate();
1640 parms.options = RDC_OPT_FORCE_DISABLE;
1641
1642 /*
1643 * We are now going to 'force' the kernel to disable the set. By
1644 * setting the RDC_OPT_FORCE_DISABLE flag, the kernel will bypass some
1645 * of the checks that are normally done when attempting to disable
1646 * a set. We need to do this force option in a cluster environment
1647 * when the logical hostname for the primary or secondary volume
1648 * is no longer available.
1649 */
1650 spcs_log("sndr", NULL, "%s sndradm -d %s %s %s %s %s %s",
1651 gettext("FORCE DISABLE"), phost, pvol, pbmp, shost, svol, sbmp);
1652 rdc_warn(NULL, gettext("Forcing set disable"));
1653 if (RDC_IOCTL(RDC_CONFIG, &parms, 0, 0, 0, 0, ustatus) != SPCS_S_OK)
1654 rdc_warn(&ustatus, gettext("set %s:%s not enabled in kernel"),
1655 shost, svol);
1656
1657 /* if we get to this point, then a set was disabled. try sv-disable */
1658 vc = nsc_lookup(volhash, datavol);
1659 if (vc && (1 == vc->count))
1660 if (cfg_vol_disable(cfg, datavol, ctag, "sndr") < 0)
1661 rdc_warn(NULL, gettext("Failed to remove data volume "
1662 "[%s] from configuration"), datavol);
1663 vc = nsc_lookup(volhash, bmpvol);
1664 if (vc && (1 == vc->count))
1665 if (cfg_vol_disable(cfg, bmpvol, ctag, "sndr") < 0)
1666 rdc_warn(NULL, gettext("Failed to remove bitmap "
1667 "[%s] from configuration"), bmpvol);
1668 }
1669
1670 void
check_rdcsecondary(char * secondary)1671 check_rdcsecondary(char *secondary)
1672 {
1673 int i;
1674 CFGFILE *cfg;
1675 int entries;
1676 char **entry;
1677 char *sha;
1678 char *buf;
1679
1680 if ((cfg = cfg_open(NULL)) == NULL)
1681 rdc_err(NULL,
1682 gettext("error opening config"));
1683 if (!cfg_lock(cfg, CFG_RDLOCK))
1684 rdc_err(NULL, gettext("error locking config"));
1685
1686 entry = NULL;
1687 entries = cfg_get_section(cfg, &entry, "ii");
1688 for (i = 0; i < entries; i++) {
1689 buf = entry[i];
1690
1691 (void) strtok(buf, " "); /* master */
1692 sha = strtok(NULL, " "); /* shadow */
1693 if (strcmp(secondary, sha) == 0) {
1694 rdc_err(NULL,
1695 gettext("secondary %s is in use by"
1696 " Point-in-Time Copy"), secondary);
1697 }
1698 free(buf);
1699 }
1700 if (entries)
1701 free(entry);
1702 cfg_close(cfg);
1703 }
1704
1705 int
main(int argc,char * argv[])1706 main(int argc, char *argv[])
1707 {
1708 char config_file[FILENAME_MAX];
1709 char fromhost[MAX_RDC_HOST_SIZE];
1710 char tohost[MAX_RDC_HOST_SIZE];
1711 char fromfile[NSC_MAXPATH];
1712 char tofile[NSC_MAXPATH];
1713 char frombitmap[NSC_MAXPATH];
1714 char tobitmap[NSC_MAXPATH];
1715 char directfile[NSC_MAXPATH];
1716 char group[NSC_MAXPATH];
1717 char ctag[MAX_RDC_HOST_SIZE];
1718 char options_cfg[CFG_MAX_BUF];
1719 char fromnetaddr[RDC_MAXADDR];
1720 char tonetaddr[RDC_MAXADDR];
1721 char tmphost[MAX_RDC_HOST_SIZE];
1722 char tmpfile[NSC_MAXPATH];
1723 char tmpbitmap[NSC_MAXPATH];
1724 char diskqueue[NSC_MAXPATH];
1725 char lhname[MAX_RDC_HOST_SIZE];
1726 char mode[16];
1727 rdc_version_t rdc_version;
1728 int pairs;
1729 int pid;
1730 int flag = 0;
1731 int fflag = 0;
1732 int reverse = 0;
1733 int nflag = 0;
1734 int iflag = 0;
1735 int doasync;
1736 int pflag = 0;
1737 int vflag = 0;
1738 int verbose = 0;
1739 int errflag = 0;
1740 int cfgflag = 0;
1741 int cfg_success;
1742 int Iflag = 0;
1743 char c;
1744 char inval = 0;
1745 int found;
1746 int rc;
1747 int geflag = 0;
1748 int qflag = 0;
1749 char *qarg;
1750 int Bflag = 0;
1751 char *bitfile;
1752 CFGFILE *cfg = NULL;
1753 int i;
1754 int setnumber;
1755 char key[CFG_MAX_KEY];
1756 char buf[CFG_MAX_BUF];
1757 char ctag_arg[MAX_RDC_HOST_SIZE];
1758 char group_arg[NSC_MAXPATH];
1759 int file_format = 0;
1760 int sev;
1761 int diskq_group = DISKQ_OKAY;
1762 int extra_argc;
1763 char *ctag_p, *group_p, *diskqueue_p;
1764 char *required;
1765 char *role_env;
1766 int checksetfields = -1;
1767 nsc_off_t boffset = 0;
1768 int oflag = 0;
1769 rdcconfig_t *sets = NULL;
1770 rdcconfig_t *sets_p = NULL;
1771 rdc_rc_t *rclist = NULL;
1772 rdc_rc_t *rcp = NULL;
1773 int host_not_found = 0;
1774
1775 (void) setlocale(LC_ALL, "");
1776 (void) textdomain("rdc");
1777 role_env = getenv("SNDR_ROLE_REVERSE");
1778 if (role_env && strcmp(role_env, "sndr_allow_reverse") == 0)
1779 allow_role = 1;
1780
1781 program = basename(argv[0]);
1782
1783 rc = rdc_check_release(&required);
1784 if (rc < 0) {
1785 rdc_err(NULL,
1786 gettext("unable to determine the current "
1787 "Solaris release: %s\n"), strerror(errno));
1788 } else if (rc == FALSE) {
1789 rdc_err(NULL,
1790 gettext("incorrect Solaris release (requires %s)\n"),
1791 required);
1792 }
1793
1794 if ((clustered = cfg_iscluster()) < 0) {
1795 rdc_err(NULL, gettext("unable to ascertain environment"));
1796 }
1797
1798 (void) strcpy(ctag_arg, "");
1799 (void) strcpy(group_arg, "");
1800 bzero(ctag, MAX_RDC_HOST_SIZE);
1801 bzero(reconfig_ctag, MAX_RDC_HOST_SIZE);
1802 bzero(diskqueue, NSC_MAXPATH);
1803
1804 rdc_maxsets = rdc_get_maxsets();
1805 if (rdc_maxsets == -1) {
1806 rdc_err(NULL,
1807 gettext("unable to get maxsets value from kernel"));
1808 }
1809
1810 pair_list = calloc(rdc_maxsets, sizeof (*pair_list));
1811 if (pair_list == NULL) {
1812 rdc_err(NULL,
1813 gettext("unable to allocate pair_list array for %d sets"),
1814 rdc_maxsets);
1815 }
1816
1817 bzero(group, sizeof (group));
1818 bzero(diskqueue, sizeof (diskqueue));
1819 qblock = 0;
1820
1821 while ((c =
1822 #ifdef DEBUG
1823 getopt(argc, argv, "A:B:C:D:EF:HIO:PRUW:a:bdef:g:hilmno:pq:rsuvw"))
1824 #else
1825 getopt(argc, argv, "A:B:C:D:EF:HIO:PRUW:a:bdef:g:hilmno:pq:rsuvw"))
1826 #endif
1827 != -1) {
1828 switch (c) {
1829 case 'B':
1830 if (!allow_role || flag) {
1831 inval = 1;
1832 break;
1833 }
1834 bitfile = optarg;
1835 Bflag = 1;
1836 flag = RDC_BITMAPOP;
1837 break;
1838 case 'H':
1839 /* 'h' was already assigned */
1840 if (flag)
1841 inval = 1;
1842 flag = RDC_CMD_HEALTH;
1843 break;
1844 case 'I':
1845 /* List or edit ndr_ii configuration entries */
1846 Iflag = 1;
1847 break;
1848 case 'R':
1849 if (flag)
1850 inval = 1;
1851 flag = RDC_CMD_RECONFIG;
1852 break;
1853 #ifdef DEBUG
1854 case 'U': /* UDP support */
1855 proto_test = 1;
1856 break;
1857 #endif
1858 case 'F':
1859 if (flag && flag != RDC_CMD_TUNABLE)
1860 inval = 1;
1861 flag = RDC_CMD_TUNABLE;
1862
1863 if (check_intrange(optarg))
1864 maxqfbas = atoi(optarg);
1865 else
1866 exit(1);
1867
1868 break;
1869 case 'W':
1870 if (flag && flag != RDC_CMD_TUNABLE)
1871 inval = 1;
1872 flag = RDC_CMD_TUNABLE;
1873
1874 if (check_intrange(optarg))
1875 maxqitems = atoi(optarg);
1876 else
1877 exit(1);
1878
1879 break;
1880 case 'A':
1881 if (flag && flag != RDC_CMD_TUNABLE)
1882 inval = 1;
1883 flag = RDC_CMD_TUNABLE;
1884
1885 if (check_intrange(optarg))
1886 asyncthr = atoi(optarg);
1887 else
1888 exit(1);
1889
1890 break;
1891 case 'D':
1892 if (flag && flag != RDC_CMD_TUNABLE)
1893 inval = 1;
1894 flag = RDC_CMD_TUNABLE;
1895
1896 if (set_qblock(optarg)) {
1897 usage();
1898 exit(1);
1899 }
1900 iflag |= qblock;
1901 break;
1902 case 'a':
1903 if (flag && flag != RDC_CMD_TUNABLE)
1904 inval = 1;
1905 flag = RDC_CMD_TUNABLE;
1906 if (strcmp(optarg, "off") == 0)
1907 autosync = AUTOSYNC_OFF;
1908 else if (strcmp(optarg, "on") == 0)
1909 autosync = AUTOSYNC_ON;
1910 else
1911 inval = 1;
1912 break;
1913 case 'C':
1914 if (clustered) {
1915 (void) strncpy(ctag_arg, optarg,
1916 MAX_RDC_HOST_SIZE);
1917 process_clocal(ctag_arg);
1918 } else
1919 inval = 1;
1920 break;
1921 case 'g':
1922 if (flag == RDC_CMD_ENABLE)
1923 inval = 1;
1924 geflag = 1;
1925 (void) strncpy(group_arg, optarg, NSC_MAXPATH);
1926 verify_groupname(group_arg);
1927 break;
1928 case 'b':
1929 /* ignore */
1930 break;
1931 case 'n':
1932 nflag = 1;
1933 break;
1934 case 'd':
1935 if (flag)
1936 inval = 1;
1937 flag = RDC_CMD_DISABLE;
1938 break;
1939 case 'e':
1940 if (flag || geflag)
1941 inval = 1;
1942 flag = RDC_CMD_ENABLE;
1943 iflag |= RDC_OPT_SETBMP;
1944 break;
1945 case 'E':
1946 if (flag)
1947 inval = 1;
1948 flag = RDC_CMD_ENABLE;
1949 iflag |= RDC_OPT_CLRBMP;
1950 break;
1951 case 'f':
1952 fflag = 1;
1953 (void) strcpy(config_file, optarg);
1954 break;
1955 case 'h':
1956 usage();
1957 exit(0);
1958 break;
1959 case 'l':
1960 if (flag)
1961 inval = 1;
1962 flag = RDC_CMD_LOG;
1963 break;
1964 case 'm':
1965 if (flag)
1966 inval = 1;
1967 flag = RDC_CMD_COPY;
1968 iflag |= RDC_OPT_FULL;
1969 break;
1970 case 'O':
1971 case 'o':
1972
1973 if (!allow_role || oflag) {
1974 inval = 1;
1975 break;
1976 }
1977 if (c == 'o') {
1978 oflag = RDC_BITMAPOR;
1979 } else {
1980 oflag = RDC_BITMAPSET;
1981 }
1982 boffset = strtoull(optarg, NULL, 0);
1983 break;
1984 case 'P':
1985 if (flag)
1986 inval = 1;
1987 pflag = 1;
1988 verbose = 1;
1989 break;
1990 case 'p':
1991 if (flag)
1992 inval = 1;
1993 pflag = 1;
1994 break;
1995 case 'q':
1996 if (flag)
1997 inval = 1;
1998 flag = RDC_CMD_INITQ;
1999 qflag = optind;
2000 qarg = optarg;
2001 break;
2002 case 'i':
2003 if (flag)
2004 inval = 1;
2005 pflag = 1;
2006 file_format = 1;
2007 break;
2008 case 'r':
2009 reverse = 1;
2010 iflag |= RDC_OPT_REVERSE;
2011 break;
2012 case 's':
2013 if (flag)
2014 inval = 1;
2015 flag = RDC_CMD_STATUS;
2016 nflag = 1; /* No prompt for a status */
2017 break;
2018 case 'u':
2019 if (flag)
2020 inval = 1;
2021 flag = RDC_CMD_COPY;
2022 iflag |= RDC_OPT_UPDATE;
2023 break;
2024 case 'v':
2025 if (flag)
2026 inval = 1;
2027 pflag = 1;
2028 vflag = 1;
2029 break;
2030 case 'w':
2031 if (flag)
2032 inval = 1;
2033 flag = RDC_CMD_WAIT;
2034 break;
2035 case '?':
2036 errflag++;
2037 }
2038 }
2039
2040 if (inval || ((flag != RDC_BITMAPOP) && oflag)) {
2041 rdc_warn(NULL, gettext("invalid argument combination"));
2042 errflag = 1;
2043 }
2044
2045 if (flag && Iflag) {
2046 /* Mutually incompatible */
2047 usage();
2048 exit(1);
2049 }
2050
2051 if (Iflag) {
2052 rdc_ii_config(argc, argv);
2053 exit(0);
2054 }
2055
2056 if (vflag) {
2057 spcs_s_info_t ustatus;
2058
2059 ustatus = spcs_s_ucreate();
2060 rc = RDC_IOCTL(RDC_VERSION, &rdc_version, 0, 0, 0, 0, ustatus);
2061 if (rc == SPCS_S_ERROR) {
2062 rdc_err(&ustatus, gettext("statistics error"));
2063 }
2064 spcs_s_ufree(&ustatus);
2065 #ifdef DEBUG
2066 (void) printf(gettext("Remote Mirror version %d.%d.%d.%d\n"),
2067 rdc_version.major, rdc_version.minor,
2068 rdc_version.micro, rdc_version.baseline);
2069 #else
2070 if (rdc_version.micro) {
2071 (void) printf(gettext(
2072 "Remote Mirror version %d.%d.%d\n"),
2073 rdc_version.major,
2074 rdc_version.minor,
2075 rdc_version.micro);
2076 } else {
2077 (void) printf(gettext("Remote Mirror version %d.%d\n"),
2078 rdc_version.major, rdc_version.minor);
2079 }
2080 #endif
2081 exit(0);
2082 }
2083
2084 if (!(flag || pflag) || errflag) {
2085 usage();
2086 exit(1);
2087 }
2088
2089 if (pflag && !fflag && (argc - optind) == 0) {
2090 /* print with no set specified */
2091 exit(rdc_print(file_format, verbose,
2092 group_arg, ctag_arg, NULL, NULL, NULL));
2093 }
2094
2095 if (qflag) { /* change disk queue setting */
2096 int subcmd = 0;
2097 int offset = 0;
2098 char *ptr;
2099 char *qvol;
2100 char tohost_arg[MAX_RDC_HOST_SIZE];
2101 char tofile_arg[NSC_MAXPATH];
2102
2103 if (strcmp("a", qarg) == 0) {
2104 subcmd = RDC_CMD_ADDQ;
2105 offset = 1;
2106 } else if (strcmp("d", qarg) == 0) {
2107 subcmd = RDC_CMD_REMQ;
2108 offset = 0;
2109 } else if (strcmp("r", qarg) == 0) {
2110 subcmd = RDC_CMD_REPQ;
2111 offset = 1;
2112 } else {
2113 rdc_warn(NULL, " %s Invalid qopt", qarg);
2114 q_usage(1);
2115 exit(1);
2116 }
2117 if (strlen(group_arg) == 0) {
2118 /* pick out single set as shost:svol */
2119 ptr = strtok(argv[qflag + offset], ":");
2120 if (ptr)
2121 (void) strncpy(tohost_arg, ptr,
2122 MAX_RDC_HOST_SIZE);
2123 else {
2124 rdc_warn(NULL, gettext("Bad host specified"));
2125 q_usage(1);
2126 exit(1);
2127 }
2128 ptr = strtok(NULL, ":");
2129 if (ptr)
2130 (void) strncpy(tofile_arg, ptr, NSC_MAXPATH);
2131 else {
2132 rdc_warn(NULL, gettext("Bad set specified"));
2133 q_usage(1);
2134 exit(1);
2135 }
2136 }
2137
2138 qvol = argv[qflag];
2139 if ((qvol == NULL) && (subcmd != RDC_CMD_REMQ)) {
2140 rdc_warn(NULL, gettext("missing queue volume"));
2141 q_usage(1);
2142 exit(1);
2143 }
2144 diskq_subcmd(subcmd, qvol, group_arg, ctag_arg,
2145 tohost_arg, tofile_arg);
2146 exit(0);
2147 }
2148
2149 if (flag == RDC_CMD_RECONFIG && !fflag) {
2150 /* See what is to be reconfigured */
2151 if (argc - optind == 0)
2152 flag = RDC_CMD_RESET;
2153 else {
2154 if (argc - optind < 2) {
2155 usage();
2156 exit(1);
2157 }
2158 c = *argv[optind++];
2159 if (argv[optind -1][1] != '\0') {
2160 usage();
2161 exit(2);
2162 }
2163 switch (c) {
2164 case 'b':
2165 if (argc - optind < 2) {
2166 usage();
2167 exit(1);
2168 }
2169 if (*argv[optind] == 'p')
2170 reconfig_pbitmap = argv[++optind];
2171 else if (*argv[optind] == 's')
2172 reconfig_sbitmap = argv[++optind];
2173 else {
2174 usage();
2175 exit(1);
2176 }
2177 optind++;
2178 break;
2179 #ifdef _RDC_CAMPUS
2180 case 'd':
2181 reconfig_direct = argv[optind++];
2182 break;
2183 #endif
2184 case 'g':
2185 reconfig_group = argv[optind++];
2186 verify_groupname(reconfig_group);
2187 break;
2188 case 'C':
2189 if (clustered) {
2190 (void) strncpy(reconfig_ctag,
2191 argv[optind++], MAX_RDC_HOST_SIZE);
2192 process_clocal(reconfig_ctag);
2193 } else {
2194 usage();
2195 exit(1);
2196 }
2197 break;
2198 case 'm':
2199 if (strcmp(argv[optind], "sync") == 0)
2200 reconfig_doasync = 0;
2201 else if (strcmp(argv[optind], "async") == 0)
2202 reconfig_doasync = 1;
2203 else {
2204 usage();
2205 exit(1);
2206 }
2207 optind++;
2208 break;
2209 case 'r':
2210 if (allow_role) {
2211 iflag |= RDC_OPT_REVERSE_ROLE;
2212 break;
2213 }
2214 default:
2215 usage();
2216 exit(1);
2217 }
2218 }
2219 }
2220 if (fflag) {
2221 checksetfields = 1;
2222 if ((argc - optind) != 0) {
2223 usage();
2224 exit(1);
2225 }
2226 } else {
2227 if ((argc - optind) == 0) {
2228 /* Use libcfg to figure out what to operate on */
2229 cfgflag = 1;
2230 #ifdef DEBUG
2231 rdc_warn(NULL, gettext("using current config"));
2232 #endif
2233 checksetfields = 0;
2234 } else {
2235 if ((argc - optind) < 8 && (argc - optind) != 1) {
2236 usage();
2237 exit(1);
2238 }
2239 }
2240 }
2241
2242 if (cfgflag) {
2243 if (flag == RDC_CMD_ADDQ ||
2244 flag == RDC_CMD_REMQ ||
2245 flag == RDC_CMD_KILLQ ||
2246 flag == RDC_CMD_INITQ) {
2247 rdc_err(NULL, gettext("can not use current config "
2248 "for disk queue operations"));
2249 }
2250 } else if (fflag) {
2251 if (flag == RDC_CMD_ADDQ ||
2252 flag == RDC_CMD_REMQ ||
2253 flag == RDC_CMD_KILLQ ||
2254 flag == RDC_CMD_INITQ) {
2255 rdc_err(NULL, gettext("can not use a config file "
2256 "for disk queue operations"));
2257 }
2258 }
2259 if (cfgflag) {
2260 if (flag == RDC_CMD_ENABLE) {
2261 rdc_err(NULL, gettext("can not use current config "
2262 "for enable command"));
2263 }
2264 if ((flag == RDC_CMD_RECONFIG) && (reconfig_pbitmap ||
2265 reconfig_sbitmap)) {
2266 rdc_err(NULL, gettext("can not use current config "
2267 "for bitmap reconfiguration"));
2268 }
2269 if (flag == RDC_BITMAPOP) {
2270 rdc_err(NULL, gettext("can not use current config "
2271 "for bitmap set command"));
2272 }
2273 pairs = read_libcfg(flag, group_arg, ctag_arg);
2274 if (pairs == 0) {
2275 (void) fprintf(stderr,
2276 gettext("no matching Remote Mirror sets found "
2277 "in config\n"));
2278 exit(1);
2279 }
2280 } else if (!fflag) {
2281 /*
2282 * Format is either:
2283 *
2284 * tohost:tofile
2285 *
2286 * or something like this for example:
2287 *
2288 * fromhost fromfile frombitmap tohost tofile tobitmap ip sync
2289 * g group C ctag
2290 */
2291
2292 if (argc - optind == 1) {
2293 char tohost_arg[MAX_RDC_HOST_SIZE];
2294 char tofile_arg[NSC_MAXPATH];
2295 char *ptr;
2296
2297 checksetfields = 0;
2298 if (flag == RDC_CMD_ENABLE) {
2299 rdc_err(NULL,
2300 gettext("must specify full set details for "
2301 "enable command"));
2302 }
2303 ptr = strtok(argv[optind], ":");
2304 if (ptr)
2305 (void) strncpy(tohost_arg, ptr,
2306 MAX_RDC_HOST_SIZE);
2307 else {
2308 rdc_err(NULL, gettext("Bad host specified"));
2309 }
2310 ptr = strtok(NULL, ":");
2311 if (ptr)
2312 (void) strncpy(tofile_arg, ptr, NSC_MAXPATH);
2313 else {
2314 rdc_err(NULL, gettext("Bad set specified"));
2315 }
2316
2317 /* Now look up tohost:tofile via libcfg */
2318
2319 if ((cfg = cfg_open(NULL)) == NULL)
2320 rdc_err(NULL,
2321 gettext("unable to access configuration"));
2322
2323 if (!cfg_lock(cfg, CFG_RDLOCK))
2324 rdc_err(NULL,
2325 gettext("unable to lock configuration"));
2326
2327 setnumber = 0;
2328 found = 0;
2329 /*CSTYLED*/
2330 for (i = 0; i < rdc_maxsets;) {
2331 setnumber++;
2332
2333 bzero(buf, CFG_MAX_BUF);
2334 (void) snprintf(key, sizeof (key),
2335 "sndr.set%d", setnumber);
2336 rc = cfg_get_cstring(cfg, key, buf,
2337 CFG_MAX_BUF);
2338 if (rc < 0)
2339 break;
2340
2341 (void) snprintf(key, sizeof (key),
2342 "sndr.set%d.shost", setnumber);
2343 (void) cfg_get_cstring(cfg, key, tohost,
2344 sizeof (tohost));
2345 if (strncmp(tohost, tohost_arg, NSC_MAXPATH))
2346 continue;
2347
2348 (void) snprintf(key, sizeof (key),
2349 "sndr.set%d.secondary", setnumber);
2350 (void) cfg_get_cstring(cfg, key, tofile,
2351 sizeof (tofile));
2352 if (strncmp(tofile, tofile_arg, NSC_MAXPATH))
2353 continue;
2354
2355 found = 1;
2356
2357 (void) snprintf(key, sizeof (key),
2358 "sndr.set%d.phost", setnumber);
2359 (void) cfg_get_cstring(cfg, key, fromhost,
2360 sizeof (fromhost));
2361
2362 (void) snprintf(key, sizeof (key),
2363 "sndr.set%d.primary", setnumber);
2364 (void) cfg_get_cstring(cfg, key, fromfile,
2365 sizeof (fromfile));
2366
2367 (void) snprintf(key, sizeof (key),
2368 "sndr.set%d.pbitmap", setnumber);
2369 (void) cfg_get_cstring(cfg, key, frombitmap,
2370 sizeof (frombitmap));
2371
2372 (void) snprintf(key, sizeof (key),
2373 "sndr.set%d.sbitmap", setnumber);
2374 (void) cfg_get_cstring(cfg, key, tobitmap,
2375 sizeof (tobitmap));
2376
2377 (void) snprintf(key, sizeof (key),
2378 "sndr.set%d.type", setnumber);
2379 (void) cfg_get_cstring(cfg, key, directfile,
2380 sizeof (directfile));
2381 if (strcmp(directfile, "ip") == 0)
2382 (void) strcpy(directfile, "");
2383
2384 (void) snprintf(key, sizeof (key),
2385 "sndr.set%d.mode", setnumber);
2386 (void) cfg_get_cstring(
2387 cfg, key, mode, sizeof (mode));
2388
2389 (void) snprintf(key, sizeof (key),
2390 "sndr.set%d.group", setnumber);
2391 (void) cfg_get_cstring(cfg, key, group,
2392 sizeof (group));
2393 if (strcmp(group_arg, "") &&
2394 strncmp(group_arg, group, NSC_MAXPATH))
2395 continue;
2396 (void) snprintf(key, sizeof (key),
2397 "sndr.set%d.cnode", setnumber);
2398 (void) cfg_get_cstring(
2399 cfg, key, ctag, sizeof (ctag));
2400 if ((strlen(ctag_arg) > 0) &&
2401 (strcmp(ctag_arg, ctag) != 0))
2402 rdc_err(NULL,
2403 gettext("ctags %s and %s "
2404 "do not match"), ctag_arg, ctag);
2405
2406 if (strcmp(mode, "sync") == 0)
2407 doasync = 0;
2408 else if (strcmp(mode, "async") == 0)
2409 doasync = 1;
2410 else {
2411 rdc_err(NULL,
2412 gettext("set %s:%s neither sync "
2413 "nor async"), tohost, tofile);
2414 }
2415 break;
2416 }
2417 cfg_close(cfg);
2418 if (!found) {
2419 rdc_err(NULL,
2420 gettext("set %s:%s not found in config"),
2421 tohost_arg, tofile_arg);
2422 }
2423 } else {
2424 checksetfields = 1;
2425 (void) strncpy(fromhost, argv[optind],
2426 MAX_RDC_HOST_SIZE);
2427 (void) strncpy(fromfile, argv[optind+1], NSC_MAXPATH);
2428 (void) strncpy(frombitmap, argv[optind+2], NSC_MAXPATH);
2429 (void) strncpy(tohost, argv[optind+3],
2430 MAX_RDC_HOST_SIZE);
2431 (void) strncpy(tofile, argv[optind+4], NSC_MAXPATH);
2432 (void) strncpy(tobitmap, argv[optind+5], NSC_MAXPATH);
2433
2434 /* Check the length of entries from the command line */
2435 if ((fromhost[MAX_RDC_HOST_SIZE - 1] != '\0') ||
2436 (tohost[MAX_RDC_HOST_SIZE - 1] != '\0')) {
2437 rdc_err(NULL,
2438 gettext("hostname is longer than %d "
2439 "characters\n"), (MAX_RDC_HOST_SIZE - 1));
2440 }
2441
2442 /* Check if it's ip address -- not allowed */
2443 if ((inet_addr(fromhost) != (in_addr_t)(-1)) ||
2444 (inet_addr(tohost) != (in_addr_t)(-1))) {
2445 rdc_err(NULL, gettext(
2446 "The hostname specified is invalid.\n"
2447 "See 'man inet(3SOCKET)'"));
2448 }
2449
2450 if ((fromfile[NSC_MAXPATH - 1] != '\0') ||
2451 (tofile[NSC_MAXPATH - 1] != '\0') ||
2452 (frombitmap[NSC_MAXPATH - 1] != '\0') ||
2453 (tobitmap[NSC_MAXPATH - 1] != '\0')) {
2454 rdc_err(NULL, gettext("device name is longer "
2455 "than %d characters\n"), (NSC_MAXPATH - 1));
2456 }
2457 #ifdef _RDC_CAMPUS
2458 if (argv[optind+6][0] == '/') {
2459 /* FCAL directio */
2460 (void) strncpy(directfile, argv[optind+6],
2461 NSC_MAXPATH);
2462 } else if (strcmp(argv[optind+6], "ip") != 0) {
2463 #else
2464 if (strcmp(argv[optind+6], "ip") != 0) {
2465 #endif
2466 usage();
2467 exit(1);
2468 } else
2469 (void) strcpy(directfile, "ip");
2470
2471 if (strcmp(argv[optind+7], "sync") == 0)
2472 doasync = 0;
2473 else if (strcmp(argv[optind+7], "async") == 0)
2474 doasync = 1;
2475 else {
2476 usage();
2477 exit(1);
2478 }
2479
2480 /*
2481 * At this point, we could have a set which is
2482 * clustered, but neither a 'C ctag' or '-C ctag' has
2483 * been specified. To avoid clobbering the ctag if a
2484 * dscfg operation is done in the future, we should get
2485 * the ctag out of the config at this point. To do this,
2486 * set the cluster resource filter to NULL to look at
2487 * all sets in the config, pulling out the ctag for the
2488 * set matching shost:svol. If the set is not found,
2489 * fail here. Note, we skip this set on an enable as the
2490 * set is not yet in the config, so no need to waste
2491 * time.
2492 */
2493 if ((argc - optind == 8) && clustered &&
2494 (flag != RDC_CMD_ENABLE)) {
2495 int setnumber;
2496 char key[CFG_MAX_KEY];
2497
2498 if ((cfg = cfg_open(NULL)) == NULL) {
2499 rdc_err(NULL,
2500 gettext("unable to access configuration"));
2501 }
2502 if (!cfg_lock(cfg, CFG_RDLOCK)) {
2503 rdc_err(NULL,
2504 gettext("unable to lock configuration"));
2505 }
2506
2507 cfg_resource(cfg, NULL);
2508
2509 if ((setnumber =
2510 find_setnumber_in_libcfg(cfg, NULL, tohost,
2511 tofile)) < 0) {
2512 cfg_close(cfg);
2513 rdc_err(NULL,
2514 gettext("unable to find Remote "
2515 "Mirror set "
2516 "%s:%s in config"),
2517 tohost, tofile);
2518 }
2519
2520 (void) snprintf(key, sizeof (key),
2521 "sndr.set%d.cnode", setnumber);
2522 if (cfg_get_cstring(cfg, key, ctag_arg,
2523 MAX_RDC_HOST_SIZE) < 0) {
2524 cfg_close(cfg);
2525 rdc_err(NULL,
2526 gettext("unable to determine ctag "
2527 "for Remote Mirror set %s:%s"),
2528 tohost, tofile);
2529 }
2530
2531 rdc_islocal = strcmp(ctag_arg, "-") ? 0 : 1;
2532
2533 cfg_close(cfg);
2534 }
2535
2536 extra_argc = argc - optind;
2537 if (extra_argc < 8 || extra_argc > 14 ||
2538 extra_argc % 2 != 0) {
2539 usage();
2540 exit(1);
2541 }
2542
2543 /*
2544 * Loop through all of the extra arguments specified
2545 * on the command line, setting the appropriate values
2546 * for valid entries. If an unrecognized argument is
2547 * detected, abort with error. Note: This hack should be
2548 * removed and we should not accept these entries as
2549 * arguments, they should be passed in as switches.
2550 */
2551 for (i = (8 + optind); i < argc; i += 2) {
2552 /* string case statement */
2553 if (strcmp(argv[i], "g") == 0) {
2554 (void) strncpy(group, argv[i + 1],
2555 NSC_MAXPATH);
2556 if (group[NSC_MAXPATH - 1] != '\0') {
2557 rdc_err(NULL, gettext("group name is "
2558 "longer than %d characters\n"),
2559 (NSC_MAXPATH - 1));
2560 }
2561 } else if (strcmp(argv[i], "C") == 0) {
2562 if (!clustered) {
2563 usage();
2564 exit(1);
2565 }
2566 (void) strncpy(ctag, argv[i + 1],
2567 MAX_RDC_HOST_SIZE);
2568
2569 if (ctag[MAX_RDC_HOST_SIZE - 1] != '\0') {
2570 rdc_err(NULL, gettext("cluster name "
2571 "is longer than %d characters\n"),
2572 (MAX_RDC_HOST_SIZE - 1));
2573 }
2574 process_clocal(ctag);
2575
2576 /*
2577 * well here is something.
2578 * what if they went sndradm -C local
2579 * host a b host a b ip sync C foobar?
2580 * they might be confused
2581 * lets stop them if ctag_arg and ctag
2582 * don't match and forgive if they are
2583 * the same, below also.
2584 */
2585 if ((strlen(ctag_arg) > 0) &&
2586 (strcmp(ctag_arg, ctag) != 0)) {
2587 rdc_err(NULL, gettext("ctags "
2588 "%s and %s do not match "),
2589 ctag_arg, ctag);
2590
2591 }
2592 } else if (strcmp(argv[i], "q") == 0) {
2593 (void) strncpy(diskqueue, argv[i + 1],
2594 NSC_MAXPATH);
2595 if (diskqueue[NSC_MAXPATH - 1] != '\0') {
2596 rdc_err(NULL, gettext("diskq name is "
2597 "longer than %d characters\n"),
2598 (NSC_MAXPATH - 1));
2599 }
2600 } else {
2601 /* Unrecognized argument */
2602 usage();
2603 exit(1);
2604 }
2605 }
2606 }
2607
2608 /*
2609 * Are we able to determine the existance of either
2610 * of these host addresses?
2611 */
2612 if (gethost_netaddrs(fromhost, tohost,
2613 (char *)&fromnetaddr, (char *)&tonetaddr) < 0) {
2614 (void) fprintf(stderr, "\n");
2615 rdc_warn(NULL, gettext("unable to determine IP "
2616 "addresses for either host %s or host %s"),
2617 fromhost, tohost);
2618
2619 if (flag != RDC_CMD_DISABLE)
2620 exit(1);
2621 else
2622 host_not_found = 1;
2623 }
2624
2625 /*
2626 * Are we running on neither host?
2627 */
2628 if (!self_check(fromhost) && !self_check(tohost)) {
2629 if (flag == RDC_CMD_DISABLE) {
2630 (void) fprintf(stderr, "\n");
2631 rdc_warn(NULL, gettext("Not running on either host "
2632 "%s or host %s"), fromhost, tohost);
2633 host_not_found = 1;
2634 }
2635 }
2636
2637 /*
2638 * at this point, hopfully it is safe to say that
2639 * if a ctag was supplied via -C tag it is safe to
2640 * move it from ctag_arg to ctag. If it was passed in
2641 * at the end and the beginning of the cli, it must
2642 * match, as per checks above. if it was not passed
2643 * in at the end, but at the beginning, we can deal.
2644 * this should handle the case of shost:svol.
2645 * which is the main reason for this.
2646 *
2647 * there are 3 cases: passed in by cli, checked just above.
2648 * using libdscfg, you must pass in -C tag to have
2649 * ctag_check pass.
2650 * finally a file. same rules as libdscfg.
2651 */
2652 if ((strlen(ctag) == 0) && (strlen(ctag_arg) > 0))
2653 (void) strcpy(ctag, ctag_arg);
2654
2655 if (flag == RDC_CMD_RECONFIG) {
2656 if (reconfig_pbitmap) {
2657 (void) strncpy(frombitmap, reconfig_pbitmap,
2658 NSC_MAXPATH);
2659 check_rdcbitmap(flag, fromhost, frombitmap);
2660 }
2661 if (reconfig_sbitmap) {
2662 (void) strncpy(tobitmap, reconfig_sbitmap,
2663 NSC_MAXPATH);
2664 check_rdcbitmap(flag, tohost, tobitmap);
2665 }
2666 #ifdef _RDC_CAMPUS
2667 if (reconfig_direct)
2668 (void) strncpy(directfile, reconfig_direct,
2669 NSC_MAXPATH);
2670 #endif
2671 if (reconfig_group)
2672 (void) strncpy(group, reconfig_group,
2673 NSC_MAXPATH);
2674
2675 if (strlen(reconfig_ctag) > 0)
2676 (void) strncpy(ctag, reconfig_ctag,
2677 MAX_RDC_HOST_SIZE);
2678 if (reconfig_doasync != -1)
2679 doasync = reconfig_doasync;
2680 }
2681
2682 if (flag == RDC_CMD_ENABLE || flag == RDC_CMD_RECONFIG) {
2683 if (ctag_check(fromhost, fromfile, frombitmap,
2684 tohost, tofile, tobitmap, ctag, diskqueue) < 0)
2685 exit(1);
2686 if ((diskq_group = check_diskqueue(NULL, diskqueue,
2687 group)) == DISKQ_FAIL) {
2688 rdc_err(NULL, gettext("disk queue %s is "
2689 "incompatible with existing queue"),
2690 diskqueue);
2691 }
2692
2693 }
2694 pairs = 1;
2695 } else {
2696 pairs = read_config(flag, config_file, group_arg, ctag_arg);
2697 if (pairs == 0) {
2698 rdc_err(NULL, gettext("%s contains no "
2699 "matching Remote Mirror sets"), config_file);
2700 }
2701 }
2702
2703 if (!nflag && !pflag && prompt_user(flag, iflag) == -1)
2704 exit(1);
2705
2706 while (pairs--) {
2707
2708 if (cfgflag || fflag) {
2709 (void) strncpy(fromfile, pair_list[pairs].ffile,
2710 NSC_MAXPATH);
2711 (void) strncpy(tofile, pair_list[pairs].tfile,
2712 NSC_MAXPATH);
2713 (void) strncpy(frombitmap, pair_list[pairs].fbitmap,
2714 NSC_MAXPATH);
2715 (void) strncpy(fromhost,
2716 pair_list[pairs].fhost, MAX_RDC_HOST_SIZE);
2717 (void) strncpy(tohost, pair_list[pairs].thost,
2718 MAX_RDC_HOST_SIZE);
2719 (void) strncpy(tobitmap, pair_list[pairs].tbitmap,
2720 NSC_MAXPATH);
2721 (void) strncpy(directfile, pair_list[pairs].directfile,
2722 NSC_MAXPATH);
2723 (void) strncpy(group, pair_list[pairs].group,
2724 NSC_MAXPATH);
2725 (void) strncpy(ctag, pair_list[pairs].ctag,
2726 MAX_RDC_HOST_SIZE);
2727 (void) strncpy(diskqueue, pair_list[pairs].diskqueue,
2728 NSC_MAXPATH);
2729
2730 bcopy(pair_list[pairs].fnetaddr, fromnetaddr,
2731 RDC_MAXADDR);
2732 bcopy(pair_list[pairs].tnetaddr, tonetaddr,
2733 RDC_MAXADDR);
2734
2735 doasync = pair_list[pairs].doasync;
2736 }
2737
2738 if (pflag) {
2739 static int first = 1;
2740
2741 if (first) {
2742 if ((cfg = cfg_open(NULL)) == NULL)
2743 rdc_err(NULL,
2744 gettext("unable to access configuration"));
2745
2746 if (!cfg_lock(cfg, CFG_RDLOCK))
2747 rdc_err(NULL,
2748 gettext("unable to lock configuration"));
2749
2750 first = 0;
2751 }
2752
2753 (void) rdc_print(file_format, verbose,
2754 group_arg, ctag_arg, tohost, tofile, cfg);
2755
2756 if (pairs == 0) {
2757 cfg_close(cfg);
2758 exit(0);
2759 }
2760
2761 /* short circuit the rest of the command loop */
2762 continue;
2763 }
2764 if (Bflag) {
2765 int ret;
2766 ret = rdc_bitmapset(tohost, tofile, bitfile, oflag,
2767 boffset);
2768 exit(ret);
2769 }
2770 if ((fflag || cfgflag) && flag == RDC_CMD_RECONFIG) {
2771 char orig_fbmp[MAXHOSTNAMELEN];
2772 char orig_tbmp[MAXHOSTNAMELEN];
2773 int ret;
2774 rdc_config_t parms;
2775 spcs_s_info_t ustatus;
2776
2777 parms.command = RDC_CMD_STATUS;
2778 parms.rdc_set->netconfig = NULL;
2779 (void) strncpy(parms.rdc_set->primary.intf, fromhost,
2780 MAX_RDC_HOST_SIZE);
2781 (void) strncpy(parms.rdc_set->secondary.intf, tohost,
2782 MAX_RDC_HOST_SIZE);
2783 (void) strncpy(parms.rdc_set->primary.file, fromfile,
2784 NSC_MAXPATH);
2785 (void) strncpy(parms.rdc_set->secondary.file, tofile,
2786 NSC_MAXPATH);
2787 ustatus = spcs_s_ucreate();
2788 ret = RDC_IOCTL(RDC_CONFIG, &parms,
2789 NULL, 0, 0, 0, ustatus);
2790 if (ret != SPCS_S_OK) {
2791 rdc_err(NULL, gettext("unable to get set status"
2792 " before reconfig operation"));
2793 }
2794 (void) strncpy(orig_fbmp, parms.rdc_set->primary.bitmap,
2795 NSC_MAXPATH);
2796 (void) strncpy(orig_tbmp,
2797 parms.rdc_set->secondary.bitmap, NSC_MAXPATH);
2798
2799 if (strncmp(orig_fbmp, frombitmap, NSC_MAXPATH) != 0)
2800 check_rdcbitmap(flag, fromhost, frombitmap);
2801 if (strncmp(orig_tbmp, tobitmap, NSC_MAXPATH) != 0)
2802 check_rdcbitmap(flag, tohost, tobitmap);
2803 spcs_s_ufree(&ustatus);
2804
2805 }
2806 /*
2807 * take a peek in the config to see if
2808 * the bitmap is being used elsewhere
2809 */
2810 if (flag == RDC_CMD_ENABLE) {
2811 struct stat stb;
2812 /*
2813 * just for fun, lets see if some silly person
2814 * specified the same vol and bitmap
2815 */
2816 if ((strcmp(fromfile, frombitmap) == 0) ||
2817 (strcmp(tofile, tobitmap) == 0))
2818 rdc_err(NULL, gettext("volumes and bitmaps"
2819 " must not match"));
2820 if (self_check(fromhost)) {
2821 check_rdcbitmap(flag, fromhost, frombitmap);
2822 if (stat(fromfile, &stb) != 0) {
2823 rdc_err(NULL,
2824 gettext("unable to access %s: %s"),
2825 fromfile, strerror(errno));
2826 }
2827 if (!S_ISCHR(stb.st_mode)) {
2828 rdc_err(NULL,
2829 gettext("%s is not a character device"),
2830 fromfile);
2831 }
2832 } else { /* on the secondary */
2833 check_rdcbitmap(flag, tohost, tobitmap);
2834 /* extra check for secondary vol */
2835 check_rdcsecondary(tofile);
2836 if (stat(tofile, &stb) != 0) {
2837 rdc_err(NULL,
2838 gettext("unable to access %s: %s"),
2839 tofile, strerror(errno));
2840 }
2841 if (!S_ISCHR(stb.st_mode)) {
2842 rdc_err(NULL,
2843 gettext("%s is not a character device"),
2844 tofile);
2845 }
2846 }
2847
2848 }
2849
2850 if (flag == RDC_CMD_ENABLE || flag == RDC_CMD_DISABLE ||
2851 flag == RDC_CMD_RECONFIG) {
2852 if ((cfg = cfg_open(NULL)) == NULL)
2853 rdc_err(NULL,
2854 gettext("unable to access configuration"));
2855
2856 if (!cfg_lock(cfg, CFG_WRLOCK))
2857 rdc_err(NULL,
2858 gettext("unable to lock configuration"));
2859
2860 cfg_resource(cfg, clustered ? ctag : NULL);
2861 } else
2862 cfg = NULL;
2863
2864 if (cfg && perform_autosv() &&
2865 (flag == RDC_CMD_ENABLE || flag == RDC_CMD_DISABLE ||
2866 flag == RDC_CMD_RECONFIG)) {
2867 if (cfg_load_svols(cfg) < 0 ||
2868 cfg_load_dsvols(cfg) < 0 ||
2869 cfg_load_shadows(cfg) < 0)
2870 rdc_err(NULL,
2871 gettext("Unable to parse config filer"));
2872 load_rdc_vols(cfg);
2873 }
2874 cfg_success = (cfg == NULL);
2875 if (cfg && flag == RDC_CMD_ENABLE) {
2876 /* Enabled, so add the set via libcfg */
2877
2878 /* Build a new sndr entry and put it */
2879 group_p = *group? group : place_holder;
2880 diskqueue_p = *diskqueue? diskqueue : place_holder;
2881
2882 if ((diskqueue_p == place_holder) &&
2883 (group_p != place_holder)) {
2884 get_group_diskq(cfg, group_p, diskqueue);
2885 if (*diskqueue)
2886 diskqueue_p = diskqueue;
2887 }
2888
2889 /*
2890 * format in pconfig is:
2891 * phost.primary.pbitmap.shost.secondary.
2892 * sbitmap.type.mode.group.cnode.options.diskq
2893 */
2894 (void) snprintf(buf, sizeof (buf),
2895 "%s %s %s %s %s %s %s %s %s %s - %s",
2896 fromhost, fromfile, frombitmap, tohost, tofile,
2897 tobitmap, directfile,
2898 doasync? "async" : "sync", group_p,
2899 clustered? ctag : "-", diskqueue_p);
2900
2901 if (cfg_put_cstring(cfg, "sndr", buf, strlen(buf)) < 0)
2902 rdc_warn(NULL,
2903 gettext("unable to add \"%s\" to "
2904 "configuration storage: %s"),
2905 buf, cfg_error(&sev));
2906 setnumber = find_setnumber_in_libcfg(cfg, clustered?
2907 ctag : NULL, tohost, tofile);
2908 if (setnumber < 0)
2909 rdc_warn(NULL,
2910 gettext("unable to add \"%s\" to "
2911 "configuration storage: %s"),
2912 diskqueue_p, cfg_error(&sev));
2913
2914 else
2915 cfg_success = 1;
2916
2917 /* Add cluster aware info */
2918 if (clustered && !rdc_islocal) {
2919 (void) snprintf(key, sizeof (key),
2920 "sndr.set%d.options", setnumber);
2921 if (self_check(fromhost)) {
2922 if (cfg_put_options(cfg, CFG_SEC_CONF,
2923 key, "lghn", fromhost) < 0) {
2924 rdc_err(NULL,
2925 gettext("unable to add "
2926 "\"%s\" to configuration "
2927 "storage: %s"),
2928 fromhost, cfg_error(&sev));
2929 }
2930 } else if (self_check(tohost)) {
2931 if (cfg_put_options(cfg, CFG_SEC_CONF,
2932 key, "lghn", tohost) < 0) {
2933 rdc_err(NULL,
2934 gettext("unable to add "
2935 "\"%s\" to configuration "
2936 "storage: %s"),
2937 fromhost, cfg_error(&sev));
2938 }
2939 }
2940 }
2941 } else if (cfg && flag == RDC_CMD_DISABLE) {
2942 found = 0;
2943 /* Disabled, so delete the set via libcfg */
2944
2945 /* get sndr entries until shost, sfile match */
2946 for (i = 0; i < rdc_maxsets; i++) {
2947 setnumber = i + 1;
2948 (void) snprintf(key, sizeof (key), "sndr.set%d",
2949 setnumber);
2950 if (cfg_get_cstring(cfg, key, buf,
2951 CFG_MAX_BUF) < 0) {
2952 break;
2953 }
2954 (void) snprintf(key, sizeof (key),
2955 "sndr.set%d.secondary", setnumber);
2956 if (cfg_get_cstring(cfg, key, buf,
2957 CFG_MAX_BUF) < 0)
2958 break;
2959 if (strcmp(buf, tofile) != 0)
2960 continue;
2961 (void) snprintf(key, sizeof (key),
2962 "sndr.set%d.shost",
2963 setnumber);
2964 if (cfg_get_cstring(cfg, key, buf,
2965 CFG_MAX_BUF) < 0)
2966 break;
2967 if (strcmp(buf, tohost) != 0)
2968 continue;
2969 found = 1;
2970 #ifdef DEBUG
2971 if (checksetfields == -1) {
2972 rdc_err(NULL,
2973 gettext("checksetfields not set"));
2974 }
2975 #endif
2976 if (checksetfields) {
2977 checkgfields(cfg, setnumber, fromhost,
2978 fromfile, frombitmap, tobitmap,
2979 directfile, (doasync == 1)
2980 ? "async" : "sync", group, ctag,
2981 diskqueue);
2982 }
2983
2984 /* perform cluster specific options */
2985 if (clustered) {
2986 /* get the logical host, if set */
2987 (void) snprintf(key, sizeof (key),
2988 "sndr.set%d.options", setnumber);
2989 (void) cfg_get_single_option(cfg,
2990 CFG_SEC_CONF, key, "lghn",
2991 lhname, MAX_RDC_HOST_SIZE);
2992
2993 /* figure out the cluster tag, if any */
2994 (void) snprintf(key, sizeof (key),
2995 "sndr.set%d.cnode", setnumber);
2996 if (cfg_get_cstring(cfg, key, buf,
2997 CFG_MAX_BUF) < 0)
2998 break;
2999 if (strcmp(buf, ctag))
3000 rdc_err(NULL, gettext("ctags %s"
3001 " and %s do not match"),
3002 buf, ctag);
3003 } else {
3004 *lhname = '\0';
3005 *ctag = '\0';
3006 }
3007
3008 /* figure out the disk queue, if any */
3009 (void) snprintf(key, sizeof (key),
3010 "sndr.set%d.diskq",
3011 setnumber);
3012 if (cfg_get_cstring(cfg, key, buf,
3013 CFG_MAX_BUF) < 0)
3014 break;
3015 if (strlen(buf) > 0) {
3016 (void) strncpy(diskqueue, buf,
3017 NSC_MAXPATH);
3018 } else {
3019 *diskqueue = '\0';
3020 }
3021 (void) snprintf(key, sizeof (key), "sndr.set%d",
3022 setnumber);
3023 if (cfg_put_cstring(cfg, key, NULL, 0) < 0)
3024 rdc_warn(NULL,
3025 gettext("unable to remove \"%s\" "
3026 "from configuration storage: %s"),
3027 buf, cfg_error(&sev));
3028 else
3029 cfg_success = 1;
3030 break;
3031 }
3032 if (found == 0) {
3033 rdc_err(NULL,
3034 gettext("Unable to find %s:%s in "
3035 "configuration storage"),
3036 tohost, tofile);
3037 }
3038 if (host_not_found) {
3039 rdc_force_disable(cfg, fromhost, fromfile,
3040 frombitmap, tohost, tofile, tobitmap, ctag,
3041 lhname);
3042 if (cfg_commit(cfg) < 0)
3043 rdc_err(NULL, gettext("commit on "
3044 "force disable failed"));
3045 cfg_close(cfg);
3046 return (0);
3047 }
3048 } else if (cfg && flag == RDC_CMD_RECONFIG) {
3049 /* Update relevant cfg record */
3050
3051 cfg_resource(cfg, NULL);
3052
3053 /* get sndr entries until shost, sfile match */
3054 for (i = 0; i < rdc_maxsets; i++) {
3055 setnumber = i + 1;
3056 (void) snprintf(key, sizeof (key), "sndr.set%d",
3057 setnumber);
3058 if (cfg_get_cstring(cfg, key, buf,
3059 CFG_MAX_BUF) < 0) {
3060 break;
3061 }
3062 (void) snprintf(key, sizeof (key),
3063 "sndr.set%d.secondary", setnumber);
3064 if (cfg_get_cstring(cfg, key, buf,
3065 CFG_MAX_BUF) < 0)
3066 break;
3067 if (strcmp(buf, tofile) != 0)
3068 continue;
3069 (void) snprintf(key, sizeof (key),
3070 "sndr.set%d.shost",
3071 setnumber);
3072 if (cfg_get_cstring(cfg, key, buf,
3073 CFG_MAX_BUF) < 0)
3074 break;
3075 if (strcmp(buf, tohost) != 0)
3076 continue;
3077 (void) snprintf(key, sizeof (key),
3078 "sndr.set%d.cnode",
3079 setnumber);
3080 if (cfg_get_cstring(cfg, key, buf,
3081 CFG_MAX_BUF) < 0)
3082 break;
3083 if (reconfig_ctag[0] == '\0')
3084 (void) strncpy(ctag, buf,
3085 sizeof (ctag));
3086 if (doasync)
3087 (void) strcpy(mode, "async");
3088 else
3089 (void) strcpy(mode, "sync");
3090 if (strcmp(directfile, "") == 0)
3091 (void) strcpy(directfile, "ip");
3092
3093 group_p = strlen(group) > 0 ? group :
3094 place_holder;
3095
3096 /*
3097 * if we are reconfigging out altogether,
3098 * get rid of the diskqueue
3099 */
3100 if (group_p == place_holder)
3101 diskqueue_p = place_holder;
3102 else
3103 diskqueue_p = strlen(diskqueue) > 0 ?
3104 diskqueue : place_holder;
3105
3106 /*
3107 * do a little diskq dance here for reconfigs
3108 * that did not specify the diskqueue whilst
3109 * reconfigging ...
3110 */
3111 if ((diskqueue_p == place_holder) &&
3112 (group_p != place_holder)) {
3113 get_group_diskq(cfg, group_p,
3114 diskqueue);
3115 diskqueue_p = strlen(diskqueue) > 0 ?
3116 diskqueue : place_holder;
3117 }
3118
3119 (void) snprintf(key, sizeof (key),
3120 "sndr.set%d.options", setnumber);
3121 if (cfg_get_cstring(cfg, key, options_cfg,
3122 CFG_MAX_BUF) < 0) {
3123 break;
3124 }
3125
3126 ctag_p = strlen(ctag) > 0 ?
3127 ctag : place_holder;
3128 (void) snprintf(buf, sizeof (buf),
3129 "%s %s %s %s %s %s %s %s %s %s %s %s",
3130 fromhost, fromfile, frombitmap,
3131 tohost, tofile, tobitmap,
3132 directfile, mode, group_p,
3133 ctag_p, options_cfg, diskqueue_p);
3134
3135 (void) snprintf(key, sizeof (key), "sndr.set%d",
3136 setnumber);
3137 if (cfg_put_cstring(cfg, key, buf,
3138 strlen(buf)) < 0)
3139 rdc_warn(NULL,
3140 gettext("unable to update \"%s\" "
3141 "in configuration storage: %s"),
3142 buf, cfg_error(&sev));
3143 else
3144 cfg_success = 1;
3145 break;
3146 }
3147 }
3148
3149 if (cfg_success) {
3150 if (cfg && perform_autosv()) {
3151 if (self_check(fromhost)) {
3152 if (diskqueue[0] &&
3153 (strcmp(diskqueue, fromfile) == 0) ||
3154 (strcmp(diskqueue, frombitmap) == 0)) {
3155 rdc_err(NULL, gettext("disk "
3156 "queue volume %s must not "
3157 "match any primary Remote "
3158 "Mirror volume or bitmap"),
3159 diskqueue);
3160 }
3161
3162 if (diskqueue[0]) {
3163 different_devs(fromfile, diskqueue);
3164 different_devs(frombitmap, diskqueue);
3165 validate_name(cfg, diskqueue);
3166 }
3167 different_devs(fromfile, frombitmap);
3168 validate_name(cfg, fromfile);
3169 validate_name(cfg, frombitmap);
3170 } else {
3171 different_devs(tofile, tobitmap);
3172 validate_name(cfg, tofile);
3173 validate_name(cfg, tobitmap);
3174 }
3175 }
3176 /*
3177 * okay, if the command is sync, just build
3178 * a list of rdcconfig_t's after the pairs--
3179 * loop is done, we will pass this list to
3180 * librdc to multithread the syncs (after
3181 * forking off a daemonish type process
3182 * that waits for the libcall to complete
3183 * ints of interest:
3184 * flag ie RDC_CMD_COPY, iflag RDC_OPT_UPDATE,
3185 * reverse RDC_OPT_REVERSE, RDC_OPT_FORWARD
3186 * if necessary, turn autosync back on
3187 */
3188 if (flag == RDC_CMD_COPY) {
3189 if (autosync_is_on(tohost, tofile) ==
3190 AUTOSYNC_ON)
3191 enable_autosync(fromhost, fromfile,
3192 tohost, tofile);
3193
3194 if (sets == NULL) {
3195 sets_p = sets =
3196 rdc_alloc_config(fromhost, fromfile,
3197 frombitmap, tohost, tofile,
3198 tobitmap, "mode", "group", "ctag",
3199 "options", 0);
3200
3201 if (sets_p == NULL) {
3202 rdc_err(NULL,
3203 gettext("rdc config alloc"
3204 "failed %s"), rdc_error(NULL));
3205 }
3206 continue;
3207 }
3208
3209 sets_p = sets_p->next =
3210 rdc_alloc_config(fromhost, fromfile,
3211 frombitmap, tohost, tofile, tobitmap,
3212 "mode", "group", "ctag", "options", 0);
3213
3214 if (sets_p == NULL) {
3215 rdc_err(NULL, gettext("rdc config alloc"
3216 "failed %s"), rdc_error(NULL));
3217 }
3218 continue;
3219 }
3220
3221 /*
3222 * block incoming signals until after the possible
3223 * cfg_commit is done
3224 */
3225 block_sigs();
3226 if (rdc_operation(cfg, fromhost, fromfile, frombitmap,
3227 tohost, tofile, tobitmap, flag, iflag, directfile,
3228 group, ctag, diskqueue, &doasync, reverse) < 0) {
3229 ;
3230 /*EMPTY*/
3231 } else if (cfg) {
3232 if (diskq_group == DISKQ_REWRITEG) {
3233 rewrite_group_diskqueue(cfg,
3234 &pair_list[pairs], diskqueue);
3235 }
3236 if (perform_autosv() &&
3237 (flag == RDC_CMD_ENABLE ||
3238 flag == RDC_CMD_DISABLE ||
3239 flag == RDC_CMD_RECONFIG)) {
3240 unload_rdc_vols();
3241 cfg_unload_shadows();
3242 cfg_unload_dsvols();
3243 cfg_unload_svols();
3244 }
3245 if ((iflag & RDC_OPT_REVERSE_ROLE) != 0 &&
3246 allow_role) {
3247 bzero(tmphost, MAX_RDC_HOST_SIZE);
3248 bzero(tmpfile, NSC_MAXPATH);
3249 bzero(tmpbitmap, NSC_MAXPATH);
3250 (void) strncpy(tmphost, fromhost,
3251 MAX_RDC_HOST_SIZE);
3252 (void) strncpy(tmpfile, fromfile,
3253 NSC_MAXPATH);
3254 (void) strncpy(tmpbitmap, frombitmap,
3255 NSC_MAXPATH);
3256
3257 (void) strncpy(fromhost, tohost,
3258 MAX_RDC_HOST_SIZE);
3259 (void) strncpy(fromfile, tofile,
3260 NSC_MAXPATH);
3261 (void) strncpy(frombitmap, tobitmap,
3262 NSC_MAXPATH);
3263
3264 (void) strncpy(tohost, tmphost,
3265 MAX_RDC_HOST_SIZE);
3266 (void) strncpy(tofile, tmpfile,
3267 NSC_MAXPATH);
3268 (void) strncpy(tobitmap, tmpbitmap,
3269 NSC_MAXPATH);
3270 group_p = strlen(group) > 0 ? group :
3271 place_holder;
3272 diskqueue_p = strlen(diskqueue) > 0 ?
3273 diskqueue : place_holder;
3274 ctag_p = strlen(ctag) > 0 ?
3275 ctag : place_holder;
3276 (void) snprintf(buf, sizeof (buf), "%s "
3277 "%s %s %s %s %s %s %s %s %s %s %s",
3278 fromhost, fromfile, frombitmap,
3279 tohost, tofile, tobitmap,
3280 directfile, mode, group_p,
3281 ctag_p, options_cfg, diskqueue_p);
3282
3283 (void) snprintf(key, sizeof (key),
3284 "sndr.set%d", setnumber);
3285 if (cfg_put_cstring(cfg, key, buf,
3286 strlen(buf)) < 0)
3287 rdc_err(NULL,
3288 gettext("unable to update \"%s\" "
3289 "in configuration storage: %s"),
3290 buf, cfg_error(&sev));
3291 }
3292 if (cfg_commit(cfg) < 0) {
3293 rdc_err(NULL, gettext("commit on role "
3294 "reversal failed"));
3295 }
3296 }
3297 unblock_sigs();
3298 }
3299
3300 if (cfg) {
3301 cfg_close(cfg);
3302 }
3303
3304 }
3305 if (flag == RDC_CMD_COPY) {
3306 pid = fork();
3307 if (pid == -1) { /* error forking */
3308 perror("fork");
3309 exit(1);
3310 }
3311 } else {
3312 exit(0);
3313 }
3314 if (pid > 0) /* parent process */
3315 exit(0);
3316
3317 spcslog_sync(sets, 1, iflag);
3318 if (iflag & RDC_OPT_REVERSE) {
3319 if (iflag & RDC_OPT_UPDATE)
3320 rclist = rdc_ursync(sets);
3321 else
3322 rclist = rdc_rsync(sets);
3323 } else if (iflag & RDC_OPT_UPDATE) {
3324 rclist = rdc_usync(sets);
3325 } else
3326 rclist = rdc_fsync(sets);
3327
3328 rcp = rclist;
3329 while (rcp) {
3330 if (rcp->rc < 0) {
3331 /* rclist->msg has already been gettext'd */
3332 (void) fprintf(stderr,
3333 gettext("Remote Mirror: %s %s %s %s %s %s\n"),
3334 rcp->set.phost, rcp->set.pfile, rcp->set.pbmp,
3335 rcp->set.shost, rcp->set.sfile, rcp->set.sbmp);
3336 rdc_warn(NULL, "%s", rcp->msg);
3337 spcs_log("sndr", NULL, "%s", rcp->msg);
3338 }
3339 rcp = rcp->next;
3340 }
3341
3342 spcslog_sync(sets, 0, iflag);
3343
3344 if (sets)
3345 rdc_free_config(sets, RDC_FREEALL);
3346 if (rclist)
3347 rdc_free_rclist(rclist);
3348
3349 return (0);
3350 }
3351 /*
3352 * process_clocal()
3353 * pre: a non null string
3354 * post: if the string is "local"
3355 * then it is converted to "-"
3356 * and rdc_islocal is set to 1
3357 * if not rdc_islocal set to 0
3358 */
3359 void
3360 process_clocal(char *ctag)
3361 {
3362 /*
3363 * Check for the special cluster tag and convert into the
3364 * internal representation.
3365 */
3366
3367 if (ctag != NULL && strcmp(ctag, RDC_LOCAL_TAG) == 0) {
3368 (void) strcpy(ctag, "-");
3369 rdc_islocal = 1;
3370 } else {
3371 rdc_islocal = 0;
3372 }
3373 }
3374
3375 static void
3376 rdc_check_dgislocal(char *dgname)
3377 {
3378 char *othernode;
3379 int rc;
3380
3381 /*
3382 * check where this disk service is mastered
3383 */
3384
3385 rc = cfg_dgname_islocal(dgname, &othernode);
3386 if (rc < 0) {
3387 rdc_err(NULL, gettext("unable to find "
3388 "disk service, %s: %s"), dgname, strerror(errno));
3389 }
3390
3391 if (rc == 0) {
3392 rdc_err(NULL, gettext("disk service, %s, is "
3393 "active on node \"%s\"\nPlease re-issue "
3394 "the command on that node"), dgname, othernode);
3395 }
3396 }
3397
3398 static void
3399 different_devs(char *dev1, char *dev2)
3400 {
3401 struct stat buf1, buf2;
3402
3403 if (stat(dev1, &buf1) < 0) {
3404 spcs_log("sndr", NULL, gettext("Remote Mirror: can't stat %s"),
3405 dev1);
3406 rdc_err(NULL, gettext("Remote Mirror: can't stat %s"), dev1);
3407 }
3408 if (stat(dev2, &buf2) < 0) {
3409 spcs_log("sndr", NULL, gettext("Remote Mirror: can't stat %s"),
3410 dev2);
3411 rdc_err(NULL, gettext("Remote Mirror: can't stat %s"), dev2);
3412 }
3413 if (buf1.st_rdev == buf2.st_rdev) {
3414 spcs_log("sndr", NULL, gettext("Remote Mirror: '%s' and '%s' "
3415 "refer to the same device"), dev1, dev2);
3416 rdc_err(NULL, gettext("Remote Mirror: '%s' and '%s' refer to "
3417 "the same device"), dev1, dev2);
3418 }
3419 }
3420
3421 static void
3422 validate_name(CFGFILE *cfg, char *vol)
3423 {
3424 char *altname;
3425 int rc;
3426
3427 if (!cfg) {
3428 rdc_err(NULL, gettext("Remote Mirror: null cfg ptr in "
3429 "validate_name"));
3430 }
3431
3432 rc = cfg_get_canonical_name(cfg, vol, &altname);
3433 if (rc < 0) {
3434 spcs_log("sndr", NULL, gettext("Remote Mirror: unable to parse "
3435 "config file\n"));
3436 rdc_err(NULL, gettext("Remote Mirror: unable to parse config "
3437 "file\n"));
3438 }
3439 if (rc) {
3440 spcs_log("sndr", NULL, gettext("Remote Mirror: '%s': already "
3441 "configured as '%s'"), vol, altname);
3442 rdc_err(NULL, gettext("Remote Mirror: The volume '%s' has been "
3443 "configured previously as '%s'. Re-enter command with "
3444 "the latter name."), vol, altname);
3445 }
3446 }
3447
3448 /*
3449 * Add the autosync value to the option field for the sndr set specified by
3450 * tohost:tofile.
3451 *
3452 * ASSUMPTIONS:
3453 * - cfg file is available to take a write lock.
3454 * - set is already configured in dscfg
3455 *
3456 * INPUTS:
3457 * autosync_val - value to set autosync to
3458 * tohost - secondary host
3459 * tofile - secondary volume
3460 *
3461 * OUTPUTS:
3462 * none.
3463 *
3464 */
3465 static void
3466 set_autosync(int autosync_val, char *tohost, char *tofile, char *ctag)
3467 {
3468 CFGFILE *cfg;
3469 char key[CFG_MAX_KEY], buf[CFG_MAX_BUF];
3470 char tag[CFG_MAX_BUF], val[CFG_MAX_BUF];
3471 char auto_tag[CFG_MAX_BUF];
3472 _sd_dual_pair_t pair;
3473 _sd_dual_pair_t tmpair;
3474 int setnumber, options = 0, already_set = 0, cfg_success = 0;
3475 int set;
3476
3477 /* verify valid autosync request */
3478 if ((autosync_val != AUTOSYNC_ON) && (autosync_val != AUTOSYNC_OFF)) {
3479 #ifdef DEBUG
3480 rdc_warn(NULL,
3481 gettext("set_autosync called with improper value"));
3482 #endif
3483 return;
3484 }
3485
3486 if ((cfg = cfg_open(NULL)) == NULL) {
3487 rdc_err(NULL, gettext("unable to access configuration"));
3488 }
3489 if (!cfg_lock(cfg, CFG_WRLOCK)) {
3490 rdc_err(NULL, gettext("unable to lock configuration"));
3491 }
3492
3493 if (clustered) {
3494 cfg_resource(cfg, ctag);
3495 } else {
3496 cfg_resource(cfg, NULL);
3497 }
3498
3499 /* find set number in config */
3500 if ((setnumber = find_setnumber_in_libcfg(cfg, clustered? ctag : NULL,
3501 tohost, tofile)) < 0) {
3502 cfg_close(cfg);
3503 rdc_err(NULL, gettext("unable to find Remote Mirror set %s:%s: "
3504 "in config"), tohost, tofile);
3505 }
3506 (void) snprintf(key, sizeof (key), "sndr.set%d.options", setnumber);
3507 (void) snprintf(auto_tag, sizeof (auto_tag), "auto");
3508
3509 /* Check if there are any options already set, including ours */
3510 if (cfg_get_options(cfg, CFG_SEC_CONF, key, tag, CFG_MAX_BUF, val,
3511 CFG_MAX_BUF) >= 0) {
3512 options = 1;
3513
3514 do {
3515 if (strcmp(tag, auto_tag) == 0) {
3516 already_set = 1;
3517 }
3518 } while (cfg_get_options(cfg, CFG_SEC_CONF, NULL, tag,
3519 CFG_MAX_BUF, val, CFG_MAX_BUF) >= 0);
3520 }
3521
3522 /* options already exist, edit ours out */
3523 if (options && already_set) {
3524 char *p, *q;
3525 int need_to_clear_buf = 1;
3526
3527 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
3528 rdc_err(NULL, gettext("unable to get options field "
3529 "for Remote Mirror set %s:%s"), tohost, tofile);
3530 }
3531
3532 /* parse out our options, all of the form "auto=" */
3533 p = strdup(buf);
3534 bzero(buf, sizeof (buf));
3535
3536 q = strtok(p, ";");
3537 do {
3538 /* if another tag/value exists, keep it */
3539 if (strncmp(auto_tag, q, 4) != 0) {
3540 (void) strcat(buf, q);
3541 (void) strcat(buf, ";");
3542 need_to_clear_buf = 0;
3543 }
3544 } while (q = strtok(NULL, ";"));
3545 free(p);
3546
3547 /* if we were the only option, clear the field */
3548 if (need_to_clear_buf) {
3549 (void) strcat(buf, "-");
3550 }
3551
3552 if (cfg_put_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
3553 rdc_err(NULL, gettext("unable to clear autosync value "
3554 "in config for Remote Mirror set %s:%s"), tohost,
3555 tofile);
3556 } else {
3557 cfg_success = 1;
3558 }
3559 }
3560
3561 /* autosync is not present in options field, add if on is requested */
3562 if (autosync_val == AUTOSYNC_ON) {
3563 if (cfg_put_options(cfg, CFG_SEC_CONF, key, auto_tag, "on")
3564 < 0) {
3565 rdc_err(NULL, gettext("unable to update autosync value "
3566 "in config for Remote Mirror set %s:%s"), tohost,
3567 tofile);
3568 } else {
3569 cfg_success = 1;
3570 }
3571 }
3572 /* if we are in a group, update any other sets in the same group */
3573 do {
3574 bzero(&pair, sizeof (pair));
3575 bzero(buf, CFG_MAX_BUF);
3576
3577 (void) snprintf(key, sizeof (key), "sndr.set%d", setnumber);
3578 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
3579 break;
3580 }
3581 if (parse_cfg_buf(buf, &pair, NULL))
3582 break;
3583 if (pair.group == NULL) /* not in a group */
3584 break;
3585 if (!pair.group[0])
3586 break; /* not in a group */
3587 for (set = 1; /*CSTYLED*/; set++) {
3588 if (set == setnumber)
3589 continue;
3590 bzero(buf, CFG_MAX_BUF);
3591 options = 0;
3592 already_set = 0;
3593
3594 (void) snprintf(key, sizeof (key), "sndr.set%d", set);
3595 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
3596 break; /* last set processed */
3597 }
3598 bzero(&tmpair, sizeof (tmpair));
3599 if (parse_cfg_buf(buf, &tmpair, NULL))
3600 break;
3601 if (strcmp(pair.group, tmpair.group) != 0)
3602 continue; /* not the group we want */
3603
3604 (void) snprintf(key, sizeof (key), "sndr.set%d.options",
3605 set);
3606 /*
3607 * Check if there are any options already set,
3608 * including ours
3609 */
3610 if (cfg_get_options(cfg, CFG_SEC_CONF, key, tag,
3611 CFG_MAX_BUF, val, CFG_MAX_BUF) >= 0) {
3612 options = 1;
3613
3614 do {
3615 if (strcmp(tag, auto_tag) == 0) {
3616 already_set = 1;
3617 }
3618 } while (cfg_get_options(cfg, CFG_SEC_CONF,
3619 NULL, tag, CFG_MAX_BUF, val,
3620 CFG_MAX_BUF) >= 0);
3621 }
3622
3623 /* options already exist, edit ours out */
3624 if (options && already_set) {
3625 char *p, *q;
3626 int need_to_clear_buf = 1;
3627
3628 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF)
3629 < 0) {
3630 rdc_err(NULL, gettext("unable to get "
3631 "options field for Remote Mirror set "
3632 "%s:%s"), tmpair.thost, tmpair.tfile);
3633 }
3634
3635 /*
3636 * parse out our options, all of the
3637 * form "auto="
3638 */
3639 p = strdup(buf);
3640 bzero(buf, sizeof (buf));
3641
3642 q = strtok(p, ";");
3643 do {
3644 /*
3645 * if another tag/value exists,
3646 * keep it
3647 */
3648 if (strncmp(auto_tag, q, 4) != 0) {
3649 (void) strcat(buf, q);
3650 (void) strcat(buf, ";");
3651 need_to_clear_buf = 0;
3652 }
3653 } while (q = strtok(NULL, ";"));
3654 free(p);
3655
3656 /*
3657 * if we were the only option,
3658 * clear the field
3659 */
3660 if (need_to_clear_buf) {
3661 (void) strcat(buf, "-");
3662 }
3663
3664 if (cfg_put_cstring(cfg, key, buf, CFG_MAX_BUF)
3665 < 0) {
3666 rdc_err(NULL, gettext("unable to clear "
3667 "autosync value in config for "
3668 "Remote Mirror set %s:%s"),
3669 tmpair.thost, tmpair.tfile);
3670 cfg_success = 0;
3671 }
3672 }
3673
3674 /*
3675 * autosync is not present in options field,
3676 * add if on is requested
3677 */
3678 if (autosync_val == AUTOSYNC_ON) {
3679 if (cfg_put_options(cfg, CFG_SEC_CONF, key,
3680 auto_tag, "on") < 0) {
3681 rdc_err(NULL, gettext("unable to update"
3682 " autosync value in config for "
3683 "Remote Mirror set %s:%s"),
3684 tmpair.thost,
3685 tmpair.tfile);
3686 cfg_success = 0;
3687 }
3688 }
3689 }
3690
3691 /* CONSTCOND */
3692 } while (0);
3693 if (cfg_success) {
3694 if (cfg_commit(cfg) < 0) {
3695 rdc_err(NULL, gettext("commit on role reversal failed"));
3696 }
3697 }
3698
3699 cfg_close(cfg);
3700 }
3701
3702 /*
3703 * Check to see if autosync is on for set specified by tohost:tofile.
3704 *
3705 * ASSUMPTIONS:
3706 * config is available to take a read lock against it.
3707 *
3708 * INPUTS:
3709 * tohost - secondary host
3710 * tofile - secondary volume
3711 *
3712 * OUTPUTS:
3713 * -1 error
3714 * AUTOSYNC_ON if autosync is on
3715 * AUTOSYNC_OFF if autosync is off
3716 */
3717 static int
3718 autosync_is_on(char *tohost, char *tofile)
3719 {
3720 CFGFILE *cfg;
3721 int setnumber, autosync_val = AUTOSYNC_OFF;
3722 char key[CFG_MAX_KEY];
3723 char tag[CFG_MAX_BUF], val[CFG_MAX_BUF];
3724
3725 if ((cfg = cfg_open(NULL)) == NULL) {
3726 rdc_err(NULL, gettext("unable to access configuration"));
3727 }
3728
3729 if (!cfg_lock(cfg, CFG_RDLOCK)) {
3730 cfg_close(cfg);
3731 rdc_err(NULL, gettext("unable to lock configuration"));
3732 }
3733
3734 if ((setnumber = find_setnumber_in_libcfg(cfg, NULL, tohost, tofile)) <
3735 0) {
3736 cfg_close(cfg);
3737 rdc_err(NULL, gettext("cannot find Remote Mirror set %s:%s in "
3738 "config"), tohost, tofile);
3739 }
3740
3741 (void) snprintf(key, CFG_MAX_KEY, "sndr.set%d.options", setnumber);
3742 if (cfg_get_options(cfg, CFG_SEC_CONF, key, tag, CFG_MAX_BUF, val,
3743 CFG_MAX_BUF) >= 0) {
3744 do {
3745 if (strcmp(tag, "auto") == 0) {
3746 if (strcmp(val, "on") == 0) {
3747 autosync_val = AUTOSYNC_ON;
3748 }
3749 break;
3750 }
3751 } while (cfg_get_options(cfg, CFG_SEC_CONF, NULL, tag,
3752 CFG_MAX_BUF, val, CFG_MAX_BUF) >= 0);
3753 }
3754
3755 cfg_close(cfg);
3756 return (autosync_val);
3757 }
3758
3759 void
3760 enable_autosync(char *fhost, char *ffile, char *thost, char *tfile)
3761 {
3762 rdc_config_t parms;
3763 spcs_s_info_t ustat;
3764 rdc_addr_t *p;
3765
3766 ustat = spcs_s_ucreate();
3767 parms.command = RDC_CMD_TUNABLE;
3768
3769 p = &parms.rdc_set[0].primary;
3770 (void) strncpy(p->intf, fhost, MAX_RDC_HOST_SIZE);
3771 (void) strncpy(p->file, ffile, MAX_RDC_HOST_SIZE);
3772
3773 p = &parms.rdc_set[0].secondary;
3774 (void) strncpy(p->intf, thost, NSC_MAXPATH);
3775 (void) strncpy(p->file, tfile, NSC_MAXPATH);
3776
3777 parms.rdc_set[0].autosync = 1;
3778 parms.rdc_set[0].maxqfbas = -1;
3779 parms.rdc_set[0].maxqitems = -1;
3780 parms.rdc_set[0].asyncthr = -1;
3781 parms.rdc_set[0].netconfig = NULL;
3782
3783 if ((RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustat)) !=
3784 SPCS_S_OK) {
3785 rdc_warn(&ustat, gettext("failed to update autosync for"
3786 " Remote Mirror set %s:%s"), thost, tfile);
3787 spcs_log("sndr", &ustat, gettext("failed to update autosync for"
3788 " Remote Mirror set %s:%s"), thost, tfile);
3789 }
3790 spcs_s_ufree(&ustat);
3791 }
3792
3793 static int
3794 rdc_operation(CFGFILE *cfg, char *fromhost, char *fromfile, char *frombitmap,
3795 char *tohost, char *tofile, char *tobitmap,
3796 int flag, int iflag,
3797 char *directfile, char *group, char *ctag, char *diskqueue,
3798 int *doasync, int reverse)
3799 {
3800 const int getaddr = (flag == RDC_CMD_ENABLE);
3801 const int rpcbind = !getaddr;
3802 rdc_config_t parms;
3803 int ret;
3804 spcs_s_info_t ustatus;
3805 struct hostent *hp;
3806 char fromname[MAXHOSTNAMELEN], toname[MAXHOSTNAMELEN];
3807 char orig_fbmp[MAXHOSTNAMELEN], orig_tbmp[MAXHOSTNAMELEN];
3808 char orig_diskq[NSC_MAXPATH];
3809 struct t_info tinfo;
3810 int success = 1;
3811 int autosync_toggle_needed = 0;
3812 char *vol1, *vol2, *vol3;
3813
3814 conf = &nconf;
3815
3816 hp = gethost_byname(fromhost);
3817 (void) strncpy(fromname, hp->h_name, MAXHOSTNAMELEN);
3818 hp = gethost_byname(tohost);
3819 (void) strncpy(toname, hp->h_name, MAXHOSTNAMELEN);
3820
3821 if (self_check(fromname) && self_check(toname)) {
3822 rdc_err(NULL, gettext("both %s and %s are local"),
3823 fromhost, tohost);
3824 }
3825
3826 /* we have to find out what to sv disable after reconfig */
3827 if (flag == RDC_CMD_RECONFIG) {
3828
3829 parms.command = RDC_CMD_STATUS;
3830 parms.rdc_set->netconfig = NULL;
3831 (void) strncpy(parms.rdc_set->primary.intf, fromhost,
3832 MAX_RDC_HOST_SIZE);
3833 (void) strncpy(parms.rdc_set->secondary.intf, tohost,
3834 MAX_RDC_HOST_SIZE);
3835 (void) strncpy(parms.rdc_set->primary.file, fromfile,
3836 NSC_MAXPATH);
3837 (void) strncpy(parms.rdc_set->secondary.file, tofile,
3838 NSC_MAXPATH);
3839 ustatus = spcs_s_ucreate();
3840 ret = RDC_IOCTL(RDC_CONFIG, &parms,
3841 NULL, 0, 0, 0, ustatus);
3842 if (ret != SPCS_S_OK) {
3843 rdc_err(NULL, gettext("unable to get set status"
3844 " before reconfig operation"));
3845 }
3846 (void) strncpy(orig_fbmp, parms.rdc_set->primary.bitmap,
3847 NSC_MAXPATH);
3848 (void) strncpy(orig_tbmp, parms.rdc_set->secondary.bitmap,
3849 NSC_MAXPATH);
3850 (void) strncpy(orig_diskq, parms.rdc_set->disk_queue,
3851 NSC_MAXPATH);
3852 }
3853
3854 /*
3855 * another terrible addition, if we are reconfigging mode
3856 * and not logging, just give up.
3857 */
3858 if ((reconfig_doasync != -1) &&
3859 (!(parms.rdc_set->flags & RDC_LOGGING))) {
3860 rdc_err(NULL, gettext("cannot reconfigure sync/async, "
3861 "Remote Mirror set not logging"));
3862 spcs_log("sndr", NULL, gettext("cannot reconfigure sync/async, "
3863 "Remote Mirror set not logging"));
3864 }
3865
3866 /*
3867 * Now build up the address for each host including port and transport
3868 */
3869 if (getaddr) {
3870 svp = get_addr(toname, RDC_PROGRAM, RDC_VERS_MIN,
3871 &conf, proto_test ? NC_UDP:NULL, "rdc", &tinfo,
3872 rpcbind);
3873
3874 if (svp == NULL) {
3875 rdc_warn(NULL, gettext("unable to determine network "
3876 "information for %s"), toname);
3877 #ifdef DEBUG
3878 (void) printf("get_addr failed for Ver 4 %s\n", toname);
3879 #endif
3880 return (-1);
3881 }
3882 svaddr = *svp;
3883 } else {
3884 bzero(&svaddr, sizeof (svaddr));
3885 }
3886
3887 parms.rdc_set->secondary.addr.len = svaddr.len;
3888 parms.rdc_set->secondary.addr.maxlen =
3889 svaddr.maxlen;
3890 parms.rdc_set->secondary.addr.buf =
3891 (void *)svaddr.buf;
3892
3893 #ifdef DEBUG_ADDR
3894 (void) fprintf(stderr, "secondary buf %x len %d\n",
3895 svaddr.buf, svaddr.len);
3896
3897 for (i = 0; i < svaddr.len; i++)
3898 (void) printf("%u ", svaddr.buf[i]);
3899 (void) printf("\n");
3900 #endif
3901
3902 if (getaddr) {
3903 svp = get_addr(fromname, RDC_PROGRAM, RDC_VERS_MIN,
3904 &conf, proto_test ? NC_UDP: NULL, "rdc", &tinfo,
3905 rpcbind);
3906 if (svp == NULL) {
3907 #ifdef DEBUG
3908 (void) printf("get_addr failed for Ver 4 %s\n",
3909 fromname);
3910 #endif
3911 return (-1);
3912 }
3913 svaddr = *svp;
3914 }
3915
3916 parms.rdc_set->primary.addr.len = svaddr.len;
3917 parms.rdc_set->primary.addr.maxlen = svaddr.maxlen;
3918 parms.rdc_set->primary.addr.buf = (void *)svaddr.buf;
3919
3920 #ifdef DEBUG_ADDR
3921 (void) fprintf(stderr, "primary buf %x len %d\n",
3922 svaddr.buf, svaddr.len);
3923 for (i = 0; i < svaddr.len; i++)
3924 (void) printf("%u ", svaddr.buf[i]);
3925 (void) printf("\n");
3926 #endif
3927
3928 if (getaddr) {
3929 (void) convert_nconf_to_knconf(conf, &knconf);
3930 #ifdef DEBUG_ADDR
3931 (void) printf("knconf %x %s %s %x\n", knconf.knc_semantics,
3932 knconf.knc_protofmly, knconf.knc_proto, knconf.knc_rdev);
3933 #endif
3934 parms.rdc_set->netconfig = &knconf;
3935 } else {
3936 parms.rdc_set->netconfig = NULL;
3937 }
3938
3939 if (!self_check(fromname) && !self_check(toname)) {
3940 if (!clustered)
3941 rdc_err(NULL, gettext("neither %s nor %s is local"),
3942 fromhost, tohost);
3943 else {
3944 /*
3945 * IF we could get a list of logical hosts on this cluster
3946 * Then we could print something intelligent about where
3947 * the volume is mastered. For now, just print some babble
3948 * about the fact that we have no idea.
3949 */
3950 rdc_err(NULL,
3951 gettext("either %s:%s or %s:%s is not local"),
3952 fromhost, fromfile, tohost, tofile);
3953 }
3954 }
3955
3956 (void) strncpy(parms.rdc_set->primary.intf, fromhost,
3957 MAX_RDC_HOST_SIZE);
3958 (void) strncpy(parms.rdc_set->primary.file, fromfile, NSC_MAXPATH);
3959 (void) strncpy(parms.rdc_set->primary.bitmap, frombitmap, NSC_MAXPATH);
3960
3961 (void) strncpy(parms.rdc_set->secondary.intf, tohost,
3962 MAX_RDC_HOST_SIZE);
3963 (void) strncpy(parms.rdc_set->secondary.file, tofile, NSC_MAXPATH);
3964 (void) strncpy(parms.rdc_set->secondary.bitmap, tobitmap, NSC_MAXPATH);
3965
3966 if ((group == NULL) || ((strcmp(group, "-")) == 0))
3967 parms.rdc_set->group_name[0] = 0;
3968 else
3969 (void) strncpy(parms.rdc_set->group_name, group, NSC_MAXPATH);
3970
3971 if (self_check(tohost) &&
3972 (strlen(diskqueue) > 0) && (diskqueue[0] != '-'))
3973 if ((flag == RDC_CMD_ENABLE) || (flag == RDC_CMD_ADDQ))
3974 rdc_err(NULL, gettext("enabling disk queue on a Remote"
3975 " Mirror secondary is not allowed (%s)"),
3976 diskqueue);
3977
3978 if ((diskqueue == NULL) || ((strcmp(diskqueue, "-")) == 0))
3979 parms.rdc_set->disk_queue[0] = 0;
3980 else
3981 (void) strncpy(parms.rdc_set->disk_queue, diskqueue,
3982 NSC_MAXPATH);
3983
3984 parms.rdc_set->maxqfbas = maxqfbas;
3985 parms.rdc_set->maxqitems = maxqitems;
3986 parms.rdc_set->asyncthr = asyncthr;
3987 /* set up the permanent set id for this set */
3988 if (flag == RDC_CMD_ENABLE) {
3989 char key[CFG_MAX_KEY];
3990 char setid[64];
3991 int set;
3992 parms.rdc_set->setid = get_new_cfg_setid(cfg);
3993 if (parms.rdc_set->setid <= 0) {
3994 rdc_err(NULL, gettext("unable to obtain unique set id "
3995 "for %s:%s"), tohost, tofile);
3996 }
3997 if ((set = find_setnumber_in_libcfg(cfg, clustered? ctag : NULL,
3998 tohost, tofile)) < 0) {
3999 rdc_err(NULL, gettext("unable to store unique set id"
4000 " for %s:%s"), tohost, tofile);
4001 }
4002 (void) snprintf(key, sizeof (key), "sndr.set%d.options", set);
4003 (void) snprintf(setid, sizeof (setid), "%d",
4004 parms.rdc_set->setid);
4005
4006 if (cfg_put_options(cfg, CFG_SEC_CONF, key, "setid",
4007 setid) < 0) {
4008 rdc_err(NULL, gettext("unable to store unique set "
4009 "id for %s:%s: %s"), tohost, tofile,
4010 gettext(cfg_error(NULL)));
4011 }
4012 } else if (flag != RDC_CMD_DISABLE) { /* set already gone from cfg */
4013 parms.rdc_set->setid = get_cfg_setid(cfg, ctag, tohost, tofile);
4014 if (parms.rdc_set->setid <= 0) {
4015 rdc_err(NULL, gettext("unable to obtain unique set id "
4016 "for %s:%s"), tohost, tofile);
4017 }
4018 }
4019
4020 /*
4021 * Always set autosync flag to default so nothing gets messed up. If
4022 * we are doing an autosync operation, it'll all get taken care of
4023 * then.
4024 */
4025 parms.rdc_set->autosync = AUTOSYNC;
4026
4027
4028 /* gethostid(3c) is defined to return a 32bit value */
4029 parms.rdc_set->syshostid = (int32_t)gethostid();
4030
4031 parms.command = 0;
4032 parms.options = iflag;
4033 parms.command = flag;
4034 if (flag == RDC_CMD_ENABLE || flag == RDC_CMD_RECONFIG) {
4035 if (*doasync)
4036 parms.options |= RDC_OPT_ASYNC;
4037 else
4038 parms.options |= RDC_OPT_SYNC;
4039 } else if (flag == RDC_CMD_COPY) {
4040 if (reverse)
4041 parms.options |= RDC_OPT_REVERSE;
4042 else
4043 parms.options |= RDC_OPT_FORWARD;
4044 }
4045
4046 if (self_check(fromname)) {
4047 if (flag == RDC_CMD_COPY && reverse && mounted(fromfile))
4048 rdc_err(NULL, gettext("can not start reverse sync"
4049 " as a file system is mounted on %s"),
4050 fromfile);
4051 parms.options |= RDC_OPT_PRIMARY;
4052 if (strcmp(directfile, "ip") == 0)
4053 parms.rdc_set->direct_file[0] = 0; /* no directfile */
4054 else
4055 (void) strncpy(parms.rdc_set->direct_file, directfile,
4056 NSC_MAXPATH);
4057 } else {
4058 parms.options |= RDC_OPT_SECONDARY;
4059 parms.rdc_set->direct_file[0] = 0; /* no fcal directio */
4060 }
4061
4062 if ((asyncthr || maxqitems || maxqfbas || qblock) &&
4063 (parms.options & RDC_OPT_SECONDARY)) {
4064 rdc_err(NULL, gettext("changing queue parameters may "
4065 " only be done on a primary Remote Mirror host"));
4066 spcs_log("sndr", NULL, gettext("changing queue parameters may "
4067 " only be done on a primary Remote Mirror host"));
4068
4069 }
4070
4071 ustatus = spcs_s_ucreate();
4072
4073 if (flag == RDC_CMD_COPY) {
4074 parms.command = RDC_CMD_STATUS;
4075 ret = RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus);
4076 if ((ret != SPCS_S_OK) ||
4077 !(parms.rdc_set->flags & RDC_LOGGING)) {
4078 rdc_err(NULL, gettext("can not start sync"
4079 " as Remote Mirror set %s:%s is not logging"),
4080 tohost, tofile);
4081 }
4082 spcs_log("sndr", NULL,
4083 gettext("%s %s %s %s %s %s %s %s\nStarting"),
4084 program, rdc_decode_flag(flag, parms.options),
4085 fromhost, fromfile, frombitmap,
4086 tohost, tofile, tobitmap);
4087 parms.command = RDC_CMD_COPY;
4088 }
4089
4090 if ((flag == RDC_CMD_COPY) &&
4091 (autosync_is_on(tohost, tofile) == AUTOSYNC_ON)) {
4092 /* check if autosync needs to be turned on when doing a copy/update */
4093 parms.rdc_set->autosync = AUTOSYNC_ON;
4094 autosync_toggle_needed = 1;
4095 } else if ((flag == RDC_CMD_LOG) &&
4096 (autosync_is_on(tohost, tofile) == AUTOSYNC_ON)) {
4097 /* check if autosync needs to be turned off when going to logging */
4098 parms.rdc_set->autosync = AUTOSYNC_OFF;
4099 autosync_toggle_needed = 1;
4100 } else if (((autosync == AUTOSYNC_ON) || (autosync == AUTOSYNC_OFF)) &&
4101 (flag == RDC_CMD_TUNABLE)) {
4102 /*
4103 * Request to change the autosync value. cfg file will be
4104 * available at this point. If autosync request is to turn off,
4105 * mark off in both the config and the kernel regardless of
4106 * the state of the set. If the request is to turn autosync on,
4107 * set in the kernel if the set is not in logging mode.
4108 *
4109 * XXX
4110 * If the set is in logging mode because of a network
4111 * failure, we will not know. Therefore, a manual update
4112 * will have to be issued to enable autosync in the
4113 * kernel.
4114 * XXX
4115 */
4116 set_autosync(autosync, tohost, tofile, ctag);
4117
4118 if (autosync == AUTOSYNC_OFF) {
4119 parms.rdc_set->autosync = AUTOSYNC_OFF;
4120 } else if (autosync == AUTOSYNC_ON) {
4121 parms.command = RDC_CMD_STATUS;
4122 ret = RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0,
4123 ustatus);
4124 if (ret != SPCS_S_OK) {
4125 rdc_err(NULL, gettext("can not determine "
4126 "status of Remote Mirror set %s:%s"),
4127 tohost, tofile);
4128 }
4129
4130 /* need to reset the tunables after a status ioctl */
4131 parms.rdc_set->autosync = autosync;
4132 parms.rdc_set->maxqfbas = maxqfbas;
4133 parms.rdc_set->maxqitems = maxqitems;
4134 parms.rdc_set->asyncthr = asyncthr;
4135
4136 /*
4137 * if in logging mode, just update config, kernel will
4138 * be updated with the next copy/update request.
4139 */
4140 if (parms.rdc_set->flags & RDC_LOGGING) {
4141 parms.rdc_set->autosync = AUTOSYNC;
4142 } else {
4143 parms.rdc_set->autosync = AUTOSYNC_ON;
4144 }
4145
4146 parms.command = flag;
4147 }
4148 }
4149
4150 if (autosync_toggle_needed) {
4151 parms.command = RDC_CMD_TUNABLE;
4152 ret = RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus);
4153 if (ret != SPCS_S_OK) {
4154 spcs_log("sndr", NULL, gettext("failed to update "
4155 "autosync for Remote Mirror set %s:%s"), tohost,
4156 tofile);
4157 rdc_err(NULL, gettext("failed to update autosync for "
4158 "Remote Mirror set %s:%s"), tohost, tofile);
4159 }
4160 /* reset command and default autosync flags */
4161 parms.rdc_set->autosync = AUTOSYNC;
4162 parms.command = flag;
4163 }
4164
4165 errno = 0;
4166 ret = RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus);
4167 if ((ret != SPCS_S_OK) && (flag != RDC_CMD_HEALTH)) {
4168 (void) fprintf(stderr,
4169 gettext("Remote Mirror: %s %s %s %s %s %s\n"),
4170 fromhost, fromfile,
4171 frombitmap, tohost, tofile, tobitmap);
4172
4173 if (errno == RDC_EEINVAL) {
4174 spcs_log("sndr", NULL,
4175 "%s %s %s %s %s %s %s %s\n%s",
4176 program, rdc_decode_flag(flag, parms.options),
4177 fromhost, fromfile, frombitmap,
4178 tohost, tofile, tobitmap,
4179 gettext("invalid command option"));
4180 rdc_err(&ustatus,
4181 gettext("Remote Mirror: invalid command option "
4182 "'%s'"), rdc_decode_flag(flag,
4183 parms.options));
4184 } else {
4185 spcs_log("sndr", &ustatus,
4186 "%s %s %s %s %s %s %s %s",
4187 program, rdc_decode_flag(flag, parms.options),
4188 fromhost, fromfile, frombitmap,
4189 tohost, tofile, tobitmap);
4190 if ((flag == RDC_CMD_RECONFIG) &&
4191 (!(iflag & RDC_OPT_REVERSE_ROLE))) {
4192 success = 0;
4193 rdc_warn(&ustatus, 0);
4194 } else
4195 rdc_err(&ustatus, 0);
4196 }
4197 }
4198 if ((flag == RDC_CMD_RECONFIG) && (iflag & RDC_OPT_REVERSE_ROLE) == 0) {
4199 parms.command = RDC_CMD_STATUS;
4200 if (RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus) ==
4201 SPCS_S_OK) {
4202 char shostbuf[CFG_MAX_BUF];
4203 char svolbuf[CFG_MAX_BUF];
4204 char key[CFG_MAX_KEY];
4205 int i, numels;
4206 int cfgsuccess = 1;
4207
4208 /*
4209 * okeydoke, at this point we could have a reconfig
4210 * gone bad. libdscfg does not know about this.
4211 * parms contains the kernel picture, and we know
4212 * what we tried to reconfig. find out where it went
4213 * wrong, find the set in libdscfg, update it. We'll
4214 * issue a warning, then return 0 (eventually).
4215 * this will allow libdscfg to be committed with the
4216 * good info. got it?
4217 * BTW: the only time we can run into this multiple
4218 * reconfig attempt failure is IF we reconfig from file
4219 * and some thing goes wrong with one of the reconfigs
4220 */
4221
4222 /* find the set in libdscfg */
4223
4224 numels = cfg_get_num_entries(cfg, "sndr");
4225 /* yes, numels could be -1 */
4226 for (i = 1; i < numels; i++) {
4227 bzero(shostbuf, sizeof (shostbuf));
4228 bzero(svolbuf, sizeof (svolbuf));
4229 bzero(key, sizeof (key));
4230
4231 (void) snprintf(key, sizeof (key),
4232 "sndr.set%d.shost", i);
4233
4234 (void) cfg_get_cstring(cfg, key, &shostbuf,
4235 sizeof (shostbuf));
4236 if (strncmp(shostbuf, tohost, sizeof (tohost)))
4237 continue;
4238
4239 bzero(key, sizeof (key));
4240 (void) snprintf(key, sizeof (key),
4241 "sndr.set%d.secondary", i);
4242 (void) cfg_get_cstring(cfg, key, &svolbuf,
4243 sizeof (svolbuf));
4244 if (strncmp(svolbuf, tofile, NSC_MAXPATH))
4245 continue;
4246 break;
4247
4248 /*
4249 * found it, now i contains the set offset.
4250 * i, being the variable, not bad english.
4251 */
4252
4253 }
4254 /* shouldn't happen */
4255 if ((numels < 1) || (i > numels)) {
4256 rdc_warn(NULL, gettext("unable to retrieve "
4257 "set from configuration database"));
4258 /*
4259 * yuck. but indents are pushing the envelope
4260 * we should not be updating config
4261 * if we did not find the entry
4262 * the error will have to do
4263 */
4264 cfgsuccess = 0;
4265 goto notfound;
4266 }
4267
4268 /*
4269 * now, put all the correct names back for errors etc.
4270 * also, sock them into dscfg, if the the config was a
4271 * success for one, it will be a redundant but harmless
4272 */
4273
4274 /*
4275 * we could not have reconfigged mode if we
4276 * are not logging, AND the kernel CAN return
4277 * sync as the status of an async set if it is
4278 * currently syncing.. Hence the flags & RDC_LOGGING
4279 */
4280 if (parms.rdc_set->flags & RDC_LOGGING) {
4281 bzero(key, sizeof (key));
4282 (void) snprintf(key, sizeof (key),
4283 "sndr.set%d.mode", i);
4284 if (parms.rdc_set->flags & RDC_ASYNC) {
4285 *doasync = 1;
4286 if (cfg_put_cstring(cfg, key, "async",
4287 strlen("async")) < 0) {
4288 cfgsuccess = 0;
4289 }
4290
4291 } else {
4292 *doasync = 0;
4293 if (cfg_put_cstring(cfg, key, "sync",
4294 strlen("sync")) < 0) {
4295 cfgsuccess = 0;
4296 }
4297 }
4298 }
4299 #ifdef _RDC_CAMPUS
4300 if (*parms.rdc_set->direct_file) {
4301 (void) strncpy(directfile,
4302 parms.rdc_set->direct_file, NSC_MAXPATH);
4303 bzero(key, sizeof (key));
4304 (void) snprintf(key, sizeof (key),
4305 "sndr.set%d.type", i);
4306 if (cfg_put_cstring(cfg, key, directfile,
4307 strlen(directfile)) < 0)
4308 cfgsuccess = 0;
4309 } else {
4310 (void) strncpy(directfile, "-", NSC_MAXPATH);
4311 bzero(key, sizeof (key));
4312 (void) snprintf(key, sizeof (key),
4313 "sndr.set%d.type", i);
4314 if (cfg_put_cstring(cfg, key, directfile,
4315 strlen(directfile)) < 0)
4316 cfgsuccess = 0;
4317 }
4318 #endif
4319
4320 if (*parms.rdc_set->group_name) {
4321 (void) strncpy(group, parms.rdc_set->group_name,
4322 NSC_MAXPATH);
4323 bzero(key, sizeof (key));
4324 (void) snprintf(key, sizeof (key),
4325 "sndr.set%d.group", i);
4326 if (cfg_put_cstring(cfg, key, group,
4327 strlen(group)) < 0)
4328 cfgsuccess = 0;
4329
4330 } else {
4331 (void) strncpy(group, "-", NSC_MAXPATH);
4332 bzero(key, sizeof (key));
4333 (void) snprintf(key, sizeof (key),
4334 "sndr.set%d.group", i);
4335 if (cfg_put_cstring(cfg, key, group,
4336 strlen(group)) < 0)
4337 cfgsuccess = 0;
4338 }
4339
4340 if (*parms.rdc_set->disk_queue) {
4341 (void) strncpy(diskqueue,
4342 parms.rdc_set->disk_queue, NSC_MAXPATH);
4343 } else {
4344 (void) strncpy(diskqueue, "-", NSC_MAXPATH);
4345 }
4346 bzero(key, sizeof (key));
4347 (void) snprintf(key, sizeof (key),
4348 "sndr.set%d.diskq", i);
4349 if (cfg_put_cstring(cfg, key, diskqueue,
4350 strlen(diskqueue)) < 0)
4351 cfgsuccess = 0;
4352
4353 (void) strncpy(frombitmap,
4354 parms.rdc_set->primary.bitmap, NSC_MAXPATH);
4355 bzero(key, sizeof (key));
4356 (void) snprintf(key, sizeof (key),
4357 "sndr.set%d.pbitmap", i);
4358 if (cfg_put_cstring(cfg, key, frombitmap,
4359 strlen(frombitmap)) < 0)
4360 cfgsuccess = 0;
4361
4362 (void) strncpy(tobitmap,
4363 parms.rdc_set->secondary.bitmap, NSC_MAXPATH);
4364 bzero(key, sizeof (key));
4365 (void) snprintf(key, sizeof (key),
4366 "sndr.set%d.sbitmap", i);
4367 if (cfg_put_cstring(cfg, key, tobitmap,
4368 strlen(tobitmap)) < 0)
4369 cfgsuccess = 0;
4370
4371 bzero(key, sizeof (key));
4372 (void) snprintf(key, sizeof (key),
4373 "sndr.set%d.cnode", i);
4374 if (clustered)
4375 if (cfg_put_cstring(cfg, key, ctag,
4376 strlen(ctag)) < 0)
4377 cfgsuccess = 0;
4378 notfound:
4379 if (cfgsuccess == 0) {
4380 rdc_warn(NULL, gettext("unable to update "
4381 "configuration storage"));
4382 }
4383 } else {
4384 spcs_log("sndr", NULL,
4385 "%s %s %s %s %s %s %s %s\n%s",
4386 program, rdc_decode_flag(flag, parms.options),
4387 fromhost, fromfile, frombitmap,
4388 tohost, tofile, tobitmap,
4389 gettext("unable to update config file"));
4390 rdc_err(&ustatus,
4391 gettext("Remote Mirror: unable to update "
4392 "config file"));
4393
4394 }
4395 }
4396
4397 if (flag == RDC_CMD_HEALTH && errno == 0) {
4398 (void) fprintf(stderr,
4399 gettext("Remote Mirror: %s %s %s %s %s %s\n"),
4400 fromhost, fromfile,
4401 frombitmap, tohost, tofile, tobitmap);
4402
4403 if (ret == RDC_ACTIVE)
4404 (void) fprintf(stderr, "Active\n");
4405 else if (ret == RDC_INACTIVE)
4406 (void) fprintf(stderr, "Inactive\n");
4407 else
4408 (void) fprintf(stderr, "Unknown\n");
4409 } else if (ret != SPCS_S_OK) {
4410 if (errno == RDC_EEINVAL) {
4411 spcs_log("sndr", NULL,
4412 "%s %s %s %s %s %s %s %s\n%s",
4413 program, rdc_decode_flag(flag, parms.options),
4414 fromhost, fromfile, frombitmap,
4415 tohost, tofile, tobitmap,
4416 gettext("invalid command option"));
4417 rdc_err(&ustatus,
4418 gettext("Remote Mirror: invalid command option "
4419 "'%s'"),
4420 rdc_decode_flag(flag, parms.options));
4421 }
4422 }
4423 if (flag == RDC_CMD_STATUS) {
4424 (void) fprintf(stderr,
4425 gettext("Remote Mirror: %s %s %s %s %s %s\n"),
4426 fromhost, fromfile,
4427 frombitmap, tohost, tofile, tobitmap);
4428 (void) fprintf(stderr, "flags 0x%x\n", parms.rdc_set->flags |
4429 parms.rdc_set->sync_flags | parms.rdc_set->bmap_flags);
4430 } else if (success) {
4431 spcs_log("sndr", NULL,
4432 gettext("%s %s %s %s %s %s %s %s\nSuccessful"),
4433 program, rdc_decode_flag(flag, parms.options),
4434 fromhost, fromfile, frombitmap,
4435 tohost, tofile, tobitmap);
4436 if (flag == RDC_CMD_TUNABLE)
4437 spcslog_tunable(tohost, tofile);
4438 }
4439
4440 if (cfg && perform_autosv()) {
4441 spcs_s_ufree(&ustatus);
4442 /* figure out which are the local volumes */
4443 if (parms.options & RDC_OPT_PRIMARY) {
4444 vol1 = fromfile;
4445 vol2 = frombitmap;
4446 if ((diskqueue && diskqueue[0]) &&
4447 (strncmp(diskqueue, "-", 1) != 0))
4448 vol3 = diskqueue;
4449 else
4450 vol3 = NULL;
4451 } else {
4452 vol1 = tofile;
4453 vol2 = tobitmap;
4454 vol3 = NULL;
4455 if ((flag == RDC_CMD_ENABLE) &&
4456 (strlen(diskqueue) > 0) &&
4457 (strncmp(diskqueue, "-", 1)) != 0) {
4458 rdc_warn(NULL,
4459 gettext("enabling a disk queue on a "
4460 "Remote Mirror secondary is not allowed. "
4461 "(%s) ignored"), diskqueue);
4462 }
4463 }
4464
4465 if (flag == RDC_CMD_ENABLE) {
4466 ustatus = spcs_s_ucreate();
4467 /*
4468 * SV-enable all local volumes
4469 * if the sv_enables fail, disable the sndr vols
4470 * that we just enabled
4471 * and return -1 so the cfg_commit() won't happen
4472 */
4473
4474 if (nsc_lookup(volhash, vol1) == NULL) {
4475 if (cfg_vol_enable(cfg, vol1, ctag, "sndr")
4476 < 0) {
4477 spcs_log("sndr", NULL,
4478 "sv enable failed for %s, "
4479 "disabling Remote Mirror set %s:%s",
4480 vol1, tohost, tofile);
4481 /*
4482 * warn here, but we are going to exit
4483 * we want to catch any errors on the
4484 * way down, then exit
4485 */
4486
4487 rdc_warn(NULL,
4488 "unable to sv enable %s\n"
4489 "disabling Remote Mirror set %s:%s",
4490 vol1, tohost, tofile);
4491
4492 parms.command = RDC_CMD_DISABLE;
4493 ret = RDC_IOCTL(RDC_CONFIG, &parms,
4494 NULL, 0, 0, 0, ustatus);
4495 if (ret != SPCS_S_OK) {
4496 (void) fprintf(stderr,
4497 gettext("Remote Mirror:"
4498 " %s %s %s %s %s %s\n"),
4499 fromhost, fromfile,
4500 frombitmap, tohost, tofile,
4501 tobitmap);
4502 spcs_log("sndr", &ustatus,
4503 "%s %s %s %s %s %s %s %s",
4504 program,
4505 rdc_decode_flag(parms.command,
4506 parms.options),
4507 fromhost,
4508 fromfile, frombitmap,
4509 tohost, tofile, tobitmap);
4510 rdc_err(&ustatus, 0);
4511 }
4512 /*
4513 * ok, we should've reported any errs
4514 * exit explictly
4515 */
4516 exit(1);
4517
4518 }
4519 }
4520 if (vol2 && nsc_lookup(volhash, vol2) == NULL) {
4521 if (cfg_vol_enable(cfg, vol2, ctag, "sndr")
4522 < 0) {
4523 spcs_log("sndr", NULL,
4524 "sv enable failed for %s, "
4525 "disabling Remote Mirror set %s:%s",
4526 vol1, tohost, tofile);
4527 /*
4528 * warn here, but we are going to exit
4529 * we want to catch any errors on the
4530 * way down, then exit
4531 */
4532
4533 rdc_warn(NULL,
4534 "unable to sv enable %s\n"
4535 "disabling Remote Mirror set %s:%s",
4536 vol2, tohost, tofile);
4537
4538 parms.command = RDC_CMD_DISABLE;
4539 ret = RDC_IOCTL(RDC_CONFIG, &parms,
4540 NULL, 0, 0, 0, ustatus);
4541 if (ret != SPCS_S_OK) {
4542 (void) fprintf(stderr,
4543 gettext("Remote Mirror:"
4544 " %s %s %s %s %s %s\n"),
4545 fromhost, fromfile,
4546 frombitmap, tohost, tofile,
4547 tobitmap);
4548 spcs_log("sndr", &ustatus,
4549 "%s %s %s %s %s %s %s %s",
4550 program,
4551 rdc_decode_flag(parms.command,
4552 parms.options),
4553 fromhost,
4554 fromfile, frombitmap,
4555 tohost, tofile, tobitmap);
4556 rdc_err(&ustatus, 0);
4557 }
4558 /*
4559 * ok, we should've reported any errs
4560 * exit explictly
4561 */
4562 exit(1);
4563
4564 }
4565 }
4566
4567 if (vol3 && nsc_lookup(volhash, diskqueue) == NULL) {
4568 if (cfg_vol_enable(cfg, diskqueue, ctag, "sndr")
4569 < 0) {
4570 spcs_log("sndr", NULL,
4571 "sv enable failed for %s, "
4572 "disabling Remote Mirror set %s:%s",
4573 diskqueue, tohost, tofile);
4574 if (cfg_vol_disable(cfg, vol1, ctag,
4575 "sndr") < 0)
4576 rdc_warn(NULL, gettext("Failed to "
4577 "remove volume [%s] from "
4578 "configuration"), vol1);
4579 if (cfg_vol_disable(cfg, vol2, ctag,
4580 "sndr") < 0)
4581 rdc_warn(NULL, gettext("Failed to "
4582 "remove volume [%s] from "
4583 "configuration"), vol2);
4584
4585 /*
4586 * warn here, but we are going to exit
4587 * we want to catch any errors on the
4588 * way down, then exit
4589 */
4590
4591 rdc_warn(NULL,
4592 "unable to sv enable %s\n"
4593 "disabling Remote Mirror set %s:%s",
4594 diskqueue, tohost, tofile);
4595
4596 parms.command = RDC_CMD_DISABLE;
4597 ret = RDC_IOCTL(RDC_CONFIG, &parms,
4598 NULL, 0, 0, 0, ustatus);
4599 if (ret != SPCS_S_OK) {
4600 (void) fprintf(stderr,
4601 gettext("Remote Mirror:"
4602 " %s %s %s %s %s %s\n"),
4603 fromhost, fromfile,
4604 frombitmap, tohost, tofile,
4605 tobitmap);
4606 spcs_log("sndr", &ustatus,
4607 "%s %s %s %s %s %s %s %s",
4608 program,
4609 rdc_decode_flag(parms.command,
4610 parms.options),
4611 fromhost,
4612 fromfile, frombitmap,
4613 tohost, tofile, tobitmap);
4614 rdc_err(&ustatus, 0);
4615 }
4616 /*
4617 * ok, we should've reported any errs
4618 * exit explictly
4619 */
4620 exit(1);
4621
4622 }
4623 }
4624 } else if (flag == RDC_CMD_DISABLE) {
4625 /*
4626 * If we're no longer using a volume, SV-disable it
4627 */
4628 volcount_t *vc;
4629
4630 vc = nsc_lookup(volhash, vol1);
4631 if (vc && (1 == vc->count)) {
4632 if (cfg_vol_disable(cfg, vol1, ctag, "sndr")
4633 < 0)
4634 rdc_warn(NULL, gettext("Failed to "
4635 "remove volume [%s] from "
4636 "configuration"), vol1);
4637
4638 } else if (!vc) {
4639 rdc_warn(NULL,
4640 gettext("Unable to find %s in config"),
4641 vol1);
4642 }
4643
4644 if (vol2) {
4645 vc = nsc_lookup(volhash, vol2);
4646 if (vc && (1 == vc->count)) {
4647 if (cfg_vol_disable(cfg, vol2, ctag,
4648 "sndr") < 0)
4649 rdc_warn(NULL, gettext("Failed to "
4650 "remove volume [%s] from "
4651 "configuration"), vol2);
4652 } else if (!vc) {
4653 rdc_warn(NULL, gettext("Unable to find"
4654 " %s in config"), vol2);
4655 }
4656 }
4657
4658 if (diskqueue != NULL && strlen(diskqueue) > 0) {
4659 vc = nsc_lookup(volhash, diskqueue);
4660 if (vc && (1 == vc->count)) {
4661 if (cfg_vol_disable(cfg, diskqueue, ctag,
4662 "sndr") < 0)
4663 rdc_warn(NULL, gettext("Failed to "
4664 "remove disk queue [%s] from "
4665 "configuration"), diskqueue);
4666 } else if (!vc) {
4667 rdc_warn(NULL, gettext("Unable to find"
4668 " %s in config"), diskqueue);
4669 }
4670 }
4671 /* WARNING about to go to 4 space indenting */
4672 } else if (flag == RDC_CMD_RECONFIG) {
4673 volcount_t *vc;
4674 /* disable ex-bitmaps, enable new bitmaps */
4675 if (parms.options & RDC_OPT_PRIMARY) {
4676 if (strcmp(orig_fbmp, frombitmap) != 0) {
4677 vc = nsc_lookup(volhash, orig_fbmp);
4678 if (vc && (vc->count == 1)) {
4679 if (cfg_vol_disable(cfg, orig_fbmp, ctag,
4680 "sndr") < 0)
4681 rdc_warn(NULL, gettext("Failed to "
4682 "remove bitmap [%s] from "
4683 "configuration"), orig_fbmp);
4684 } else if (!vc) {
4685 rdc_warn(NULL, gettext("Unable to find "
4686 "%s in config"), orig_fbmp);
4687 }
4688 if (nsc_lookup(volhash, frombitmap) == NULL) {
4689 if (cfg_vol_enable(cfg, frombitmap, ctag,
4690 "sndr") < 0) {
4691 spcs_log("sndr", NULL,
4692 "reconfig sv enable failed for %s, "
4693 "disabling Remote Mirror set %s:%s",
4694 frombitmap, tohost, tofile);
4695 rdc_warn(NULL,
4696 "unable to sv enable %s\n"
4697 "disabling Remote Mirror set %s:%s",
4698 frombitmap, tohost, tofile);
4699 parms.command = RDC_CMD_DISABLE;
4700 ret = RDC_IOCTL(RDC_CONFIG, &parms,
4701 NULL, 0, 0, 0, ustatus);
4702 if (ret != SPCS_S_OK) {
4703 (void) fprintf(stderr,
4704 gettext("Remote Mirror:"
4705 " %s %s %s %s %s %s\n"),
4706 fromhost, fromfile,
4707 frombitmap, tohost, tofile,
4708 tobitmap);
4709 spcs_log("sndr", &ustatus,
4710 "%s %s %s %s %s %s %s %s",
4711 program,
4712 rdc_decode_flag(parms.command,
4713 parms.options),
4714 fromhost,
4715 fromfile, frombitmap,
4716 tohost, tofile, tobitmap);
4717 rdc_warn(&ustatus, 0);
4718 }
4719 exit(1);
4720 }
4721 }
4722 } else if ((orig_diskq[0] != '\0') &&
4723 (strcmp(orig_diskq, diskqueue) != 0)) {
4724 vc = nsc_lookup(volhash, orig_diskq);
4725 if (vc && (vc->count == 1)) {
4726 if (cfg_vol_disable(cfg, orig_diskq, ctag,
4727 "sndr") < 0)
4728 rdc_warn(NULL, gettext("Failed to "
4729 "remove disk queue [%s] from "
4730 "configuration"), orig_diskq);
4731 } else if (!vc) {
4732 rdc_warn(NULL, gettext("Unable to find "
4733 "%s in config"), orig_diskq);
4734 }
4735 if (vol3 &&
4736 (nsc_lookup(volhash, diskqueue) == NULL)) {
4737 if (cfg_vol_enable(cfg, diskqueue, ctag,
4738 "sndr") < 0) {
4739 spcs_log("sndr", NULL, "reconfig sv "
4740 "enable of diskqueue %s failed, "
4741 "disabling Remote Mirror set %s:%s",
4742 diskqueue, tohost, tofile);
4743 rdc_warn(NULL, "reconfig sv "
4744 "enable of diskqueue %s failed."
4745 "disabling Remote Mirror set %s:%s",
4746 diskqueue, tohost, tofile);
4747 parms.command = RDC_CMD_DISABLE;
4748 ret = RDC_IOCTL(RDC_CONFIG, &parms,
4749 NULL, 0, 0, 0, ustatus);
4750 if (ret != SPCS_S_OK) {
4751 (void) fprintf(stderr,
4752 gettext("Remote Mirror:"
4753 " %s %s %s %s %s %s\n"),
4754 fromhost, fromfile,
4755 frombitmap, tohost, tofile,
4756 tobitmap);
4757 spcs_log("sndr", &ustatus,
4758 "%s %s %s %s %s %s %s %s",
4759 program,
4760 rdc_decode_flag(parms.command,
4761 parms.options),
4762 fromhost,
4763 fromfile, frombitmap,
4764 tohost, tofile, tobitmap);
4765 rdc_warn(&ustatus, 0);
4766 }
4767 exit(1);
4768 }
4769 }
4770 }
4771 } else if (flag != RDC_OPT_PRIMARY) {
4772 if (strcmp(orig_tbmp, tobitmap) != 0) {
4773 vc = nsc_lookup(volhash, orig_tbmp);
4774 if (vc && (vc->count == 1)) {
4775 if (cfg_vol_disable(cfg, orig_tbmp, ctag,
4776 "sndr") < 0)
4777 rdc_warn(NULL, gettext("Failed to "
4778 "remove bitmap [%s] from "
4779 "configuration"), orig_tbmp);
4780 } else if (!vc) {
4781 rdc_warn(NULL,
4782 gettext("Unable to find %s in config"),
4783 orig_tbmp);
4784 }
4785 if (nsc_lookup(volhash, tobitmap) == NULL) {
4786 if (cfg_vol_enable(cfg, tobitmap, ctag,
4787 "sndr") < 0) {
4788 spcs_log("sndr", NULL,
4789 "reconfig sv enable failed for %s, "
4790 "disabling Remote Mirror set %s:%s",
4791 tobitmap, tohost, tofile);
4792 rdc_warn(NULL,
4793 "unable to sv enable %s\n"
4794 "disabling Remote Mirror set %s:%s",
4795 tobitmap, tohost, tofile);
4796 parms.command = RDC_CMD_DISABLE;
4797 ret = RDC_IOCTL(RDC_CONFIG, &parms,
4798 NULL, 0, 0, 0, ustatus);
4799 if (ret != SPCS_S_OK) {
4800 (void) fprintf(stderr,
4801 gettext("Remote Mirror:"
4802 " %s %s %s %s %s %s\n"),
4803 fromhost, fromfile,
4804 frombitmap, tohost, tofile,
4805 tobitmap);
4806 spcs_log("sndr", &ustatus,
4807 "%s %s %s %s %s %s %s %s",
4808 program,
4809 rdc_decode_flag(parms.command,
4810 parms.options),
4811 fromhost, fromfile, frombitmap,
4812 tohost, tofile, tobitmap);
4813 rdc_warn(&ustatus, 0);
4814 }
4815 exit(1);
4816 }
4817 }
4818 }
4819 }
4820 /* END 4 space indenting */
4821 }
4822 }
4823 spcs_s_ufree(&ustatus);
4824
4825 return (0);
4826 }
4827
4828
4829 /*
4830 * read_config()
4831 *
4832 * DESCRIPTION: Read the lines in a configuration file and return the
4833 * pairs of devices to be mirrored/enabled/disabled/updated.
4834 * The format for the configuration file is as follows:
4835 *
4836 * fromhost fromfile frombitmap tohost tofile tobitmap
4837 *
4838 * where fromfile is the primary device which is local to the
4839 * fromhost subsystem, tofile is the secondary device which is
4840 * local to the tohost subsystem, and type is 1 if the device
4841 * a simckd device or 0 otherwise. Any line preceeded by a '#'
4842 * is considered to be a comment.
4843 *
4844 * Inputs:
4845 * char *config_file Name of configuration file for rdcadm
4846 *
4847 * Outputs:
4848 * int i Number of pairs of devices
4849 *
4850 * Side Effects: The 0 to i-1 entries in the pair_list are filled.
4851 *
4852 */
4853
4854 int
4855 read_config(int flag, char *config_file, char *group_arg, char *ctag_arg)
4856 {
4857 int ret;
4858 char dsk_flagstr[NSC_MAXPATH];
4859 char line[1024], tmp_line[1024];
4860 char fromhost[MAX_RDC_HOST_SIZE];
4861 char fromfile[NSC_MAXPATH];
4862 char frombitmap[NSC_MAXPATH];
4863 char tohost[MAX_RDC_HOST_SIZE];
4864 char tofile[NSC_MAXPATH];
4865 char tobitmap[NSC_MAXPATH];
4866 char directfile[NSC_MAXPATH];
4867 char sync[16];
4868 int doasync;
4869 FILE *fp;
4870 int i, j;
4871 char *extra_args[EXTRA_ARGS];
4872 char *tmp, *split_str = " \t\n";
4873
4874 for (j = 0; j < EXTRA_ARGS; j++)
4875 extra_args[j] = malloc(NSC_MAXPATH);
4876
4877 if (!(fp = fopen(config_file, "r"))) {
4878 rdc_err(NULL, gettext("error opening %s"), config_file);
4879 }
4880
4881 i = 0;
4882 while (fgets(line, sizeof (line), fp)) {
4883 if (line[0] == '#') /* this is a comment */
4884 continue;
4885
4886 ret = 0;
4887 (void) strcpy(tmp_line, line);
4888
4889 if ((tmp = strtok(tmp_line, split_str)) != NULL) {
4890 if (strlen(tmp) >= MAX_RDC_HOST_SIZE) {
4891 (void) printf(gettext("hostname is longer than %d "
4892 "characters\n"), (MAX_RDC_HOST_SIZE - 1));
4893 continue;
4894 }
4895 (void) strncpy(fromhost, tmp, (MAX_RDC_HOST_SIZE - 1));
4896 fromhost[(MAX_RDC_HOST_SIZE - 1)] = '\0';
4897 ret++;
4898 }
4899 if ((tmp = strtok(NULL, split_str)) != NULL) {
4900 if (strlen(tmp) >= NSC_MAXPATH) {
4901 (void) printf(gettext(
4902 "device name is longer than %d "
4903 "characters\n"), (NSC_MAXPATH - 1));
4904 continue;
4905 }
4906 (void) strncpy(fromfile, tmp, (NSC_MAXPATH - 1));
4907 fromfile[(NSC_MAXPATH - 1)] = '\0';
4908 ret++;
4909 }
4910 if ((tmp = strtok(NULL, split_str)) != NULL) {
4911 if (strlen(tmp) >= NSC_MAXPATH) {
4912 (void) printf(gettext(
4913 "device name is longer than %d "
4914 "characters\n"), (NSC_MAXPATH - 1));
4915 continue;
4916 }
4917 (void) strncpy(frombitmap, tmp, (NSC_MAXPATH - 1));
4918 frombitmap[(NSC_MAXPATH - 1)] = '\0';
4919 ret++;
4920 }
4921 if ((tmp = strtok(NULL, split_str)) != NULL) {
4922 if (strlen(tmp) >= MAX_RDC_HOST_SIZE) {
4923 (void) printf(gettext(
4924 "hostname is longer than %d "
4925 "characters\n"), (MAX_RDC_HOST_SIZE - 1));
4926 continue;
4927 }
4928 (void) strncpy(tohost, tmp, (MAX_RDC_HOST_SIZE - 1));
4929 tohost[(MAX_RDC_HOST_SIZE - 1)] = '\0';
4930 ret++;
4931 }
4932 if ((tmp = strtok(NULL, split_str)) != NULL) {
4933 if (strlen(tmp) >= NSC_MAXPATH) {
4934 (void) printf(gettext(
4935 "device name is longer than %d "
4936 "characters\n"), (NSC_MAXPATH - 1));
4937 continue;
4938 }
4939 (void) strncpy(tofile, tmp, (NSC_MAXPATH - 1));
4940 tofile[(NSC_MAXPATH - 1)] = '\0';
4941 ret++;
4942 }
4943 if ((tmp = strtok(NULL, split_str)) != NULL) {
4944 if (strlen(tmp) >= NSC_MAXPATH) {
4945 (void) printf(gettext(
4946 "device name is longer than %d "
4947 "characters\n"), (NSC_MAXPATH - 1));
4948 continue;
4949 }
4950 (void) strncpy(tobitmap, tmp, (NSC_MAXPATH - 1));
4951 tobitmap[(NSC_MAXPATH - 1)] = '\0';
4952 ret++;
4953 }
4954 if ((tmp = strtok(NULL, split_str)) != NULL) {
4955 (void) strncpy(dsk_flagstr, tmp, 15);
4956 dsk_flagstr[15] = '\0';
4957 ret++;
4958 }
4959 if ((tmp = strtok(NULL, split_str)) != NULL) {
4960 (void) strncpy(sync, tmp, 15);
4961 sync[15] = '\0';
4962 ret++;
4963 }
4964 for (j = 0; j < EXTRA_ARGS; j++) {
4965 if ((tmp = strtok(NULL, split_str)) != NULL) {
4966 (void) strncpy(extra_args[j], tmp,
4967 (NSC_MAXPATH - 1));
4968 extra_args[j][(NSC_MAXPATH - 1)] = '\0';
4969 ret++;
4970 }
4971 }
4972
4973 if (ret == 0) /* this is a blank line */
4974 continue;
4975
4976 if (ret < 8) {
4977 (void) fclose(fp);
4978 rdc_warn(NULL,
4979 gettext("invalid format in %s"), config_file);
4980 rdc_err(NULL, "%s", line);
4981 }
4982
4983 if (i >= rdc_maxsets) {
4984 (void) fclose(fp);
4985 rdc_err(NULL,
4986 gettext("number of Remote Mirror sets exceeds %d"),
4987 rdc_maxsets);
4988 }
4989
4990 #ifdef _RDC_CAMPUS
4991 if (dsk_flagstr[0] == '/') {
4992 /* fcal directio */
4993 (void) strncpy(directfile, dsk_flagstr, NSC_MAXPATH);
4994 } else if (strcmp(dsk_flagstr, "ip") != 0) {
4995 #else
4996 if (strcmp(dsk_flagstr, "ip") != 0) {
4997 #endif
4998 (void) fclose(fp);
4999 rdc_err(NULL,
5000 #ifdef _RDC_CAMPUS
5001 gettext("ip/fcal specification missing"));
5002 #else
5003 gettext("ip specification missing"));
5004 #endif
5005 } else
5006 (void) strcpy(directfile, "ip");
5007
5008 if (strcmp(sync, "sync") == 0)
5009 doasync = 0;
5010 else if (strcmp(sync, "async") == 0)
5011 doasync = 1;
5012 else {
5013 (void) fclose(fp);
5014 rdc_err(NULL,
5015 gettext("sync/async specification missing"));
5016 }
5017 (void) strncpy(pair_list[i].fhost, fromhost, MAX_RDC_HOST_SIZE);
5018 (void) strncpy(pair_list[i].ffile, fromfile, NSC_MAXPATH);
5019 (void) strncpy(pair_list[i].fbitmap, frombitmap, NSC_MAXPATH);
5020 (void) strncpy(pair_list[i].thost, tohost, MAX_RDC_HOST_SIZE);
5021 (void) strncpy(pair_list[i].tfile, tofile, NSC_MAXPATH);
5022 (void) strncpy(pair_list[i].tbitmap, tobitmap, NSC_MAXPATH);
5023 (void) strncpy(pair_list[i].directfile, directfile,
5024 NSC_MAXPATH);
5025 pair_list[i].doasync = doasync;
5026
5027 if (gethost_netaddrs(fromhost, tohost,
5028 (char *)pair_list[i].fnetaddr,
5029 (char *)pair_list[i].tnetaddr) < 0) {
5030 (void) fclose(fp);
5031 rdc_err(NULL, gettext("unable to determine IP "
5032 "addresses for hosts %s, %s"), fromhost, tohost);
5033 }
5034
5035 if (parse_extras(ret - 8, extra_args, i) < 0) {
5036 (void) fclose(fp);
5037 rdc_err(NULL, gettext("illegal option in:\n%s"),
5038 line);
5039 }
5040
5041 if (flag == RDC_CMD_ENABLE || flag == RDC_CMD_RECONFIG) {
5042 if (ctag_check(fromhost, fromfile, frombitmap,
5043 tohost, tofile, tobitmap, pair_list[i].ctag,
5044 pair_list[i].diskqueue) < 0)
5045 continue; /* Ignore illegal sets */
5046 if (pair_diskqueue_check(i))
5047 continue; /* ignore sets with incorrect diskq */
5048 }
5049
5050 /* Filter according to ctag and group arguments */
5051 if (strcmp(ctag_arg, "") &&
5052 strncmp(ctag_arg, pair_list[i].ctag,
5053 MAX_RDC_HOST_SIZE))
5054 continue;
5055 if (strcmp(group_arg, "") &&
5056 strncmp(group_arg, pair_list[i].group, NSC_MAXPATH))
5057 continue;
5058
5059 i++;
5060 }
5061 (void) fclose(fp);
5062 for (j = 0; j < EXTRA_ARGS; j++)
5063 free(extra_args[j]);
5064 return (i);
5065 }
5066
5067
5068 /*
5069 * read_libcfg()
5070 *
5071 * DESCRIPTION: Read the relevant config info via libcfg
5072 *
5073 * Outputs:
5074 * int i Number of pairs of devices
5075 *
5076 * Side Effects: The 0 to i-1 entries in the pair_list are filled.
5077 *
5078 */
5079 static int
5080 read_libcfg(int flag, char *group_arg, char *ctag_arg)
5081 {
5082 int rc;
5083 CFGFILE *cfg;
5084 int i;
5085 _sd_dual_pair_t *pairp;
5086 char buf[CFG_MAX_BUF];
5087 char key[CFG_MAX_KEY];
5088 int setnumber;
5089
5090 if ((cfg = cfg_open(NULL)) == NULL)
5091 rdc_err(NULL, gettext("unable to access configuration"));
5092
5093 if (!cfg_lock(cfg, CFG_RDLOCK))
5094 rdc_err(NULL, gettext("unable to lock configuration"));
5095
5096 if (strcmp(ctag_arg, ""))
5097 cfg_resource(cfg, ctag_arg);
5098 else {
5099 cfg_resource(cfg, NULL);
5100 }
5101
5102 setnumber = 0;
5103 /*CSTYLED*/
5104 for (i = 0; i < rdc_maxsets;) {
5105 setnumber++;
5106
5107 bzero(buf, CFG_MAX_BUF);
5108 (void) snprintf(key, sizeof (key), "sndr.set%d", setnumber);
5109 rc = cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF);
5110 if (rc < 0)
5111 break;
5112
5113 pairp = &pair_list[i];
5114 if (parse_cfg_buf(buf, pairp, NULL))
5115 continue;
5116
5117 if (strcmp(group_arg, "") &&
5118 strncmp(group_arg, pairp->group, NSC_MAXPATH))
5119 continue;
5120
5121 if (flag == RDC_CMD_RECONFIG) {
5122 if (reconfig_pbitmap)
5123 (void) strncpy(pairp->fbitmap, reconfig_pbitmap,
5124 NSC_MAXPATH);
5125 if (reconfig_sbitmap)
5126 (void) strncpy(pairp->tbitmap, reconfig_sbitmap,
5127 NSC_MAXPATH);
5128 #ifdef _RDC_CAMPUS
5129 if (reconfig_direct)
5130 (void) strncpy(directfile, reconfig_direct,
5131 NSC_MAXPATH);
5132 #endif
5133 if (reconfig_group)
5134 (void) strncpy(pairp->group, reconfig_group,
5135 NSC_MAXPATH);
5136
5137 if (strlen(reconfig_ctag) > 0)
5138 (void) strncpy(pairp->ctag, reconfig_ctag,
5139 MAX_RDC_HOST_SIZE);
5140
5141 if (reconfig_doasync != -1)
5142 pairp->doasync = reconfig_doasync;
5143 }
5144
5145
5146 if (ctag_check(pairp->fhost, pairp->ffile,
5147 pairp->fbitmap, pairp->thost, pairp->tfile,
5148 pairp->tbitmap, pairp->ctag, pairp->diskqueue) < 0)
5149 continue; /* Ignore illegal sets */
5150
5151 if (gethost_netaddrs(pairp->fhost, pairp->thost,
5152 (char *)pairp->fnetaddr,
5153 (char *)pairp->tnetaddr) < 0) {
5154 rdc_err(NULL, gettext("unable to determine IP "
5155 "addresses for hosts %s, %s"), pairp->fhost,
5156 pairp->thost);
5157 }
5158
5159 i++;
5160 }
5161
5162 cfg_close(cfg);
5163 return (i);
5164 }
5165
5166 void
5167 q_usage(int prhdr)
5168 {
5169 if (prhdr)
5170 (void) fprintf(stderr, gettext("disk queue usage:\n"));
5171
5172 (void) fprintf(stderr,
5173 gettext("\t%s -g <group> -q a <vol>\t\tadd disk queue to "
5174 "group\n"), program);
5175 (void) fprintf(stderr,
5176 gettext("\t%s -g <group> -q d \t\tremove disk queue from"
5177 " group\n"), program);
5178 (void) fprintf(stderr,
5179 gettext("\t%s -g <group> -q r <newvol>\treplace disk queue for a"
5180 " group\n"), program);
5181
5182 (void) fprintf(stderr,
5183 gettext("\t%s -q a <vol> <shost>:<sdev>\tadd disk queue to "
5184 "a set\n"), program);
5185 (void) fprintf(stderr,
5186 gettext("\t%s -q d <shost>:<sdev>\t\tremove disk queue from "
5187 "a set\n"), program);
5188 (void) fprintf(stderr,
5189 gettext("\t%s -q r <newvol> <shost>:<sdev>\treplace disk queue for "
5190 "a set\n"), program);
5191
5192 }
5193
5194 static void
5195 usage()
5196 {
5197 (void) fprintf(stderr, gettext("usage:\n"));
5198
5199 (void) fprintf(stderr,
5200 gettext("\t%s [opts] -a {on | off} [set]\t"
5201 "set autosync\n"), program);
5202
5203 (void) fprintf(stderr,
5204 gettext("\t%s [opts] -A <asyncthr> [set]\t"
5205 "set the number of asynchronous\n\t\t\t\t\t\tthreads\n"),
5206 program);
5207
5208 (void) fprintf(stderr,
5209 gettext("\t%s [opts] -d [set]\t\t\t"
5210 "disable\n"), program);
5211
5212 (void) fprintf(stderr,
5213 gettext("\t%s [opts] -e [set]\t\t\t"
5214 "enable with bits in bitmap set\n"), program);
5215
5216 (void) fprintf(stderr,
5217 gettext("\t%s [opts] -E [set]\t\t\t"
5218 "enable with bits in bitmap clear\n"), program);
5219
5220 (void) fprintf(stderr,
5221 gettext("\t%s [opts] -F <maxqfbas> [set]\t"
5222 "set maximum fbas to queue\n"), program);
5223
5224 (void) fprintf(stderr,
5225 gettext("\t%s [opts] -D {block | noblock} [set]\t"
5226 "set disk queue blocking mode\n"), program);
5227
5228 (void) fprintf(stderr,
5229 gettext("\t%s [opts] -H [set]\t\t\t"
5230 "report link health\n"), program);
5231
5232 (void) fprintf(stderr,
5233 gettext("\t%s -h\t\t\t\tusage message\n"), program);
5234
5235 (void) fprintf(stderr,
5236 gettext("\t%s -I a <master> <shadow> <bitmap>\t"
5237 "add ndr_ii config entry\n"), program);
5238
5239 (void) fprintf(stderr,
5240 gettext("\t%s -I d <master> <shadow> <bitmap>\t"
5241 "delete ndr_ii config entry\n"), program);
5242
5243 (void) fprintf(stderr,
5244 gettext("\t%s [opts] -i [set]\t\t\t"
5245 "print sets in config file format\n"), program);
5246
5247 (void) fprintf(stderr,
5248 gettext("\t%s [opts] -l [set]\t\t\t"
5249 "enter logging mode\n"), program);
5250
5251 (void) fprintf(stderr,
5252 gettext("\t%s [opts] -m [set]\t\t\t"
5253 "full sync\n"), program);
5254
5255 (void) fprintf(stderr,
5256 gettext("\t%s [opts] -m -r [set]\t\t"
5257 "full reverse sync\n"), program);
5258
5259 (void) fprintf(stderr,
5260 gettext("\t%s [opts] -P [set]\t\t\t"
5261 "print sets verbose\n"), program);
5262
5263 (void) fprintf(stderr,
5264 gettext("\t%s [opts] -p [set]\t\t\t"
5265 "print sets\n"), program);
5266
5267 (void) fprintf(stderr,
5268 gettext("\t%s [opts] -R\t\t\t"
5269 "reset error conditions\n"), program);
5270
5271 (void) fprintf(stderr,
5272 gettext("\t%s [opts] -R b p <bitmap> [set]\t"
5273 "reconfig primary bitmap\n"), program);
5274
5275 (void) fprintf(stderr,
5276 gettext("\t%s [opts] -R b s <bitmap> [set]\t"
5277 "reconfig secondary bitmap\n"), program);
5278
5279 if (clustered)
5280 (void) fprintf(stderr,
5281 gettext("\t%s [opts] -R C <ctag> [set]\t"
5282 "reconfig cluster tag\n"), program);
5283
5284 #ifdef _RDC_CAMPUS
5285 (void) fprintf(stderr,
5286 gettext("\t%s [opts] -R d <pathname> [set]\t"
5287 "reconfig campus direct file\n"), program);
5288 #endif
5289
5290 (void) fprintf(stderr,
5291 gettext("\t%s [opts] -R -f <volset-file> \t"
5292 "reconfig from file\n"), program);
5293
5294 (void) fprintf(stderr,
5295 gettext("\t%s [opts] -R g <group> [set]\t"
5296 "reconfig group\n"), program);
5297
5298 (void) fprintf(stderr,
5299 gettext("\t%s [opts] -R m {sync|async} [set]\t"
5300 "reconfig mode\n"), program);
5301
5302 if (allow_role)
5303 (void) fprintf(stderr,
5304 gettext("\t%s [opts] -R r [set]\t\t"
5305 "reverse roles\n"), program);
5306
5307 (void) fprintf(stderr,
5308 gettext("\t%s [opts] -u [set]\t\t\t"
5309 "update sync\n"), program);
5310
5311 (void) fprintf(stderr,
5312 gettext("\t%s [opts] -u -r [set]\t\t"
5313 "update reverse sync\n"), program);
5314
5315 (void) fprintf(stderr,
5316 gettext("\t%s -v\t\t\t\tdisplay version\n"), program);
5317
5318 (void) fprintf(stderr,
5319 gettext("\t%s [opts] -W <maxwrites> [set]\t"
5320 "set maximum writes to queue\n"), program);
5321
5322 (void) fprintf(stderr,
5323 gettext("\t%s [opts] -w [set]\t\t\t"
5324 "wait\n"), program);
5325 q_usage(0);
5326
5327 (void) fprintf(stderr, gettext("\nopts:\n"));
5328 (void) fprintf(stderr, gettext("\t-n\t\tnon-interactive mode "
5329 "(not valid for print operations)\n"));
5330 (void) fprintf(stderr, gettext(
5331 "\t-g <group>\toperate on sets in group only "
5332 "(not valid for enable\n\t\t\toperations)\n"));
5333 if (clustered)
5334 (void) fprintf(stderr,
5335 gettext("\t-C <ctag>\tignore sets not in cluster ctag "
5336 "(not valid for enable\n\t\t\toperations)\n"));
5337
5338 (void) fprintf(stderr, gettext("\nset:\n"));
5339 if (clustered)
5340 (void) fprintf(stderr,
5341 gettext("\t<phost> <pdev> <pbmp> "
5342 #ifdef _RDC_CAMPUS
5343 "<shost> <sdev> <sbmp> {ip | <directfile>} "
5344 #else
5345 "<shost> <sdev> <sbmp> ip "
5346 #endif
5347 "\\\n\t\t{sync | async} [g <group>] [q <qdev>] "
5348 "[C <ctag>]\n"));
5349 else
5350 (void) fprintf(stderr,
5351 gettext("\t<phost> <pdev> <pbmp> "
5352 #ifdef _RDC_CAMPUS
5353 "<shost> <sdev> <sbmp> {ip | <directfile>} "
5354 #else
5355 "<shost> <sdev> <sbmp> ip "
5356 #endif
5357 "\\\n\t\t{sync | async} [g <group>] [q <qdev>]\n"));
5358 (void) fprintf(stderr,
5359 gettext("\t<shost>:<sdev>\t\t"
5360 "operate on set matching shost and sdev\n"));
5361 (void) fprintf(stderr,
5362 gettext("\t-f volset-file\t\t"
5363 "operate on all sets specified in config file\n"
5364 "\t\t\t\tnote: not valid for single set operations. See\n"
5365 "\t\t\t\t%s(1RDC).\n"), program);
5366 (void) fprintf(stderr,
5367 gettext("\t<no arg>\t\toperate on all configured sets\n"));
5368 }
5369
5370 int
5371 prompt_user(int flag, int options)
5372 {
5373 int c;
5374
5375 switch (flag) {
5376 case RDC_CMD_DISABLE:
5377 (void) printf(gettext("Disable Remote Mirror? (Y/N) [N]: "));
5378 break;
5379 case RDC_CMD_ENABLE:
5380 (void) printf(gettext("Enable Remote Mirror? (Y/N) [N]: "));
5381 break;
5382 case RDC_CMD_HEALTH:
5383 (void) printf(gettext("Report Remote Mirror link health? (Y/N)"
5384 "[N]: "));
5385 break;
5386 case RDC_CMD_COPY:
5387 if (options & RDC_OPT_FULL) {
5388 if (options & RDC_OPT_REVERSE)
5389 (void) printf(gettext("Overwrite primary with"
5390 " secondary? (Y/N) [N]: "));
5391 else
5392 (void) printf(gettext("Overwrite secondary with"
5393 " primary? (Y/N) [N]: "));
5394 } else {
5395 if (options & RDC_OPT_REVERSE)
5396 (void) printf(gettext("Refresh primary with"
5397 " secondary? (Y/N) [N]: "));
5398 else
5399 (void) printf(gettext("Refresh secondary with"
5400 " primary? (Y/N) [N]: "));
5401 }
5402 break;
5403 case RDC_CMD_RECONFIG:
5404 (void) printf(gettext(
5405 "Perform Remote Mirror reconfiguration? (Y/N) [N]: "));
5406 break;
5407 case RDC_CMD_RESET:
5408 (void) printf(gettext("Perform Remote Mirror reset? (Y/N) "
5409 "[N]: "));
5410 break;
5411 case RDC_CMD_TUNABLE:
5412 (void) printf(gettext("Change Remote Mirror tunable? (Y/N) "
5413 "[N]: "));
5414 break;
5415 case RDC_CMD_LOG:
5416 (void) printf(gettext(
5417 "Put Remote Mirror into logging mode? (Y/N) [N]: "));
5418 break;
5419 case RDC_CMD_WAIT:
5420 (void) printf(gettext(
5421 "Wait for Remote Mirror sync completion? (Y/N) [N]: "));
5422 break;
5423 default:
5424 (void) printf(gettext("Perform Remote Mirror operation? (Y/N) "
5425 "[N]: "));
5426 }
5427
5428 c = getchar();
5429 if ((c != 'y') && (c != 'Y')) {
5430 (void) printf("\n");
5431 return (-1);
5432 }
5433 return (0);
5434 }
5435
5436 static void
5437 load_rdc_vols(CFGFILE *cfg)
5438 {
5439 int set;
5440 char key[ CFG_MAX_KEY ];
5441 char buf[ CFG_MAX_BUF ];
5442 _sd_dual_pair_t pair;
5443 char *vol, *bmp;
5444 char *host1 = pair.fhost, *host2 = pair.thost;
5445 char *diskqueue = pair.diskqueue;
5446 volcount_t *volcount;
5447 char lghn[ MAX_RDC_HOST_SIZE ];
5448
5449 if (volhash) {
5450 return;
5451 }
5452
5453 cfg_rewind(cfg, CFG_SEC_CONF);
5454 volhash = nsc_create_hash();
5455 for (set = 1; /*CSTYLED*/; set++) {
5456 (void) snprintf(key, CFG_MAX_KEY, "sndr.set%d", set);
5457 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF)) {
5458 break;
5459 }
5460
5461 if (parse_cfg_buf(buf, &pair, lghn))
5462 continue;
5463 vol = pair.ffile;
5464 bmp = pair.fbitmap;
5465
5466 /* use lghn if possible */
5467 if (*lghn) {
5468 if (strcmp(host2, lghn) == 0) {
5469 vol = pair.tfile;
5470 bmp = pair.tbitmap;
5471 }
5472 } else if (!self_check(host1)) {
5473 /* next one had better be ours */
5474 vol = pair.tfile;
5475 bmp = pair.tbitmap;
5476
5477 if (!self_check(host2)) {
5478 rdc_warn(NULL,
5479 gettext("config error: neither %s nor %s"
5480 " is localhost"), host1, host2);
5481 continue;
5482 }
5483 }
5484
5485 /* primary vol may be used more than once */
5486 volcount = (volcount_t *)nsc_lookup(volhash, vol);
5487 if (volcount) {
5488 volcount->count++;
5489 } else {
5490 volcount = (volcount_t *)malloc(sizeof (volcount_t));
5491 volcount->count = 1;
5492 (void) nsc_insert_node(volhash, volcount, vol);
5493 }
5494
5495 /* bitmap ought to be only used once */
5496 volcount = (volcount_t *)nsc_lookup(volhash, bmp);
5497 if (volcount) {
5498 /* argh */
5499 volcount->count++;
5500 } else {
5501 volcount = (volcount_t *)malloc(sizeof (volcount_t));
5502 volcount->count = 1;
5503 (void) nsc_insert_node(volhash, volcount, bmp);
5504 }
5505
5506 if (strcmp(diskqueue, place_holder) == 0)
5507 continue;
5508 /* diskqueue vol may be used more than once */
5509 volcount = (volcount_t *)nsc_lookup(volhash, diskqueue);
5510 if (volcount) {
5511 volcount->count++;
5512 } else {
5513 volcount = (volcount_t *)malloc(sizeof (volcount_t));
5514 volcount->count = 1;
5515 (void) nsc_insert_node(volhash, volcount, diskqueue);
5516 }
5517 }
5518 }
5519
5520 static void
5521 unload_rdc_vols()
5522 {
5523 nsc_remove_all(volhash, free);
5524 volhash = 0;
5525 }
5526
5527 static int
5528 perform_autosv()
5529 {
5530 if (!clustered) {
5531 return (1);
5532 } else {
5533 return (cfg_issuncluster());
5534 }
5535 }
5536
5537 /*
5538 * Check the user supplied fields against those in the dscfg for
5539 * this set.
5540 * Never returns on an error.
5541 */
5542 static void
5543 checkgfields(CFGFILE *cfg, int setnumber, char *fromhost, char *fromfile,
5544 char *frombitmap, char *tobitmap, char *type, char *mode, char *group,
5545 char *ctag, char *diskq)
5546 {
5547 if (fromhost[0])
5548 checkgfield(cfg, setnumber, "phost",
5549 gettext("primary host"), fromhost);
5550 if (fromfile[0])
5551 checkgfield(cfg, setnumber, "primary",
5552 gettext("primary volume"), fromfile);
5553 if (frombitmap[0])
5554 checkgfield(cfg, setnumber, "pbitmap",
5555 gettext("primary bitmap"), frombitmap);
5556 if (tobitmap[0])
5557 checkgfield(cfg, setnumber, "sbitmap",
5558 gettext("secondary bitmap"), tobitmap);
5559 if (type[0])
5560 checkgfield(cfg, setnumber, "type",
5561 gettext("type of connection"), type);
5562 if (mode[0])
5563 checkgfield(cfg, setnumber, "mode",
5564 gettext("mode of connection"), mode);
5565 if (group[0])
5566 checkgfield(cfg, setnumber, "group",
5567 gettext("group"), group);
5568 if (ctag[0])
5569 checkgfield(cfg, setnumber, "cnode",
5570 gettext("cluster tag"), ctag);
5571 if (diskq[0])
5572 checkgfield(cfg, setnumber, "diskq",
5573 gettext("disk queue volume"), diskq);
5574 }
5575
5576 /*
5577 * Check the 'fname' field in the dscfg file for set number 'setnumber'
5578 * If it does not match the user's data, 'data', then print the error
5579 * message using the friendly field name 'ufield'.
5580 * Never returns on an error.
5581 */
5582 static void
5583 checkgfield(CFGFILE *cfg, int setnumber, char *fname, char *ufield, char *data)
5584 {
5585 char buf[CFG_MAX_BUF];
5586 char key[CFG_MAX_KEY];
5587
5588 (void) snprintf(key, sizeof (key), "sndr.set%d.%s", setnumber, fname);
5589 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
5590 rdc_err(NULL, gettext("unable to fetch data for key %s"),
5591 key);
5592 }
5593 if (strcmp(buf, data) != 0) {
5594 rdc_err(NULL,
5595 gettext("the value specified for the %s field is not\nthe "
5596 "same as that contained within the configuration storage "
5597 "file for this set.\nYou specified \"%s\" "
5598 "expected \"%s\"."),
5599 ufield, data, buf);
5600 }
5601 }
5602
5603 /*
5604 * load and send the contents of the bitmap file to the kernel.
5605 */
5606 static int
5607 rdc_bitmapset(char *tohost, char *tofile, char *bitmap, int op,
5608 nsc_off_t offset)
5609 {
5610 rdc_bitmap_op_t bmop;
5611 int fd;
5612 void *buffer;
5613 int buffersz;
5614 struct stat s;
5615 int n;
5616 int ret;
5617 /*
5618 * open bitmap file for reading.
5619 */
5620 if ((fd = open(bitmap, O_RDONLY)) < 0) {
5621 rdc_warn(NULL, gettext("Unable to open bitmap file %s"),
5622 bitmap);
5623 return (1);
5624 }
5625 (void) fstat(fd, &s);
5626
5627 if (S_ISREG(s.st_mode) == 0) {
5628 rdc_warn(NULL, gettext("Bitmap %s is not a regular file"),
5629 bitmap);
5630 (void) close(fd);
5631 return (1);
5632 }
5633
5634 if (op == 0) {
5635 op = RDC_BITMAPOR;
5636 }
5637 /*
5638 * use the file size to allocate buffer. This
5639 * size should be a multiple of FBA, but don't check
5640 * it here.
5641 */
5642 buffersz = s.st_size;
5643 buffer = malloc(buffersz);
5644 if (buffer == NULL) {
5645 rdc_warn(NULL, gettext("Unable to allocate %d bytes "
5646 "for bitmap file %s"), buffersz, bitmap);
5647 (void) close(fd);
5648 return (1);
5649 }
5650 n = read(fd, buffer, buffersz);
5651 (void) close(fd);
5652 if (n != buffersz) {
5653 rdc_warn(NULL, gettext("Unable to read the bitmap file, "
5654 "read returned %d instead of %d"),
5655 n, buffersz);
5656 free(buffer);
5657 return (1);
5658 }
5659 bmop.offset = offset;
5660 bmop.op = op;
5661 (void) strncpy(bmop.sechost, tohost, MAX_RDC_HOST_SIZE);
5662 (void) strncpy(bmop.secfile, tofile, NSC_MAXPATH);
5663 bmop.len = buffersz;
5664 bmop.addr = (unsigned long)buffer;
5665 ret = rdc_ioctl_simple(RDC_BITMAPOP, &bmop);
5666 free(buffer);
5667 if (ret < 0) {
5668 rdc_warn(NULL, gettext("Setting bitmap ioctl failed for set "
5669 "%s:%s"), tohost, tofile);
5670
5671 switch (errno) {
5672 case EIO:
5673 rdc_warn(NULL, gettext("One of the sets is not "
5674 "enabled"));
5675 break;
5676 case ENXIO:
5677 rdc_warn(NULL, gettext("One of the sets is not "
5678 "logging"));
5679 break;
5680 default:
5681 break;
5682 }
5683 } else {
5684 ret = 0;
5685 }
5686 if (ret)
5687 ret = 1;
5688 return (ret);
5689 }
5690
5691 /*
5692 * verify_groupname: Check the group name for the following rules:
5693 * 1. The name does not start with a '-'
5694 * 2. The name does not contain any space characters as defined by
5695 * isspace(3C).
5696 *
5697 * If either of these rules are broken, error immediately.
5698 */
5699 static void
5700 verify_groupname(char *grp)
5701 {
5702 int i;
5703
5704 if (grp[0] == '-') {
5705 rdc_err(NULL, gettext("group name cannot start with a '-'"));
5706 }
5707
5708 for (i = 0; grp[i] != '\0'; i++) {
5709 if (isspace(grp[i])) {
5710 rdc_err(NULL, gettext("group name cannot contain a "
5711 "space"));
5712 }
5713 }
5714 }
5715