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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 /* FALLTHROUGH */
2215 default:
2216 usage();
2217 exit(1);
2218 }
2219 }
2220 }
2221 if (fflag) {
2222 checksetfields = 1;
2223 if ((argc - optind) != 0) {
2224 usage();
2225 exit(1);
2226 }
2227 } else {
2228 if ((argc - optind) == 0) {
2229 /* Use libcfg to figure out what to operate on */
2230 cfgflag = 1;
2231 #ifdef DEBUG
2232 rdc_warn(NULL, gettext("using current config"));
2233 #endif
2234 checksetfields = 0;
2235 } else {
2236 if ((argc - optind) < 8 && (argc - optind) != 1) {
2237 usage();
2238 exit(1);
2239 }
2240 }
2241 }
2242
2243 if (cfgflag) {
2244 if (flag == RDC_CMD_ADDQ ||
2245 flag == RDC_CMD_REMQ ||
2246 flag == RDC_CMD_KILLQ ||
2247 flag == RDC_CMD_INITQ) {
2248 rdc_err(NULL, gettext("can not use current config "
2249 "for disk queue operations"));
2250 }
2251 } else if (fflag) {
2252 if (flag == RDC_CMD_ADDQ ||
2253 flag == RDC_CMD_REMQ ||
2254 flag == RDC_CMD_KILLQ ||
2255 flag == RDC_CMD_INITQ) {
2256 rdc_err(NULL, gettext("can not use a config file "
2257 "for disk queue operations"));
2258 }
2259 }
2260 if (cfgflag) {
2261 if (flag == RDC_CMD_ENABLE) {
2262 rdc_err(NULL, gettext("can not use current config "
2263 "for enable command"));
2264 }
2265 if ((flag == RDC_CMD_RECONFIG) && (reconfig_pbitmap ||
2266 reconfig_sbitmap)) {
2267 rdc_err(NULL, gettext("can not use current config "
2268 "for bitmap reconfiguration"));
2269 }
2270 if (flag == RDC_BITMAPOP) {
2271 rdc_err(NULL, gettext("can not use current config "
2272 "for bitmap set command"));
2273 }
2274 pairs = read_libcfg(flag, group_arg, ctag_arg);
2275 if (pairs == 0) {
2276 (void) fprintf(stderr,
2277 gettext("no matching Remote Mirror sets found "
2278 "in config\n"));
2279 exit(1);
2280 }
2281 } else if (!fflag) {
2282 /*
2283 * Format is either:
2284 *
2285 * tohost:tofile
2286 *
2287 * or something like this for example:
2288 *
2289 * fromhost fromfile frombitmap tohost tofile tobitmap ip sync
2290 * g group C ctag
2291 */
2292
2293 if (argc - optind == 1) {
2294 char tohost_arg[MAX_RDC_HOST_SIZE];
2295 char tofile_arg[NSC_MAXPATH];
2296 char *ptr;
2297
2298 checksetfields = 0;
2299 if (flag == RDC_CMD_ENABLE) {
2300 rdc_err(NULL,
2301 gettext("must specify full set details for "
2302 "enable command"));
2303 }
2304 ptr = strtok(argv[optind], ":");
2305 if (ptr)
2306 (void) strncpy(tohost_arg, ptr,
2307 MAX_RDC_HOST_SIZE);
2308 else {
2309 rdc_err(NULL, gettext("Bad host specified"));
2310 }
2311 ptr = strtok(NULL, ":");
2312 if (ptr)
2313 (void) strncpy(tofile_arg, ptr, NSC_MAXPATH);
2314 else {
2315 rdc_err(NULL, gettext("Bad set specified"));
2316 }
2317
2318 /* Now look up tohost:tofile via libcfg */
2319
2320 if ((cfg = cfg_open(NULL)) == NULL)
2321 rdc_err(NULL,
2322 gettext("unable to access configuration"));
2323
2324 if (!cfg_lock(cfg, CFG_RDLOCK))
2325 rdc_err(NULL,
2326 gettext("unable to lock configuration"));
2327
2328 setnumber = 0;
2329 found = 0;
2330 /*CSTYLED*/
2331 for (i = 0; i < rdc_maxsets;) {
2332 setnumber++;
2333
2334 bzero(buf, CFG_MAX_BUF);
2335 (void) snprintf(key, sizeof (key),
2336 "sndr.set%d", setnumber);
2337 rc = cfg_get_cstring(cfg, key, buf,
2338 CFG_MAX_BUF);
2339 if (rc < 0)
2340 break;
2341
2342 (void) snprintf(key, sizeof (key),
2343 "sndr.set%d.shost", setnumber);
2344 (void) cfg_get_cstring(cfg, key, tohost,
2345 sizeof (tohost));
2346 if (strncmp(tohost, tohost_arg, NSC_MAXPATH))
2347 continue;
2348
2349 (void) snprintf(key, sizeof (key),
2350 "sndr.set%d.secondary", setnumber);
2351 (void) cfg_get_cstring(cfg, key, tofile,
2352 sizeof (tofile));
2353 if (strncmp(tofile, tofile_arg, NSC_MAXPATH))
2354 continue;
2355
2356 found = 1;
2357
2358 (void) snprintf(key, sizeof (key),
2359 "sndr.set%d.phost", setnumber);
2360 (void) cfg_get_cstring(cfg, key, fromhost,
2361 sizeof (fromhost));
2362
2363 (void) snprintf(key, sizeof (key),
2364 "sndr.set%d.primary", setnumber);
2365 (void) cfg_get_cstring(cfg, key, fromfile,
2366 sizeof (fromfile));
2367
2368 (void) snprintf(key, sizeof (key),
2369 "sndr.set%d.pbitmap", setnumber);
2370 (void) cfg_get_cstring(cfg, key, frombitmap,
2371 sizeof (frombitmap));
2372
2373 (void) snprintf(key, sizeof (key),
2374 "sndr.set%d.sbitmap", setnumber);
2375 (void) cfg_get_cstring(cfg, key, tobitmap,
2376 sizeof (tobitmap));
2377
2378 (void) snprintf(key, sizeof (key),
2379 "sndr.set%d.type", setnumber);
2380 (void) cfg_get_cstring(cfg, key, directfile,
2381 sizeof (directfile));
2382 if (strcmp(directfile, "ip") == 0)
2383 (void) strcpy(directfile, "");
2384
2385 (void) snprintf(key, sizeof (key),
2386 "sndr.set%d.mode", setnumber);
2387 (void) cfg_get_cstring(
2388 cfg, key, mode, sizeof (mode));
2389
2390 (void) snprintf(key, sizeof (key),
2391 "sndr.set%d.group", setnumber);
2392 (void) cfg_get_cstring(cfg, key, group,
2393 sizeof (group));
2394 if (strcmp(group_arg, "") &&
2395 strncmp(group_arg, group, NSC_MAXPATH))
2396 continue;
2397 (void) snprintf(key, sizeof (key),
2398 "sndr.set%d.cnode", setnumber);
2399 (void) cfg_get_cstring(
2400 cfg, key, ctag, sizeof (ctag));
2401 if ((strlen(ctag_arg) > 0) &&
2402 (strcmp(ctag_arg, ctag) != 0))
2403 rdc_err(NULL,
2404 gettext("ctags %s and %s "
2405 "do not match"), ctag_arg, ctag);
2406
2407 if (strcmp(mode, "sync") == 0)
2408 doasync = 0;
2409 else if (strcmp(mode, "async") == 0)
2410 doasync = 1;
2411 else {
2412 rdc_err(NULL,
2413 gettext("set %s:%s neither sync "
2414 "nor async"), tohost, tofile);
2415 }
2416 break;
2417 }
2418 cfg_close(cfg);
2419 if (!found) {
2420 rdc_err(NULL,
2421 gettext("set %s:%s not found in config"),
2422 tohost_arg, tofile_arg);
2423 }
2424 } else {
2425 checksetfields = 1;
2426 (void) strncpy(fromhost, argv[optind],
2427 MAX_RDC_HOST_SIZE);
2428 (void) strncpy(fromfile, argv[optind+1], NSC_MAXPATH);
2429 (void) strncpy(frombitmap, argv[optind+2], NSC_MAXPATH);
2430 (void) strncpy(tohost, argv[optind+3],
2431 MAX_RDC_HOST_SIZE);
2432 (void) strncpy(tofile, argv[optind+4], NSC_MAXPATH);
2433 (void) strncpy(tobitmap, argv[optind+5], NSC_MAXPATH);
2434
2435 /* Check the length of entries from the command line */
2436 if ((fromhost[MAX_RDC_HOST_SIZE - 1] != '\0') ||
2437 (tohost[MAX_RDC_HOST_SIZE - 1] != '\0')) {
2438 rdc_err(NULL,
2439 gettext("hostname is longer than %d "
2440 "characters\n"), (MAX_RDC_HOST_SIZE - 1));
2441 }
2442
2443 /* Check if it's ip address -- not allowed */
2444 if ((inet_addr(fromhost) != (in_addr_t)(-1)) ||
2445 (inet_addr(tohost) != (in_addr_t)(-1))) {
2446 rdc_err(NULL, gettext(
2447 "The hostname specified is invalid.\n"
2448 "See 'man inet(3SOCKET)'"));
2449 }
2450
2451 if ((fromfile[NSC_MAXPATH - 1] != '\0') ||
2452 (tofile[NSC_MAXPATH - 1] != '\0') ||
2453 (frombitmap[NSC_MAXPATH - 1] != '\0') ||
2454 (tobitmap[NSC_MAXPATH - 1] != '\0')) {
2455 rdc_err(NULL, gettext("device name is longer "
2456 "than %d characters\n"), (NSC_MAXPATH - 1));
2457 }
2458 #ifdef _RDC_CAMPUS
2459 if (argv[optind+6][0] == '/') {
2460 /* FCAL directio */
2461 (void) strncpy(directfile, argv[optind+6],
2462 NSC_MAXPATH);
2463 } else if (strcmp(argv[optind+6], "ip") != 0) {
2464 #else
2465 if (strcmp(argv[optind+6], "ip") != 0) {
2466 #endif
2467 usage();
2468 exit(1);
2469 } else
2470 (void) strcpy(directfile, "ip");
2471
2472 if (strcmp(argv[optind+7], "sync") == 0)
2473 doasync = 0;
2474 else if (strcmp(argv[optind+7], "async") == 0)
2475 doasync = 1;
2476 else {
2477 usage();
2478 exit(1);
2479 }
2480
2481 /*
2482 * At this point, we could have a set which is
2483 * clustered, but neither a 'C ctag' or '-C ctag' has
2484 * been specified. To avoid clobbering the ctag if a
2485 * dscfg operation is done in the future, we should get
2486 * the ctag out of the config at this point. To do this,
2487 * set the cluster resource filter to NULL to look at
2488 * all sets in the config, pulling out the ctag for the
2489 * set matching shost:svol. If the set is not found,
2490 * fail here. Note, we skip this set on an enable as the
2491 * set is not yet in the config, so no need to waste
2492 * time.
2493 */
2494 if ((argc - optind == 8) && clustered &&
2495 (flag != RDC_CMD_ENABLE)) {
2496 int setnumber;
2497 char key[CFG_MAX_KEY];
2498
2499 if ((cfg = cfg_open(NULL)) == NULL) {
2500 rdc_err(NULL,
2501 gettext("unable to access configuration"));
2502 }
2503 if (!cfg_lock(cfg, CFG_RDLOCK)) {
2504 rdc_err(NULL,
2505 gettext("unable to lock configuration"));
2506 }
2507
2508 cfg_resource(cfg, NULL);
2509
2510 if ((setnumber =
2511 find_setnumber_in_libcfg(cfg, NULL, tohost,
2512 tofile)) < 0) {
2513 cfg_close(cfg);
2514 rdc_err(NULL,
2515 gettext("unable to find Remote "
2516 "Mirror set "
2517 "%s:%s in config"),
2518 tohost, tofile);
2519 }
2520
2521 (void) snprintf(key, sizeof (key),
2522 "sndr.set%d.cnode", setnumber);
2523 if (cfg_get_cstring(cfg, key, ctag_arg,
2524 MAX_RDC_HOST_SIZE) < 0) {
2525 cfg_close(cfg);
2526 rdc_err(NULL,
2527 gettext("unable to determine ctag "
2528 "for Remote Mirror set %s:%s"),
2529 tohost, tofile);
2530 }
2531
2532 rdc_islocal = strcmp(ctag_arg, "-") ? 0 : 1;
2533
2534 cfg_close(cfg);
2535 }
2536
2537 extra_argc = argc - optind;
2538 if (extra_argc < 8 || extra_argc > 14 ||
2539 extra_argc % 2 != 0) {
2540 usage();
2541 exit(1);
2542 }
2543
2544 /*
2545 * Loop through all of the extra arguments specified
2546 * on the command line, setting the appropriate values
2547 * for valid entries. If an unrecognized argument is
2548 * detected, abort with error. Note: This hack should be
2549 * removed and we should not accept these entries as
2550 * arguments, they should be passed in as switches.
2551 */
2552 for (i = (8 + optind); i < argc; i += 2) {
2553 /* string case statement */
2554 if (strcmp(argv[i], "g") == 0) {
2555 (void) strncpy(group, argv[i + 1],
2556 NSC_MAXPATH);
2557 if (group[NSC_MAXPATH - 1] != '\0') {
2558 rdc_err(NULL, gettext("group name is "
2559 "longer than %d characters\n"),
2560 (NSC_MAXPATH - 1));
2561 }
2562 } else if (strcmp(argv[i], "C") == 0) {
2563 if (!clustered) {
2564 usage();
2565 exit(1);
2566 }
2567 (void) strncpy(ctag, argv[i + 1],
2568 MAX_RDC_HOST_SIZE);
2569
2570 if (ctag[MAX_RDC_HOST_SIZE - 1] != '\0') {
2571 rdc_err(NULL, gettext("cluster name "
2572 "is longer than %d characters\n"),
2573 (MAX_RDC_HOST_SIZE - 1));
2574 }
2575 process_clocal(ctag);
2576
2577 /*
2578 * well here is something.
2579 * what if they went sndradm -C local
2580 * host a b host a b ip sync C foobar?
2581 * they might be confused
2582 * lets stop them if ctag_arg and ctag
2583 * don't match and forgive if they are
2584 * the same, below also.
2585 */
2586 if ((strlen(ctag_arg) > 0) &&
2587 (strcmp(ctag_arg, ctag) != 0)) {
2588 rdc_err(NULL, gettext("ctags "
2589 "%s and %s do not match "),
2590 ctag_arg, ctag);
2591
2592 }
2593 } else if (strcmp(argv[i], "q") == 0) {
2594 (void) strncpy(diskqueue, argv[i + 1],
2595 NSC_MAXPATH);
2596 if (diskqueue[NSC_MAXPATH - 1] != '\0') {
2597 rdc_err(NULL, gettext("diskq name is "
2598 "longer than %d characters\n"),
2599 (NSC_MAXPATH - 1));
2600 }
2601 } else {
2602 /* Unrecognized argument */
2603 usage();
2604 exit(1);
2605 }
2606 }
2607 }
2608
2609 /*
2610 * Are we able to determine the existance of either
2611 * of these host addresses?
2612 */
2613 if (gethost_netaddrs(fromhost, tohost,
2614 (char *)&fromnetaddr, (char *)&tonetaddr) < 0) {
2615 (void) fprintf(stderr, "\n");
2616 rdc_warn(NULL, gettext("unable to determine IP "
2617 "addresses for either host %s or host %s"),
2618 fromhost, tohost);
2619
2620 if (flag != RDC_CMD_DISABLE)
2621 exit(1);
2622 else
2623 host_not_found = 1;
2624 }
2625
2626 /*
2627 * Are we running on neither host?
2628 */
2629 if (!self_check(fromhost) && !self_check(tohost)) {
2630 if (flag == RDC_CMD_DISABLE) {
2631 (void) fprintf(stderr, "\n");
2632 rdc_warn(NULL, gettext("Not running on either host "
2633 "%s or host %s"), fromhost, tohost);
2634 host_not_found = 1;
2635 }
2636 }
2637
2638 /*
2639 * at this point, hopfully it is safe to say that
2640 * if a ctag was supplied via -C tag it is safe to
2641 * move it from ctag_arg to ctag. If it was passed in
2642 * at the end and the beginning of the cli, it must
2643 * match, as per checks above. if it was not passed
2644 * in at the end, but at the beginning, we can deal.
2645 * this should handle the case of shost:svol.
2646 * which is the main reason for this.
2647 *
2648 * there are 3 cases: passed in by cli, checked just above.
2649 * using libdscfg, you must pass in -C tag to have
2650 * ctag_check pass.
2651 * finally a file. same rules as libdscfg.
2652 */
2653 if ((strlen(ctag) == 0) && (strlen(ctag_arg) > 0))
2654 (void) strcpy(ctag, ctag_arg);
2655
2656 if (flag == RDC_CMD_RECONFIG) {
2657 if (reconfig_pbitmap) {
2658 (void) strncpy(frombitmap, reconfig_pbitmap,
2659 NSC_MAXPATH);
2660 check_rdcbitmap(flag, fromhost, frombitmap);
2661 }
2662 if (reconfig_sbitmap) {
2663 (void) strncpy(tobitmap, reconfig_sbitmap,
2664 NSC_MAXPATH);
2665 check_rdcbitmap(flag, tohost, tobitmap);
2666 }
2667 #ifdef _RDC_CAMPUS
2668 if (reconfig_direct)
2669 (void) strncpy(directfile, reconfig_direct,
2670 NSC_MAXPATH);
2671 #endif
2672 if (reconfig_group)
2673 (void) strncpy(group, reconfig_group,
2674 NSC_MAXPATH);
2675
2676 if (strlen(reconfig_ctag) > 0)
2677 (void) strncpy(ctag, reconfig_ctag,
2678 MAX_RDC_HOST_SIZE);
2679 if (reconfig_doasync != -1)
2680 doasync = reconfig_doasync;
2681 }
2682
2683 if (flag == RDC_CMD_ENABLE || flag == RDC_CMD_RECONFIG) {
2684 if (ctag_check(fromhost, fromfile, frombitmap,
2685 tohost, tofile, tobitmap, ctag, diskqueue) < 0)
2686 exit(1);
2687 if ((diskq_group = check_diskqueue(NULL, diskqueue,
2688 group)) == DISKQ_FAIL) {
2689 rdc_err(NULL, gettext("disk queue %s is "
2690 "incompatible with existing queue"),
2691 diskqueue);
2692 }
2693
2694 }
2695 pairs = 1;
2696 } else {
2697 pairs = read_config(flag, config_file, group_arg, ctag_arg);
2698 if (pairs == 0) {
2699 rdc_err(NULL, gettext("%s contains no "
2700 "matching Remote Mirror sets"), config_file);
2701 }
2702 }
2703
2704 if (!nflag && !pflag && prompt_user(flag, iflag) == -1)
2705 exit(1);
2706
2707 while (pairs--) {
2708
2709 if (cfgflag || fflag) {
2710 (void) strncpy(fromfile, pair_list[pairs].ffile,
2711 NSC_MAXPATH);
2712 (void) strncpy(tofile, pair_list[pairs].tfile,
2713 NSC_MAXPATH);
2714 (void) strncpy(frombitmap, pair_list[pairs].fbitmap,
2715 NSC_MAXPATH);
2716 (void) strncpy(fromhost,
2717 pair_list[pairs].fhost, MAX_RDC_HOST_SIZE);
2718 (void) strncpy(tohost, pair_list[pairs].thost,
2719 MAX_RDC_HOST_SIZE);
2720 (void) strncpy(tobitmap, pair_list[pairs].tbitmap,
2721 NSC_MAXPATH);
2722 (void) strncpy(directfile, pair_list[pairs].directfile,
2723 NSC_MAXPATH);
2724 (void) strncpy(group, pair_list[pairs].group,
2725 NSC_MAXPATH);
2726 (void) strncpy(ctag, pair_list[pairs].ctag,
2727 MAX_RDC_HOST_SIZE);
2728 (void) strncpy(diskqueue, pair_list[pairs].diskqueue,
2729 NSC_MAXPATH);
2730
2731 bcopy(pair_list[pairs].fnetaddr, fromnetaddr,
2732 RDC_MAXADDR);
2733 bcopy(pair_list[pairs].tnetaddr, tonetaddr,
2734 RDC_MAXADDR);
2735
2736 doasync = pair_list[pairs].doasync;
2737 }
2738
2739 if (pflag) {
2740 static int first = 1;
2741
2742 if (first) {
2743 if ((cfg = cfg_open(NULL)) == NULL)
2744 rdc_err(NULL,
2745 gettext("unable to access configuration"));
2746
2747 if (!cfg_lock(cfg, CFG_RDLOCK))
2748 rdc_err(NULL,
2749 gettext("unable to lock configuration"));
2750
2751 first = 0;
2752 }
2753
2754 (void) rdc_print(file_format, verbose,
2755 group_arg, ctag_arg, tohost, tofile, cfg);
2756
2757 if (pairs == 0) {
2758 cfg_close(cfg);
2759 exit(0);
2760 }
2761
2762 /* short circuit the rest of the command loop */
2763 continue;
2764 }
2765 if (Bflag) {
2766 int ret;
2767 ret = rdc_bitmapset(tohost, tofile, bitfile, oflag,
2768 boffset);
2769 exit(ret);
2770 }
2771 if ((fflag || cfgflag) && flag == RDC_CMD_RECONFIG) {
2772 char orig_fbmp[MAXHOSTNAMELEN];
2773 char orig_tbmp[MAXHOSTNAMELEN];
2774 int ret;
2775 rdc_config_t parms;
2776 spcs_s_info_t ustatus;
2777
2778 parms.command = RDC_CMD_STATUS;
2779 parms.rdc_set->netconfig = NULL;
2780 (void) strncpy(parms.rdc_set->primary.intf, fromhost,
2781 MAX_RDC_HOST_SIZE);
2782 (void) strncpy(parms.rdc_set->secondary.intf, tohost,
2783 MAX_RDC_HOST_SIZE);
2784 (void) strncpy(parms.rdc_set->primary.file, fromfile,
2785 NSC_MAXPATH);
2786 (void) strncpy(parms.rdc_set->secondary.file, tofile,
2787 NSC_MAXPATH);
2788 ustatus = spcs_s_ucreate();
2789 ret = RDC_IOCTL(RDC_CONFIG, &parms,
2790 NULL, 0, 0, 0, ustatus);
2791 if (ret != SPCS_S_OK) {
2792 rdc_err(NULL, gettext("unable to get set status"
2793 " before reconfig operation"));
2794 }
2795 (void) strncpy(orig_fbmp, parms.rdc_set->primary.bitmap,
2796 NSC_MAXPATH);
2797 (void) strncpy(orig_tbmp,
2798 parms.rdc_set->secondary.bitmap, NSC_MAXPATH);
2799
2800 if (strncmp(orig_fbmp, frombitmap, NSC_MAXPATH) != 0)
2801 check_rdcbitmap(flag, fromhost, frombitmap);
2802 if (strncmp(orig_tbmp, tobitmap, NSC_MAXPATH) != 0)
2803 check_rdcbitmap(flag, tohost, tobitmap);
2804 spcs_s_ufree(&ustatus);
2805
2806 }
2807 /*
2808 * take a peek in the config to see if
2809 * the bitmap is being used elsewhere
2810 */
2811 if (flag == RDC_CMD_ENABLE) {
2812 struct stat stb;
2813 /*
2814 * just for fun, lets see if some silly person
2815 * specified the same vol and bitmap
2816 */
2817 if ((strcmp(fromfile, frombitmap) == 0) ||
2818 (strcmp(tofile, tobitmap) == 0))
2819 rdc_err(NULL, gettext("volumes and bitmaps"
2820 " must not match"));
2821 if (self_check(fromhost)) {
2822 check_rdcbitmap(flag, fromhost, frombitmap);
2823 if (stat(fromfile, &stb) != 0) {
2824 rdc_err(NULL,
2825 gettext("unable to access %s: %s"),
2826 fromfile, strerror(errno));
2827 }
2828 if (!S_ISCHR(stb.st_mode)) {
2829 rdc_err(NULL,
2830 gettext("%s is not a character device"),
2831 fromfile);
2832 }
2833 } else { /* on the secondary */
2834 check_rdcbitmap(flag, tohost, tobitmap);
2835 /* extra check for secondary vol */
2836 check_rdcsecondary(tofile);
2837 if (stat(tofile, &stb) != 0) {
2838 rdc_err(NULL,
2839 gettext("unable to access %s: %s"),
2840 tofile, strerror(errno));
2841 }
2842 if (!S_ISCHR(stb.st_mode)) {
2843 rdc_err(NULL,
2844 gettext("%s is not a character device"),
2845 tofile);
2846 }
2847 }
2848
2849 }
2850
2851 if (flag == RDC_CMD_ENABLE || flag == RDC_CMD_DISABLE ||
2852 flag == RDC_CMD_RECONFIG) {
2853 if ((cfg = cfg_open(NULL)) == NULL)
2854 rdc_err(NULL,
2855 gettext("unable to access configuration"));
2856
2857 if (!cfg_lock(cfg, CFG_WRLOCK))
2858 rdc_err(NULL,
2859 gettext("unable to lock configuration"));
2860
2861 cfg_resource(cfg, clustered ? ctag : NULL);
2862 } else
2863 cfg = NULL;
2864
2865 if (cfg && perform_autosv() &&
2866 (flag == RDC_CMD_ENABLE || flag == RDC_CMD_DISABLE ||
2867 flag == RDC_CMD_RECONFIG)) {
2868 if (cfg_load_svols(cfg) < 0 ||
2869 cfg_load_dsvols(cfg) < 0 ||
2870 cfg_load_shadows(cfg) < 0)
2871 rdc_err(NULL,
2872 gettext("Unable to parse config filer"));
2873 load_rdc_vols(cfg);
2874 }
2875 cfg_success = (cfg == NULL);
2876 if (cfg && flag == RDC_CMD_ENABLE) {
2877 /* Enabled, so add the set via libcfg */
2878
2879 /* Build a new sndr entry and put it */
2880 group_p = *group? group : place_holder;
2881 diskqueue_p = *diskqueue? diskqueue : place_holder;
2882
2883 if ((diskqueue_p == place_holder) &&
2884 (group_p != place_holder)) {
2885 get_group_diskq(cfg, group_p, diskqueue);
2886 if (*diskqueue)
2887 diskqueue_p = diskqueue;
2888 }
2889
2890 /*
2891 * format in pconfig is:
2892 * phost.primary.pbitmap.shost.secondary.
2893 * sbitmap.type.mode.group.cnode.options.diskq
2894 */
2895 (void) snprintf(buf, sizeof (buf),
2896 "%s %s %s %s %s %s %s %s %s %s - %s",
2897 fromhost, fromfile, frombitmap, tohost, tofile,
2898 tobitmap, directfile,
2899 doasync? "async" : "sync", group_p,
2900 clustered? ctag : "-", diskqueue_p);
2901
2902 if (cfg_put_cstring(cfg, "sndr", buf, strlen(buf)) < 0)
2903 rdc_warn(NULL,
2904 gettext("unable to add \"%s\" to "
2905 "configuration storage: %s"),
2906 buf, cfg_error(&sev));
2907 setnumber = find_setnumber_in_libcfg(cfg, clustered?
2908 ctag : NULL, tohost, tofile);
2909 if (setnumber < 0)
2910 rdc_warn(NULL,
2911 gettext("unable to add \"%s\" to "
2912 "configuration storage: %s"),
2913 diskqueue_p, cfg_error(&sev));
2914
2915 else
2916 cfg_success = 1;
2917
2918 /* Add cluster aware info */
2919 if (clustered && !rdc_islocal) {
2920 (void) snprintf(key, sizeof (key),
2921 "sndr.set%d.options", setnumber);
2922 if (self_check(fromhost)) {
2923 if (cfg_put_options(cfg, CFG_SEC_CONF,
2924 key, "lghn", fromhost) < 0) {
2925 rdc_err(NULL,
2926 gettext("unable to add "
2927 "\"%s\" to configuration "
2928 "storage: %s"),
2929 fromhost, cfg_error(&sev));
2930 }
2931 } else if (self_check(tohost)) {
2932 if (cfg_put_options(cfg, CFG_SEC_CONF,
2933 key, "lghn", tohost) < 0) {
2934 rdc_err(NULL,
2935 gettext("unable to add "
2936 "\"%s\" to configuration "
2937 "storage: %s"),
2938 fromhost, cfg_error(&sev));
2939 }
2940 }
2941 }
2942 } else if (cfg && flag == RDC_CMD_DISABLE) {
2943 found = 0;
2944 /* Disabled, so delete the set via libcfg */
2945
2946 /* get sndr entries until shost, sfile match */
2947 for (i = 0; i < rdc_maxsets; i++) {
2948 setnumber = i + 1;
2949 (void) snprintf(key, sizeof (key), "sndr.set%d",
2950 setnumber);
2951 if (cfg_get_cstring(cfg, key, buf,
2952 CFG_MAX_BUF) < 0) {
2953 break;
2954 }
2955 (void) snprintf(key, sizeof (key),
2956 "sndr.set%d.secondary", setnumber);
2957 if (cfg_get_cstring(cfg, key, buf,
2958 CFG_MAX_BUF) < 0)
2959 break;
2960 if (strcmp(buf, tofile) != 0)
2961 continue;
2962 (void) snprintf(key, sizeof (key),
2963 "sndr.set%d.shost",
2964 setnumber);
2965 if (cfg_get_cstring(cfg, key, buf,
2966 CFG_MAX_BUF) < 0)
2967 break;
2968 if (strcmp(buf, tohost) != 0)
2969 continue;
2970 found = 1;
2971 #ifdef DEBUG
2972 if (checksetfields == -1) {
2973 rdc_err(NULL,
2974 gettext("checksetfields not set"));
2975 }
2976 #endif
2977 if (checksetfields) {
2978 checkgfields(cfg, setnumber, fromhost,
2979 fromfile, frombitmap, tobitmap,
2980 directfile, (doasync == 1)
2981 ? "async" : "sync", group, ctag,
2982 diskqueue);
2983 }
2984
2985 /* perform cluster specific options */
2986 if (clustered) {
2987 /* get the logical host, if set */
2988 (void) snprintf(key, sizeof (key),
2989 "sndr.set%d.options", setnumber);
2990 (void) cfg_get_single_option(cfg,
2991 CFG_SEC_CONF, key, "lghn",
2992 lhname, MAX_RDC_HOST_SIZE);
2993
2994 /* figure out the cluster tag, if any */
2995 (void) snprintf(key, sizeof (key),
2996 "sndr.set%d.cnode", setnumber);
2997 if (cfg_get_cstring(cfg, key, buf,
2998 CFG_MAX_BUF) < 0)
2999 break;
3000 if (strcmp(buf, ctag))
3001 rdc_err(NULL, gettext("ctags %s"
3002 " and %s do not match"),
3003 buf, ctag);
3004 } else {
3005 *lhname = '\0';
3006 *ctag = '\0';
3007 }
3008
3009 /* figure out the disk queue, if any */
3010 (void) snprintf(key, sizeof (key),
3011 "sndr.set%d.diskq",
3012 setnumber);
3013 if (cfg_get_cstring(cfg, key, buf,
3014 CFG_MAX_BUF) < 0)
3015 break;
3016 if (strlen(buf) > 0) {
3017 (void) strncpy(diskqueue, buf,
3018 NSC_MAXPATH);
3019 } else {
3020 *diskqueue = '\0';
3021 }
3022 (void) snprintf(key, sizeof (key), "sndr.set%d",
3023 setnumber);
3024 if (cfg_put_cstring(cfg, key, NULL, 0) < 0)
3025 rdc_warn(NULL,
3026 gettext("unable to remove \"%s\" "
3027 "from configuration storage: %s"),
3028 buf, cfg_error(&sev));
3029 else
3030 cfg_success = 1;
3031 break;
3032 }
3033 if (found == 0) {
3034 rdc_err(NULL,
3035 gettext("Unable to find %s:%s in "
3036 "configuration storage"),
3037 tohost, tofile);
3038 }
3039 if (host_not_found) {
3040 rdc_force_disable(cfg, fromhost, fromfile,
3041 frombitmap, tohost, tofile, tobitmap, ctag,
3042 lhname);
3043 if (cfg_commit(cfg) < 0)
3044 rdc_err(NULL, gettext("commit on "
3045 "force disable failed"));
3046 cfg_close(cfg);
3047 return (0);
3048 }
3049 } else if (cfg && flag == RDC_CMD_RECONFIG) {
3050 /* Update relevant cfg record */
3051
3052 cfg_resource(cfg, NULL);
3053
3054 /* get sndr entries until shost, sfile match */
3055 for (i = 0; i < rdc_maxsets; i++) {
3056 setnumber = i + 1;
3057 (void) snprintf(key, sizeof (key), "sndr.set%d",
3058 setnumber);
3059 if (cfg_get_cstring(cfg, key, buf,
3060 CFG_MAX_BUF) < 0) {
3061 break;
3062 }
3063 (void) snprintf(key, sizeof (key),
3064 "sndr.set%d.secondary", setnumber);
3065 if (cfg_get_cstring(cfg, key, buf,
3066 CFG_MAX_BUF) < 0)
3067 break;
3068 if (strcmp(buf, tofile) != 0)
3069 continue;
3070 (void) snprintf(key, sizeof (key),
3071 "sndr.set%d.shost",
3072 setnumber);
3073 if (cfg_get_cstring(cfg, key, buf,
3074 CFG_MAX_BUF) < 0)
3075 break;
3076 if (strcmp(buf, tohost) != 0)
3077 continue;
3078 (void) snprintf(key, sizeof (key),
3079 "sndr.set%d.cnode",
3080 setnumber);
3081 if (cfg_get_cstring(cfg, key, buf,
3082 CFG_MAX_BUF) < 0)
3083 break;
3084 if (reconfig_ctag[0] == '\0')
3085 (void) strncpy(ctag, buf,
3086 sizeof (ctag));
3087 if (doasync)
3088 (void) strcpy(mode, "async");
3089 else
3090 (void) strcpy(mode, "sync");
3091 if (strcmp(directfile, "") == 0)
3092 (void) strcpy(directfile, "ip");
3093
3094 group_p = strlen(group) > 0 ? group :
3095 place_holder;
3096
3097 /*
3098 * if we are reconfigging out altogether,
3099 * get rid of the diskqueue
3100 */
3101 if (group_p == place_holder)
3102 diskqueue_p = place_holder;
3103 else
3104 diskqueue_p = strlen(diskqueue) > 0 ?
3105 diskqueue : place_holder;
3106
3107 /*
3108 * do a little diskq dance here for reconfigs
3109 * that did not specify the diskqueue whilst
3110 * reconfigging ...
3111 */
3112 if ((diskqueue_p == place_holder) &&
3113 (group_p != place_holder)) {
3114 get_group_diskq(cfg, group_p,
3115 diskqueue);
3116 diskqueue_p = strlen(diskqueue) > 0 ?
3117 diskqueue : place_holder;
3118 }
3119
3120 (void) snprintf(key, sizeof (key),
3121 "sndr.set%d.options", setnumber);
3122 if (cfg_get_cstring(cfg, key, options_cfg,
3123 CFG_MAX_BUF) < 0) {
3124 break;
3125 }
3126
3127 ctag_p = strlen(ctag) > 0 ?
3128 ctag : place_holder;
3129 (void) snprintf(buf, sizeof (buf),
3130 "%s %s %s %s %s %s %s %s %s %s %s %s",
3131 fromhost, fromfile, frombitmap,
3132 tohost, tofile, tobitmap,
3133 directfile, mode, group_p,
3134 ctag_p, options_cfg, diskqueue_p);
3135
3136 (void) snprintf(key, sizeof (key), "sndr.set%d",
3137 setnumber);
3138 if (cfg_put_cstring(cfg, key, buf,
3139 strlen(buf)) < 0)
3140 rdc_warn(NULL,
3141 gettext("unable to update \"%s\" "
3142 "in configuration storage: %s"),
3143 buf, cfg_error(&sev));
3144 else
3145 cfg_success = 1;
3146 break;
3147 }
3148 }
3149
3150 if (cfg_success) {
3151 if (cfg && perform_autosv()) {
3152 if (self_check(fromhost)) {
3153 if (diskqueue[0] &&
3154 (strcmp(diskqueue, fromfile) == 0) ||
3155 (strcmp(diskqueue, frombitmap) == 0)) {
3156 rdc_err(NULL, gettext("disk "
3157 "queue volume %s must not "
3158 "match any primary Remote "
3159 "Mirror volume or bitmap"),
3160 diskqueue);
3161 }
3162
3163 if (diskqueue[0]) {
3164 different_devs(fromfile, diskqueue);
3165 different_devs(frombitmap, diskqueue);
3166 validate_name(cfg, diskqueue);
3167 }
3168 different_devs(fromfile, frombitmap);
3169 validate_name(cfg, fromfile);
3170 validate_name(cfg, frombitmap);
3171 } else {
3172 different_devs(tofile, tobitmap);
3173 validate_name(cfg, tofile);
3174 validate_name(cfg, tobitmap);
3175 }
3176 }
3177 /*
3178 * okay, if the command is sync, just build
3179 * a list of rdcconfig_t's after the pairs--
3180 * loop is done, we will pass this list to
3181 * librdc to multithread the syncs (after
3182 * forking off a daemonish type process
3183 * that waits for the libcall to complete
3184 * ints of interest:
3185 * flag ie RDC_CMD_COPY, iflag RDC_OPT_UPDATE,
3186 * reverse RDC_OPT_REVERSE, RDC_OPT_FORWARD
3187 * if necessary, turn autosync back on
3188 */
3189 if (flag == RDC_CMD_COPY) {
3190 if (autosync_is_on(tohost, tofile) ==
3191 AUTOSYNC_ON)
3192 enable_autosync(fromhost, fromfile,
3193 tohost, tofile);
3194
3195 if (sets == NULL) {
3196 sets_p = sets =
3197 rdc_alloc_config(fromhost, fromfile,
3198 frombitmap, tohost, tofile,
3199 tobitmap, "mode", "group", "ctag",
3200 "options", 0);
3201
3202 if (sets_p == NULL) {
3203 rdc_err(NULL,
3204 gettext("rdc config alloc"
3205 "failed %s"), rdc_error(NULL));
3206 }
3207 continue;
3208 }
3209
3210 sets_p = sets_p->next =
3211 rdc_alloc_config(fromhost, fromfile,
3212 frombitmap, tohost, tofile, tobitmap,
3213 "mode", "group", "ctag", "options", 0);
3214
3215 if (sets_p == NULL) {
3216 rdc_err(NULL, gettext("rdc config alloc"
3217 "failed %s"), rdc_error(NULL));
3218 }
3219 continue;
3220 }
3221
3222 /*
3223 * block incoming signals until after the possible
3224 * cfg_commit is done
3225 */
3226 block_sigs();
3227 if (rdc_operation(cfg, fromhost, fromfile, frombitmap,
3228 tohost, tofile, tobitmap, flag, iflag, directfile,
3229 group, ctag, diskqueue, &doasync, reverse) < 0) {
3230 ;
3231 /*EMPTY*/
3232 } else if (cfg) {
3233 if (diskq_group == DISKQ_REWRITEG) {
3234 rewrite_group_diskqueue(cfg,
3235 &pair_list[pairs], diskqueue);
3236 }
3237 if (perform_autosv() &&
3238 (flag == RDC_CMD_ENABLE ||
3239 flag == RDC_CMD_DISABLE ||
3240 flag == RDC_CMD_RECONFIG)) {
3241 unload_rdc_vols();
3242 cfg_unload_shadows();
3243 cfg_unload_dsvols();
3244 cfg_unload_svols();
3245 }
3246 if ((iflag & RDC_OPT_REVERSE_ROLE) != 0 &&
3247 allow_role) {
3248 bzero(tmphost, MAX_RDC_HOST_SIZE);
3249 bzero(tmpfile, NSC_MAXPATH);
3250 bzero(tmpbitmap, NSC_MAXPATH);
3251 (void) strncpy(tmphost, fromhost,
3252 MAX_RDC_HOST_SIZE);
3253 (void) strncpy(tmpfile, fromfile,
3254 NSC_MAXPATH);
3255 (void) strncpy(tmpbitmap, frombitmap,
3256 NSC_MAXPATH);
3257
3258 (void) strncpy(fromhost, tohost,
3259 MAX_RDC_HOST_SIZE);
3260 (void) strncpy(fromfile, tofile,
3261 NSC_MAXPATH);
3262 (void) strncpy(frombitmap, tobitmap,
3263 NSC_MAXPATH);
3264
3265 (void) strncpy(tohost, tmphost,
3266 MAX_RDC_HOST_SIZE);
3267 (void) strncpy(tofile, tmpfile,
3268 NSC_MAXPATH);
3269 (void) strncpy(tobitmap, tmpbitmap,
3270 NSC_MAXPATH);
3271 group_p = strlen(group) > 0 ? group :
3272 place_holder;
3273 diskqueue_p = strlen(diskqueue) > 0 ?
3274 diskqueue : place_holder;
3275 ctag_p = strlen(ctag) > 0 ?
3276 ctag : place_holder;
3277 (void) snprintf(buf, sizeof (buf), "%s "
3278 "%s %s %s %s %s %s %s %s %s %s %s",
3279 fromhost, fromfile, frombitmap,
3280 tohost, tofile, tobitmap,
3281 directfile, mode, group_p,
3282 ctag_p, options_cfg, diskqueue_p);
3283
3284 (void) snprintf(key, sizeof (key),
3285 "sndr.set%d", setnumber);
3286 if (cfg_put_cstring(cfg, key, buf,
3287 strlen(buf)) < 0)
3288 rdc_err(NULL,
3289 gettext("unable to update \"%s\" "
3290 "in configuration storage: %s"),
3291 buf, cfg_error(&sev));
3292 }
3293 if (cfg_commit(cfg) < 0) {
3294 rdc_err(NULL, gettext("commit on role "
3295 "reversal failed"));
3296 }
3297 }
3298 unblock_sigs();
3299 }
3300
3301 if (cfg) {
3302 cfg_close(cfg);
3303 }
3304
3305 }
3306 if (flag == RDC_CMD_COPY) {
3307 pid = fork();
3308 if (pid == -1) { /* error forking */
3309 perror("fork");
3310 exit(1);
3311 }
3312 } else {
3313 exit(0);
3314 }
3315 if (pid > 0) /* parent process */
3316 exit(0);
3317
3318 spcslog_sync(sets, 1, iflag);
3319 if (iflag & RDC_OPT_REVERSE) {
3320 if (iflag & RDC_OPT_UPDATE)
3321 rclist = rdc_ursync(sets);
3322 else
3323 rclist = rdc_rsync(sets);
3324 } else if (iflag & RDC_OPT_UPDATE) {
3325 rclist = rdc_usync(sets);
3326 } else
3327 rclist = rdc_fsync(sets);
3328
3329 rcp = rclist;
3330 while (rcp) {
3331 if (rcp->rc < 0) {
3332 /* rclist->msg has already been gettext'd */
3333 (void) fprintf(stderr,
3334 gettext("Remote Mirror: %s %s %s %s %s %s\n"),
3335 rcp->set.phost, rcp->set.pfile, rcp->set.pbmp,
3336 rcp->set.shost, rcp->set.sfile, rcp->set.sbmp);
3337 rdc_warn(NULL, "%s", rcp->msg);
3338 spcs_log("sndr", NULL, "%s", rcp->msg);
3339 }
3340 rcp = rcp->next;
3341 }
3342
3343 spcslog_sync(sets, 0, iflag);
3344
3345 if (sets)
3346 rdc_free_config(sets, RDC_FREEALL);
3347 if (rclist)
3348 rdc_free_rclist(rclist);
3349
3350 return (0);
3351 }
3352 /*
3353 * process_clocal()
3354 * pre: a non null string
3355 * post: if the string is "local"
3356 * then it is converted to "-"
3357 * and rdc_islocal is set to 1
3358 * if not rdc_islocal set to 0
3359 */
3360 void
3361 process_clocal(char *ctag)
3362 {
3363 /*
3364 * Check for the special cluster tag and convert into the
3365 * internal representation.
3366 */
3367
3368 if (ctag != NULL && strcmp(ctag, RDC_LOCAL_TAG) == 0) {
3369 (void) strcpy(ctag, "-");
3370 rdc_islocal = 1;
3371 } else {
3372 rdc_islocal = 0;
3373 }
3374 }
3375
3376 static void
3377 rdc_check_dgislocal(char *dgname)
3378 {
3379 char *othernode;
3380 int rc;
3381
3382 /*
3383 * check where this disk service is mastered
3384 */
3385
3386 rc = cfg_dgname_islocal(dgname, &othernode);
3387 if (rc < 0) {
3388 rdc_err(NULL, gettext("unable to find "
3389 "disk service, %s: %s"), dgname, strerror(errno));
3390 }
3391
3392 if (rc == 0) {
3393 rdc_err(NULL, gettext("disk service, %s, is "
3394 "active on node \"%s\"\nPlease re-issue "
3395 "the command on that node"), dgname, othernode);
3396 }
3397 }
3398
3399 static void
3400 different_devs(char *dev1, char *dev2)
3401 {
3402 struct stat buf1, buf2;
3403
3404 if (stat(dev1, &buf1) < 0) {
3405 spcs_log("sndr", NULL, gettext("Remote Mirror: can't stat %s"),
3406 dev1);
3407 rdc_err(NULL, gettext("Remote Mirror: can't stat %s"), dev1);
3408 }
3409 if (stat(dev2, &buf2) < 0) {
3410 spcs_log("sndr", NULL, gettext("Remote Mirror: can't stat %s"),
3411 dev2);
3412 rdc_err(NULL, gettext("Remote Mirror: can't stat %s"), dev2);
3413 }
3414 if (buf1.st_rdev == buf2.st_rdev) {
3415 spcs_log("sndr", NULL, gettext("Remote Mirror: '%s' and '%s' "
3416 "refer to the same device"), dev1, dev2);
3417 rdc_err(NULL, gettext("Remote Mirror: '%s' and '%s' refer to "
3418 "the same device"), dev1, dev2);
3419 }
3420 }
3421
3422 static void
3423 validate_name(CFGFILE *cfg, char *vol)
3424 {
3425 char *altname;
3426 int rc;
3427
3428 if (!cfg) {
3429 rdc_err(NULL, gettext("Remote Mirror: null cfg ptr in "
3430 "validate_name"));
3431 }
3432
3433 rc = cfg_get_canonical_name(cfg, vol, &altname);
3434 if (rc < 0) {
3435 spcs_log("sndr", NULL, gettext("Remote Mirror: unable to parse "
3436 "config file\n"));
3437 rdc_err(NULL, gettext("Remote Mirror: unable to parse config "
3438 "file\n"));
3439 }
3440 if (rc) {
3441 spcs_log("sndr", NULL, gettext("Remote Mirror: '%s': already "
3442 "configured as '%s'"), vol, altname);
3443 rdc_err(NULL, gettext("Remote Mirror: The volume '%s' has been "
3444 "configured previously as '%s'. Re-enter command with "
3445 "the latter name."), vol, altname);
3446 }
3447 }
3448
3449 /*
3450 * Add the autosync value to the option field for the sndr set specified by
3451 * tohost:tofile.
3452 *
3453 * ASSUMPTIONS:
3454 * - cfg file is available to take a write lock.
3455 * - set is already configured in dscfg
3456 *
3457 * INPUTS:
3458 * autosync_val - value to set autosync to
3459 * tohost - secondary host
3460 * tofile - secondary volume
3461 *
3462 * OUTPUTS:
3463 * none.
3464 *
3465 */
3466 static void
3467 set_autosync(int autosync_val, char *tohost, char *tofile, char *ctag)
3468 {
3469 CFGFILE *cfg;
3470 char key[CFG_MAX_KEY], buf[CFG_MAX_BUF];
3471 char tag[CFG_MAX_BUF], val[CFG_MAX_BUF];
3472 char auto_tag[CFG_MAX_BUF];
3473 _sd_dual_pair_t pair;
3474 _sd_dual_pair_t tmpair;
3475 int setnumber, options = 0, already_set = 0, cfg_success = 0;
3476 int set;
3477
3478 /* verify valid autosync request */
3479 if ((autosync_val != AUTOSYNC_ON) && (autosync_val != AUTOSYNC_OFF)) {
3480 #ifdef DEBUG
3481 rdc_warn(NULL,
3482 gettext("set_autosync called with improper value"));
3483 #endif
3484 return;
3485 }
3486
3487 if ((cfg = cfg_open(NULL)) == NULL) {
3488 rdc_err(NULL, gettext("unable to access configuration"));
3489 }
3490 if (!cfg_lock(cfg, CFG_WRLOCK)) {
3491 rdc_err(NULL, gettext("unable to lock configuration"));
3492 }
3493
3494 if (clustered) {
3495 cfg_resource(cfg, ctag);
3496 } else {
3497 cfg_resource(cfg, NULL);
3498 }
3499
3500 /* find set number in config */
3501 if ((setnumber = find_setnumber_in_libcfg(cfg, clustered? ctag : NULL,
3502 tohost, tofile)) < 0) {
3503 cfg_close(cfg);
3504 rdc_err(NULL, gettext("unable to find Remote Mirror set %s:%s: "
3505 "in config"), tohost, tofile);
3506 }
3507 (void) snprintf(key, sizeof (key), "sndr.set%d.options", setnumber);
3508 (void) snprintf(auto_tag, sizeof (auto_tag), "auto");
3509
3510 /* Check if there are any options already set, including ours */
3511 if (cfg_get_options(cfg, CFG_SEC_CONF, key, tag, CFG_MAX_BUF, val,
3512 CFG_MAX_BUF) >= 0) {
3513 options = 1;
3514
3515 do {
3516 if (strcmp(tag, auto_tag) == 0) {
3517 already_set = 1;
3518 }
3519 } while (cfg_get_options(cfg, CFG_SEC_CONF, NULL, tag,
3520 CFG_MAX_BUF, val, CFG_MAX_BUF) >= 0);
3521 }
3522
3523 /* options already exist, edit ours out */
3524 if (options && already_set) {
3525 char *p, *q;
3526 int need_to_clear_buf = 1;
3527
3528 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
3529 rdc_err(NULL, gettext("unable to get options field "
3530 "for Remote Mirror set %s:%s"), tohost, tofile);
3531 }
3532
3533 /* parse out our options, all of the form "auto=" */
3534 p = strdup(buf);
3535 bzero(buf, sizeof (buf));
3536
3537 q = strtok(p, ";");
3538 do {
3539 /* if another tag/value exists, keep it */
3540 if (strncmp(auto_tag, q, 4) != 0) {
3541 (void) strcat(buf, q);
3542 (void) strcat(buf, ";");
3543 need_to_clear_buf = 0;
3544 }
3545 } while (q = strtok(NULL, ";"));
3546 free(p);
3547
3548 /* if we were the only option, clear the field */
3549 if (need_to_clear_buf) {
3550 (void) strcat(buf, "-");
3551 }
3552
3553 if (cfg_put_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
3554 rdc_err(NULL, gettext("unable to clear autosync value "
3555 "in config for Remote Mirror set %s:%s"), tohost,
3556 tofile);
3557 } else {
3558 cfg_success = 1;
3559 }
3560 }
3561
3562 /* autosync is not present in options field, add if on is requested */
3563 if (autosync_val == AUTOSYNC_ON) {
3564 if (cfg_put_options(cfg, CFG_SEC_CONF, key, auto_tag, "on")
3565 < 0) {
3566 rdc_err(NULL, gettext("unable to update autosync value "
3567 "in config for Remote Mirror set %s:%s"), tohost,
3568 tofile);
3569 } else {
3570 cfg_success = 1;
3571 }
3572 }
3573 /* if we are in a group, update any other sets in the same group */
3574 do {
3575 bzero(&pair, sizeof (pair));
3576 bzero(buf, CFG_MAX_BUF);
3577
3578 (void) snprintf(key, sizeof (key), "sndr.set%d", setnumber);
3579 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
3580 break;
3581 }
3582 if (parse_cfg_buf(buf, &pair, NULL))
3583 break;
3584 if (pair.group == NULL) /* not in a group */
3585 break;
3586 if (!pair.group[0])
3587 break; /* not in a group */
3588 for (set = 1; /*CSTYLED*/; set++) {
3589 if (set == setnumber)
3590 continue;
3591 bzero(buf, CFG_MAX_BUF);
3592 options = 0;
3593 already_set = 0;
3594
3595 (void) snprintf(key, sizeof (key), "sndr.set%d", set);
3596 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
3597 break; /* last set processed */
3598 }
3599 bzero(&tmpair, sizeof (tmpair));
3600 if (parse_cfg_buf(buf, &tmpair, NULL))
3601 break;
3602 if (strcmp(pair.group, tmpair.group) != 0)
3603 continue; /* not the group we want */
3604
3605 (void) snprintf(key, sizeof (key), "sndr.set%d.options",
3606 set);
3607 /*
3608 * Check if there are any options already set,
3609 * including ours
3610 */
3611 if (cfg_get_options(cfg, CFG_SEC_CONF, key, tag,
3612 CFG_MAX_BUF, val, CFG_MAX_BUF) >= 0) {
3613 options = 1;
3614
3615 do {
3616 if (strcmp(tag, auto_tag) == 0) {
3617 already_set = 1;
3618 }
3619 } while (cfg_get_options(cfg, CFG_SEC_CONF,
3620 NULL, tag, CFG_MAX_BUF, val,
3621 CFG_MAX_BUF) >= 0);
3622 }
3623
3624 /* options already exist, edit ours out */
3625 if (options && already_set) {
3626 char *p, *q;
3627 int need_to_clear_buf = 1;
3628
3629 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF)
3630 < 0) {
3631 rdc_err(NULL, gettext("unable to get "
3632 "options field for Remote Mirror set "
3633 "%s:%s"), tmpair.thost, tmpair.tfile);
3634 }
3635
3636 /*
3637 * parse out our options, all of the
3638 * form "auto="
3639 */
3640 p = strdup(buf);
3641 bzero(buf, sizeof (buf));
3642
3643 q = strtok(p, ";");
3644 do {
3645 /*
3646 * if another tag/value exists,
3647 * keep it
3648 */
3649 if (strncmp(auto_tag, q, 4) != 0) {
3650 (void) strcat(buf, q);
3651 (void) strcat(buf, ";");
3652 need_to_clear_buf = 0;
3653 }
3654 } while (q = strtok(NULL, ";"));
3655 free(p);
3656
3657 /*
3658 * if we were the only option,
3659 * clear the field
3660 */
3661 if (need_to_clear_buf) {
3662 (void) strcat(buf, "-");
3663 }
3664
3665 if (cfg_put_cstring(cfg, key, buf, CFG_MAX_BUF)
3666 < 0) {
3667 rdc_err(NULL, gettext("unable to clear "
3668 "autosync value in config for "
3669 "Remote Mirror set %s:%s"),
3670 tmpair.thost, tmpair.tfile);
3671 cfg_success = 0;
3672 }
3673 }
3674
3675 /*
3676 * autosync is not present in options field,
3677 * add if on is requested
3678 */
3679 if (autosync_val == AUTOSYNC_ON) {
3680 if (cfg_put_options(cfg, CFG_SEC_CONF, key,
3681 auto_tag, "on") < 0) {
3682 rdc_err(NULL, gettext("unable to update"
3683 " autosync value in config for "
3684 "Remote Mirror set %s:%s"),
3685 tmpair.thost,
3686 tmpair.tfile);
3687 cfg_success = 0;
3688 }
3689 }
3690 }
3691
3692 /* CONSTCOND */
3693 } while (0);
3694 if (cfg_success) {
3695 if (cfg_commit(cfg) < 0) {
3696 rdc_err(NULL, gettext("commit on role reversal failed"));
3697 }
3698 }
3699
3700 cfg_close(cfg);
3701 }
3702
3703 /*
3704 * Check to see if autosync is on for set specified by tohost:tofile.
3705 *
3706 * ASSUMPTIONS:
3707 * config is available to take a read lock against it.
3708 *
3709 * INPUTS:
3710 * tohost - secondary host
3711 * tofile - secondary volume
3712 *
3713 * OUTPUTS:
3714 * -1 error
3715 * AUTOSYNC_ON if autosync is on
3716 * AUTOSYNC_OFF if autosync is off
3717 */
3718 static int
3719 autosync_is_on(char *tohost, char *tofile)
3720 {
3721 CFGFILE *cfg;
3722 int setnumber, autosync_val = AUTOSYNC_OFF;
3723 char key[CFG_MAX_KEY];
3724 char tag[CFG_MAX_BUF], val[CFG_MAX_BUF];
3725
3726 if ((cfg = cfg_open(NULL)) == NULL) {
3727 rdc_err(NULL, gettext("unable to access configuration"));
3728 }
3729
3730 if (!cfg_lock(cfg, CFG_RDLOCK)) {
3731 cfg_close(cfg);
3732 rdc_err(NULL, gettext("unable to lock configuration"));
3733 }
3734
3735 if ((setnumber = find_setnumber_in_libcfg(cfg, NULL, tohost, tofile)) <
3736 0) {
3737 cfg_close(cfg);
3738 rdc_err(NULL, gettext("cannot find Remote Mirror set %s:%s in "
3739 "config"), tohost, tofile);
3740 }
3741
3742 (void) snprintf(key, CFG_MAX_KEY, "sndr.set%d.options", setnumber);
3743 if (cfg_get_options(cfg, CFG_SEC_CONF, key, tag, CFG_MAX_BUF, val,
3744 CFG_MAX_BUF) >= 0) {
3745 do {
3746 if (strcmp(tag, "auto") == 0) {
3747 if (strcmp(val, "on") == 0) {
3748 autosync_val = AUTOSYNC_ON;
3749 }
3750 break;
3751 }
3752 } while (cfg_get_options(cfg, CFG_SEC_CONF, NULL, tag,
3753 CFG_MAX_BUF, val, CFG_MAX_BUF) >= 0);
3754 }
3755
3756 cfg_close(cfg);
3757 return (autosync_val);
3758 }
3759
3760 void
3761 enable_autosync(char *fhost, char *ffile, char *thost, char *tfile)
3762 {
3763 rdc_config_t parms;
3764 spcs_s_info_t ustat;
3765 rdc_addr_t *p;
3766
3767 ustat = spcs_s_ucreate();
3768 parms.command = RDC_CMD_TUNABLE;
3769
3770 p = &parms.rdc_set[0].primary;
3771 (void) strncpy(p->intf, fhost, MAX_RDC_HOST_SIZE);
3772 (void) strncpy(p->file, ffile, MAX_RDC_HOST_SIZE);
3773
3774 p = &parms.rdc_set[0].secondary;
3775 (void) strncpy(p->intf, thost, NSC_MAXPATH);
3776 (void) strncpy(p->file, tfile, NSC_MAXPATH);
3777
3778 parms.rdc_set[0].autosync = 1;
3779 parms.rdc_set[0].maxqfbas = -1;
3780 parms.rdc_set[0].maxqitems = -1;
3781 parms.rdc_set[0].asyncthr = -1;
3782 parms.rdc_set[0].netconfig = NULL;
3783
3784 if ((RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustat)) !=
3785 SPCS_S_OK) {
3786 rdc_warn(&ustat, gettext("failed to update autosync for"
3787 " Remote Mirror set %s:%s"), thost, tfile);
3788 spcs_log("sndr", &ustat, gettext("failed to update autosync for"
3789 " Remote Mirror set %s:%s"), thost, tfile);
3790 }
3791 spcs_s_ufree(&ustat);
3792 }
3793
3794 static int
3795 rdc_operation(CFGFILE *cfg, char *fromhost, char *fromfile, char *frombitmap,
3796 char *tohost, char *tofile, char *tobitmap,
3797 int flag, int iflag,
3798 char *directfile, char *group, char *ctag, char *diskqueue,
3799 int *doasync, int reverse)
3800 {
3801 const int getaddr = (flag == RDC_CMD_ENABLE);
3802 const int rpcbind = !getaddr;
3803 rdc_config_t parms;
3804 int ret;
3805 spcs_s_info_t ustatus;
3806 struct hostent *hp;
3807 char fromname[MAXHOSTNAMELEN], toname[MAXHOSTNAMELEN];
3808 char orig_fbmp[MAXHOSTNAMELEN], orig_tbmp[MAXHOSTNAMELEN];
3809 char orig_diskq[NSC_MAXPATH];
3810 struct t_info tinfo;
3811 int success = 1;
3812 int autosync_toggle_needed = 0;
3813 char *vol1, *vol2, *vol3;
3814
3815 conf = &nconf;
3816
3817 hp = gethost_byname(fromhost);
3818 (void) strncpy(fromname, hp->h_name, MAXHOSTNAMELEN);
3819 hp = gethost_byname(tohost);
3820 (void) strncpy(toname, hp->h_name, MAXHOSTNAMELEN);
3821
3822 if (self_check(fromname) && self_check(toname)) {
3823 rdc_err(NULL, gettext("both %s and %s are local"),
3824 fromhost, tohost);
3825 }
3826
3827 /* we have to find out what to sv disable after reconfig */
3828 if (flag == RDC_CMD_RECONFIG) {
3829
3830 parms.command = RDC_CMD_STATUS;
3831 parms.rdc_set->netconfig = NULL;
3832 (void) strncpy(parms.rdc_set->primary.intf, fromhost,
3833 MAX_RDC_HOST_SIZE);
3834 (void) strncpy(parms.rdc_set->secondary.intf, tohost,
3835 MAX_RDC_HOST_SIZE);
3836 (void) strncpy(parms.rdc_set->primary.file, fromfile,
3837 NSC_MAXPATH);
3838 (void) strncpy(parms.rdc_set->secondary.file, tofile,
3839 NSC_MAXPATH);
3840 ustatus = spcs_s_ucreate();
3841 ret = RDC_IOCTL(RDC_CONFIG, &parms,
3842 NULL, 0, 0, 0, ustatus);
3843 if (ret != SPCS_S_OK) {
3844 rdc_err(NULL, gettext("unable to get set status"
3845 " before reconfig operation"));
3846 }
3847 (void) strncpy(orig_fbmp, parms.rdc_set->primary.bitmap,
3848 NSC_MAXPATH);
3849 (void) strncpy(orig_tbmp, parms.rdc_set->secondary.bitmap,
3850 NSC_MAXPATH);
3851 (void) strncpy(orig_diskq, parms.rdc_set->disk_queue,
3852 NSC_MAXPATH);
3853 }
3854
3855 /*
3856 * another terrible addition, if we are reconfigging mode
3857 * and not logging, just give up.
3858 */
3859 if ((reconfig_doasync != -1) &&
3860 (!(parms.rdc_set->flags & RDC_LOGGING))) {
3861 rdc_err(NULL, gettext("cannot reconfigure sync/async, "
3862 "Remote Mirror set not logging"));
3863 spcs_log("sndr", NULL, gettext("cannot reconfigure sync/async, "
3864 "Remote Mirror set not logging"));
3865 }
3866
3867 /*
3868 * Now build up the address for each host including port and transport
3869 */
3870 if (getaddr) {
3871 svp = get_addr(toname, RDC_PROGRAM, RDC_VERS_MIN,
3872 &conf, proto_test ? NC_UDP:NULL, "rdc", &tinfo,
3873 rpcbind);
3874
3875 if (svp == NULL) {
3876 rdc_warn(NULL, gettext("unable to determine network "
3877 "information for %s"), toname);
3878 #ifdef DEBUG
3879 (void) printf("get_addr failed for Ver 4 %s\n", toname);
3880 #endif
3881 return (-1);
3882 }
3883 svaddr = *svp;
3884 } else {
3885 bzero(&svaddr, sizeof (svaddr));
3886 }
3887
3888 parms.rdc_set->secondary.addr.len = svaddr.len;
3889 parms.rdc_set->secondary.addr.maxlen =
3890 svaddr.maxlen;
3891 parms.rdc_set->secondary.addr.buf =
3892 (void *)svaddr.buf;
3893
3894 #ifdef DEBUG_ADDR
3895 (void) fprintf(stderr, "secondary buf %x len %d\n",
3896 svaddr.buf, svaddr.len);
3897
3898 for (i = 0; i < svaddr.len; i++)
3899 (void) printf("%u ", svaddr.buf[i]);
3900 (void) printf("\n");
3901 #endif
3902
3903 if (getaddr) {
3904 svp = get_addr(fromname, RDC_PROGRAM, RDC_VERS_MIN,
3905 &conf, proto_test ? NC_UDP: NULL, "rdc", &tinfo,
3906 rpcbind);
3907 if (svp == NULL) {
3908 #ifdef DEBUG
3909 (void) printf("get_addr failed for Ver 4 %s\n",
3910 fromname);
3911 #endif
3912 return (-1);
3913 }
3914 svaddr = *svp;
3915 }
3916
3917 parms.rdc_set->primary.addr.len = svaddr.len;
3918 parms.rdc_set->primary.addr.maxlen = svaddr.maxlen;
3919 parms.rdc_set->primary.addr.buf = (void *)svaddr.buf;
3920
3921 #ifdef DEBUG_ADDR
3922 (void) fprintf(stderr, "primary buf %x len %d\n",
3923 svaddr.buf, svaddr.len);
3924 for (i = 0; i < svaddr.len; i++)
3925 (void) printf("%u ", svaddr.buf[i]);
3926 (void) printf("\n");
3927 #endif
3928
3929 if (getaddr) {
3930 (void) convert_nconf_to_knconf(conf, &knconf);
3931 #ifdef DEBUG_ADDR
3932 (void) printf("knconf %x %s %s %x\n", knconf.knc_semantics,
3933 knconf.knc_protofmly, knconf.knc_proto, knconf.knc_rdev);
3934 #endif
3935 parms.rdc_set->netconfig = &knconf;
3936 } else {
3937 parms.rdc_set->netconfig = NULL;
3938 }
3939
3940 if (!self_check(fromname) && !self_check(toname)) {
3941 if (!clustered)
3942 rdc_err(NULL, gettext("neither %s nor %s is local"),
3943 fromhost, tohost);
3944 else {
3945 /*
3946 * IF we could get a list of logical hosts on this cluster
3947 * Then we could print something intelligent about where
3948 * the volume is mastered. For now, just print some babble
3949 * about the fact that we have no idea.
3950 */
3951 rdc_err(NULL,
3952 gettext("either %s:%s or %s:%s is not local"),
3953 fromhost, fromfile, tohost, tofile);
3954 }
3955 }
3956
3957 (void) strncpy(parms.rdc_set->primary.intf, fromhost,
3958 MAX_RDC_HOST_SIZE);
3959 (void) strncpy(parms.rdc_set->primary.file, fromfile, NSC_MAXPATH);
3960 (void) strncpy(parms.rdc_set->primary.bitmap, frombitmap, NSC_MAXPATH);
3961
3962 (void) strncpy(parms.rdc_set->secondary.intf, tohost,
3963 MAX_RDC_HOST_SIZE);
3964 (void) strncpy(parms.rdc_set->secondary.file, tofile, NSC_MAXPATH);
3965 (void) strncpy(parms.rdc_set->secondary.bitmap, tobitmap, NSC_MAXPATH);
3966
3967 if ((group == NULL) || ((strcmp(group, "-")) == 0))
3968 parms.rdc_set->group_name[0] = 0;
3969 else
3970 (void) strncpy(parms.rdc_set->group_name, group, NSC_MAXPATH);
3971
3972 if (self_check(tohost) &&
3973 (strlen(diskqueue) > 0) && (diskqueue[0] != '-'))
3974 if ((flag == RDC_CMD_ENABLE) || (flag == RDC_CMD_ADDQ))
3975 rdc_err(NULL, gettext("enabling disk queue on a Remote"
3976 " Mirror secondary is not allowed (%s)"),
3977 diskqueue);
3978
3979 if ((diskqueue == NULL) || ((strcmp(diskqueue, "-")) == 0))
3980 parms.rdc_set->disk_queue[0] = 0;
3981 else
3982 (void) strncpy(parms.rdc_set->disk_queue, diskqueue,
3983 NSC_MAXPATH);
3984
3985 parms.rdc_set->maxqfbas = maxqfbas;
3986 parms.rdc_set->maxqitems = maxqitems;
3987 parms.rdc_set->asyncthr = asyncthr;
3988 /* set up the permanent set id for this set */
3989 if (flag == RDC_CMD_ENABLE) {
3990 char key[CFG_MAX_KEY];
3991 char setid[64];
3992 int set;
3993 parms.rdc_set->setid = get_new_cfg_setid(cfg);
3994 if (parms.rdc_set->setid <= 0) {
3995 rdc_err(NULL, gettext("unable to obtain unique set id "
3996 "for %s:%s"), tohost, tofile);
3997 }
3998 if ((set = find_setnumber_in_libcfg(cfg, clustered? ctag : NULL,
3999 tohost, tofile)) < 0) {
4000 rdc_err(NULL, gettext("unable to store unique set id"
4001 " for %s:%s"), tohost, tofile);
4002 }
4003 (void) snprintf(key, sizeof (key), "sndr.set%d.options", set);
4004 (void) snprintf(setid, sizeof (setid), "%d",
4005 parms.rdc_set->setid);
4006
4007 if (cfg_put_options(cfg, CFG_SEC_CONF, key, "setid",
4008 setid) < 0) {
4009 rdc_err(NULL, gettext("unable to store unique set "
4010 "id for %s:%s: %s"), tohost, tofile,
4011 gettext(cfg_error(NULL)));
4012 }
4013 } else if (flag != RDC_CMD_DISABLE) { /* set already gone from cfg */
4014 parms.rdc_set->setid = get_cfg_setid(cfg, ctag, tohost, tofile);
4015 if (parms.rdc_set->setid <= 0) {
4016 rdc_err(NULL, gettext("unable to obtain unique set id "
4017 "for %s:%s"), tohost, tofile);
4018 }
4019 }
4020
4021 /*
4022 * Always set autosync flag to default so nothing gets messed up. If
4023 * we are doing an autosync operation, it'll all get taken care of
4024 * then.
4025 */
4026 parms.rdc_set->autosync = AUTOSYNC;
4027
4028
4029 /* gethostid(3c) is defined to return a 32bit value */
4030 parms.rdc_set->syshostid = (int32_t)gethostid();
4031
4032 parms.command = 0;
4033 parms.options = iflag;
4034 parms.command = flag;
4035 if (flag == RDC_CMD_ENABLE || flag == RDC_CMD_RECONFIG) {
4036 if (*doasync)
4037 parms.options |= RDC_OPT_ASYNC;
4038 else
4039 parms.options |= RDC_OPT_SYNC;
4040 } else if (flag == RDC_CMD_COPY) {
4041 if (reverse)
4042 parms.options |= RDC_OPT_REVERSE;
4043 else
4044 parms.options |= RDC_OPT_FORWARD;
4045 }
4046
4047 if (self_check(fromname)) {
4048 if (flag == RDC_CMD_COPY && reverse && mounted(fromfile))
4049 rdc_err(NULL, gettext("can not start reverse sync"
4050 " as a file system is mounted on %s"),
4051 fromfile);
4052 parms.options |= RDC_OPT_PRIMARY;
4053 if (strcmp(directfile, "ip") == 0)
4054 parms.rdc_set->direct_file[0] = 0; /* no directfile */
4055 else
4056 (void) strncpy(parms.rdc_set->direct_file, directfile,
4057 NSC_MAXPATH);
4058 } else {
4059 parms.options |= RDC_OPT_SECONDARY;
4060 parms.rdc_set->direct_file[0] = 0; /* no fcal directio */
4061 }
4062
4063 if ((asyncthr || maxqitems || maxqfbas || qblock) &&
4064 (parms.options & RDC_OPT_SECONDARY)) {
4065 rdc_err(NULL, gettext("changing queue parameters may "
4066 " only be done on a primary Remote Mirror host"));
4067 spcs_log("sndr", NULL, gettext("changing queue parameters may "
4068 " only be done on a primary Remote Mirror host"));
4069
4070 }
4071
4072 ustatus = spcs_s_ucreate();
4073
4074 if (flag == RDC_CMD_COPY) {
4075 parms.command = RDC_CMD_STATUS;
4076 ret = RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus);
4077 if ((ret != SPCS_S_OK) ||
4078 !(parms.rdc_set->flags & RDC_LOGGING)) {
4079 rdc_err(NULL, gettext("can not start sync"
4080 " as Remote Mirror set %s:%s is not logging"),
4081 tohost, tofile);
4082 }
4083 spcs_log("sndr", NULL,
4084 gettext("%s %s %s %s %s %s %s %s\nStarting"),
4085 program, rdc_decode_flag(flag, parms.options),
4086 fromhost, fromfile, frombitmap,
4087 tohost, tofile, tobitmap);
4088 parms.command = RDC_CMD_COPY;
4089 }
4090
4091 if ((flag == RDC_CMD_COPY) &&
4092 (autosync_is_on(tohost, tofile) == AUTOSYNC_ON)) {
4093 /* check if autosync needs to be turned on when doing a copy/update */
4094 parms.rdc_set->autosync = AUTOSYNC_ON;
4095 autosync_toggle_needed = 1;
4096 } else if ((flag == RDC_CMD_LOG) &&
4097 (autosync_is_on(tohost, tofile) == AUTOSYNC_ON)) {
4098 /* check if autosync needs to be turned off when going to logging */
4099 parms.rdc_set->autosync = AUTOSYNC_OFF;
4100 autosync_toggle_needed = 1;
4101 } else if (((autosync == AUTOSYNC_ON) || (autosync == AUTOSYNC_OFF)) &&
4102 (flag == RDC_CMD_TUNABLE)) {
4103 /*
4104 * Request to change the autosync value. cfg file will be
4105 * available at this point. If autosync request is to turn off,
4106 * mark off in both the config and the kernel regardless of
4107 * the state of the set. If the request is to turn autosync on,
4108 * set in the kernel if the set is not in logging mode.
4109 *
4110 * XXX
4111 * If the set is in logging mode because of a network
4112 * failure, we will not know. Therefore, a manual update
4113 * will have to be issued to enable autosync in the
4114 * kernel.
4115 * XXX
4116 */
4117 set_autosync(autosync, tohost, tofile, ctag);
4118
4119 if (autosync == AUTOSYNC_OFF) {
4120 parms.rdc_set->autosync = AUTOSYNC_OFF;
4121 } else if (autosync == AUTOSYNC_ON) {
4122 parms.command = RDC_CMD_STATUS;
4123 ret = RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0,
4124 ustatus);
4125 if (ret != SPCS_S_OK) {
4126 rdc_err(NULL, gettext("can not determine "
4127 "status of Remote Mirror set %s:%s"),
4128 tohost, tofile);
4129 }
4130
4131 /* need to reset the tunables after a status ioctl */
4132 parms.rdc_set->autosync = autosync;
4133 parms.rdc_set->maxqfbas = maxqfbas;
4134 parms.rdc_set->maxqitems = maxqitems;
4135 parms.rdc_set->asyncthr = asyncthr;
4136
4137 /*
4138 * if in logging mode, just update config, kernel will
4139 * be updated with the next copy/update request.
4140 */
4141 if (parms.rdc_set->flags & RDC_LOGGING) {
4142 parms.rdc_set->autosync = AUTOSYNC;
4143 } else {
4144 parms.rdc_set->autosync = AUTOSYNC_ON;
4145 }
4146
4147 parms.command = flag;
4148 }
4149 }
4150
4151 if (autosync_toggle_needed) {
4152 parms.command = RDC_CMD_TUNABLE;
4153 ret = RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus);
4154 if (ret != SPCS_S_OK) {
4155 spcs_log("sndr", NULL, gettext("failed to update "
4156 "autosync for Remote Mirror set %s:%s"), tohost,
4157 tofile);
4158 rdc_err(NULL, gettext("failed to update autosync for "
4159 "Remote Mirror set %s:%s"), tohost, tofile);
4160 }
4161 /* reset command and default autosync flags */
4162 parms.rdc_set->autosync = AUTOSYNC;
4163 parms.command = flag;
4164 }
4165
4166 errno = 0;
4167 ret = RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus);
4168 if ((ret != SPCS_S_OK) && (flag != RDC_CMD_HEALTH)) {
4169 (void) fprintf(stderr,
4170 gettext("Remote Mirror: %s %s %s %s %s %s\n"),
4171 fromhost, fromfile,
4172 frombitmap, tohost, tofile, tobitmap);
4173
4174 if (errno == RDC_EEINVAL) {
4175 spcs_log("sndr", NULL,
4176 "%s %s %s %s %s %s %s %s\n%s",
4177 program, rdc_decode_flag(flag, parms.options),
4178 fromhost, fromfile, frombitmap,
4179 tohost, tofile, tobitmap,
4180 gettext("invalid command option"));
4181 rdc_err(&ustatus,
4182 gettext("Remote Mirror: invalid command option "
4183 "'%s'"), rdc_decode_flag(flag,
4184 parms.options));
4185 } else {
4186 spcs_log("sndr", &ustatus,
4187 "%s %s %s %s %s %s %s %s",
4188 program, rdc_decode_flag(flag, parms.options),
4189 fromhost, fromfile, frombitmap,
4190 tohost, tofile, tobitmap);
4191 if ((flag == RDC_CMD_RECONFIG) &&
4192 (!(iflag & RDC_OPT_REVERSE_ROLE))) {
4193 success = 0;
4194 rdc_warn(&ustatus, 0);
4195 } else
4196 rdc_err(&ustatus, 0);
4197 }
4198 }
4199 if ((flag == RDC_CMD_RECONFIG) && (iflag & RDC_OPT_REVERSE_ROLE) == 0) {
4200 parms.command = RDC_CMD_STATUS;
4201 if (RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus) ==
4202 SPCS_S_OK) {
4203 char shostbuf[CFG_MAX_BUF];
4204 char svolbuf[CFG_MAX_BUF];
4205 char key[CFG_MAX_KEY];
4206 int i, numels;
4207 int cfgsuccess = 1;
4208
4209 /*
4210 * okeydoke, at this point we could have a reconfig
4211 * gone bad. libdscfg does not know about this.
4212 * parms contains the kernel picture, and we know
4213 * what we tried to reconfig. find out where it went
4214 * wrong, find the set in libdscfg, update it. We'll
4215 * issue a warning, then return 0 (eventually).
4216 * this will allow libdscfg to be committed with the
4217 * good info. got it?
4218 * BTW: the only time we can run into this multiple
4219 * reconfig attempt failure is IF we reconfig from file
4220 * and some thing goes wrong with one of the reconfigs
4221 */
4222
4223 /* find the set in libdscfg */
4224
4225 numels = cfg_get_num_entries(cfg, "sndr");
4226 /* yes, numels could be -1 */
4227 for (i = 1; i < numels; i++) {
4228 bzero(shostbuf, sizeof (shostbuf));
4229 bzero(svolbuf, sizeof (svolbuf));
4230 bzero(key, sizeof (key));
4231
4232 (void) snprintf(key, sizeof (key),
4233 "sndr.set%d.shost", i);
4234
4235 (void) cfg_get_cstring(cfg, key, &shostbuf,
4236 sizeof (shostbuf));
4237 if (strncmp(shostbuf, tohost, sizeof (tohost)))
4238 continue;
4239
4240 bzero(key, sizeof (key));
4241 (void) snprintf(key, sizeof (key),
4242 "sndr.set%d.secondary", i);
4243 (void) cfg_get_cstring(cfg, key, &svolbuf,
4244 sizeof (svolbuf));
4245 if (strncmp(svolbuf, tofile, NSC_MAXPATH))
4246 continue;
4247 break;
4248
4249 /*
4250 * found it, now i contains the set offset.
4251 * i, being the variable, not bad english.
4252 */
4253
4254 }
4255 /* shouldn't happen */
4256 if ((numels < 1) || (i > numels)) {
4257 rdc_warn(NULL, gettext("unable to retrieve "
4258 "set from configuration database"));
4259 /*
4260 * yuck. but indents are pushing the envelope
4261 * we should not be updating config
4262 * if we did not find the entry
4263 * the error will have to do
4264 */
4265 cfgsuccess = 0;
4266 goto notfound;
4267 }
4268
4269 /*
4270 * now, put all the correct names back for errors etc.
4271 * also, sock them into dscfg, if the the config was a
4272 * success for one, it will be a redundant but harmless
4273 */
4274
4275 /*
4276 * we could not have reconfigged mode if we
4277 * are not logging, AND the kernel CAN return
4278 * sync as the status of an async set if it is
4279 * currently syncing.. Hence the flags & RDC_LOGGING
4280 */
4281 if (parms.rdc_set->flags & RDC_LOGGING) {
4282 bzero(key, sizeof (key));
4283 (void) snprintf(key, sizeof (key),
4284 "sndr.set%d.mode", i);
4285 if (parms.rdc_set->flags & RDC_ASYNC) {
4286 *doasync = 1;
4287 if (cfg_put_cstring(cfg, key, "async",
4288 strlen("async")) < 0) {
4289 cfgsuccess = 0;
4290 }
4291
4292 } else {
4293 *doasync = 0;
4294 if (cfg_put_cstring(cfg, key, "sync",
4295 strlen("sync")) < 0) {
4296 cfgsuccess = 0;
4297 }
4298 }
4299 }
4300 #ifdef _RDC_CAMPUS
4301 if (*parms.rdc_set->direct_file) {
4302 (void) strncpy(directfile,
4303 parms.rdc_set->direct_file, NSC_MAXPATH);
4304 bzero(key, sizeof (key));
4305 (void) snprintf(key, sizeof (key),
4306 "sndr.set%d.type", i);
4307 if (cfg_put_cstring(cfg, key, directfile,
4308 strlen(directfile)) < 0)
4309 cfgsuccess = 0;
4310 } else {
4311 (void) strncpy(directfile, "-", NSC_MAXPATH);
4312 bzero(key, sizeof (key));
4313 (void) snprintf(key, sizeof (key),
4314 "sndr.set%d.type", i);
4315 if (cfg_put_cstring(cfg, key, directfile,
4316 strlen(directfile)) < 0)
4317 cfgsuccess = 0;
4318 }
4319 #endif
4320
4321 if (*parms.rdc_set->group_name) {
4322 (void) strncpy(group, parms.rdc_set->group_name,
4323 NSC_MAXPATH);
4324 bzero(key, sizeof (key));
4325 (void) snprintf(key, sizeof (key),
4326 "sndr.set%d.group", i);
4327 if (cfg_put_cstring(cfg, key, group,
4328 strlen(group)) < 0)
4329 cfgsuccess = 0;
4330
4331 } else {
4332 (void) strncpy(group, "-", NSC_MAXPATH);
4333 bzero(key, sizeof (key));
4334 (void) snprintf(key, sizeof (key),
4335 "sndr.set%d.group", i);
4336 if (cfg_put_cstring(cfg, key, group,
4337 strlen(group)) < 0)
4338 cfgsuccess = 0;
4339 }
4340
4341 if (*parms.rdc_set->disk_queue) {
4342 (void) strncpy(diskqueue,
4343 parms.rdc_set->disk_queue, NSC_MAXPATH);
4344 } else {
4345 (void) strncpy(diskqueue, "-", NSC_MAXPATH);
4346 }
4347 bzero(key, sizeof (key));
4348 (void) snprintf(key, sizeof (key),
4349 "sndr.set%d.diskq", i);
4350 if (cfg_put_cstring(cfg, key, diskqueue,
4351 strlen(diskqueue)) < 0)
4352 cfgsuccess = 0;
4353
4354 (void) strncpy(frombitmap,
4355 parms.rdc_set->primary.bitmap, NSC_MAXPATH);
4356 bzero(key, sizeof (key));
4357 (void) snprintf(key, sizeof (key),
4358 "sndr.set%d.pbitmap", i);
4359 if (cfg_put_cstring(cfg, key, frombitmap,
4360 strlen(frombitmap)) < 0)
4361 cfgsuccess = 0;
4362
4363 (void) strncpy(tobitmap,
4364 parms.rdc_set->secondary.bitmap, NSC_MAXPATH);
4365 bzero(key, sizeof (key));
4366 (void) snprintf(key, sizeof (key),
4367 "sndr.set%d.sbitmap", i);
4368 if (cfg_put_cstring(cfg, key, tobitmap,
4369 strlen(tobitmap)) < 0)
4370 cfgsuccess = 0;
4371
4372 bzero(key, sizeof (key));
4373 (void) snprintf(key, sizeof (key),
4374 "sndr.set%d.cnode", i);
4375 if (clustered)
4376 if (cfg_put_cstring(cfg, key, ctag,
4377 strlen(ctag)) < 0)
4378 cfgsuccess = 0;
4379 notfound:
4380 if (cfgsuccess == 0) {
4381 rdc_warn(NULL, gettext("unable to update "
4382 "configuration storage"));
4383 }
4384 } else {
4385 spcs_log("sndr", NULL,
4386 "%s %s %s %s %s %s %s %s\n%s",
4387 program, rdc_decode_flag(flag, parms.options),
4388 fromhost, fromfile, frombitmap,
4389 tohost, tofile, tobitmap,
4390 gettext("unable to update config file"));
4391 rdc_err(&ustatus,
4392 gettext("Remote Mirror: unable to update "
4393 "config file"));
4394
4395 }
4396 }
4397
4398 if (flag == RDC_CMD_HEALTH && errno == 0) {
4399 (void) fprintf(stderr,
4400 gettext("Remote Mirror: %s %s %s %s %s %s\n"),
4401 fromhost, fromfile,
4402 frombitmap, tohost, tofile, tobitmap);
4403
4404 if (ret == RDC_ACTIVE)
4405 (void) fprintf(stderr, "Active\n");
4406 else if (ret == RDC_INACTIVE)
4407 (void) fprintf(stderr, "Inactive\n");
4408 else
4409 (void) fprintf(stderr, "Unknown\n");
4410 } else if (ret != SPCS_S_OK) {
4411 if (errno == RDC_EEINVAL) {
4412 spcs_log("sndr", NULL,
4413 "%s %s %s %s %s %s %s %s\n%s",
4414 program, rdc_decode_flag(flag, parms.options),
4415 fromhost, fromfile, frombitmap,
4416 tohost, tofile, tobitmap,
4417 gettext("invalid command option"));
4418 rdc_err(&ustatus,
4419 gettext("Remote Mirror: invalid command option "
4420 "'%s'"),
4421 rdc_decode_flag(flag, parms.options));
4422 }
4423 }
4424 if (flag == RDC_CMD_STATUS) {
4425 (void) fprintf(stderr,
4426 gettext("Remote Mirror: %s %s %s %s %s %s\n"),
4427 fromhost, fromfile,
4428 frombitmap, tohost, tofile, tobitmap);
4429 (void) fprintf(stderr, "flags 0x%x\n", parms.rdc_set->flags |
4430 parms.rdc_set->sync_flags | parms.rdc_set->bmap_flags);
4431 } else if (success) {
4432 spcs_log("sndr", NULL,
4433 gettext("%s %s %s %s %s %s %s %s\nSuccessful"),
4434 program, rdc_decode_flag(flag, parms.options),
4435 fromhost, fromfile, frombitmap,
4436 tohost, tofile, tobitmap);
4437 if (flag == RDC_CMD_TUNABLE)
4438 spcslog_tunable(tohost, tofile);
4439 }
4440
4441 if (cfg && perform_autosv()) {
4442 spcs_s_ufree(&ustatus);
4443 /* figure out which are the local volumes */
4444 if (parms.options & RDC_OPT_PRIMARY) {
4445 vol1 = fromfile;
4446 vol2 = frombitmap;
4447 if ((diskqueue && diskqueue[0]) &&
4448 (strncmp(diskqueue, "-", 1) != 0))
4449 vol3 = diskqueue;
4450 else
4451 vol3 = NULL;
4452 } else {
4453 vol1 = tofile;
4454 vol2 = tobitmap;
4455 vol3 = NULL;
4456 if ((flag == RDC_CMD_ENABLE) &&
4457 (strlen(diskqueue) > 0) &&
4458 (strncmp(diskqueue, "-", 1)) != 0) {
4459 rdc_warn(NULL,
4460 gettext("enabling a disk queue on a "
4461 "Remote Mirror secondary is not allowed. "
4462 "(%s) ignored"), diskqueue);
4463 }
4464 }
4465
4466 if (flag == RDC_CMD_ENABLE) {
4467 ustatus = spcs_s_ucreate();
4468 /*
4469 * SV-enable all local volumes
4470 * if the sv_enables fail, disable the sndr vols
4471 * that we just enabled
4472 * and return -1 so the cfg_commit() won't happen
4473 */
4474
4475 if (nsc_lookup(volhash, vol1) == NULL) {
4476 if (cfg_vol_enable(cfg, vol1, ctag, "sndr")
4477 < 0) {
4478 spcs_log("sndr", NULL,
4479 "sv enable failed for %s, "
4480 "disabling Remote Mirror set %s:%s",
4481 vol1, tohost, tofile);
4482 /*
4483 * warn here, but we are going to exit
4484 * we want to catch any errors on the
4485 * way down, then exit
4486 */
4487
4488 rdc_warn(NULL,
4489 "unable to sv enable %s\n"
4490 "disabling Remote Mirror set %s:%s",
4491 vol1, tohost, tofile);
4492
4493 parms.command = RDC_CMD_DISABLE;
4494 ret = RDC_IOCTL(RDC_CONFIG, &parms,
4495 NULL, 0, 0, 0, ustatus);
4496 if (ret != SPCS_S_OK) {
4497 (void) fprintf(stderr,
4498 gettext("Remote Mirror:"
4499 " %s %s %s %s %s %s\n"),
4500 fromhost, fromfile,
4501 frombitmap, tohost, tofile,
4502 tobitmap);
4503 spcs_log("sndr", &ustatus,
4504 "%s %s %s %s %s %s %s %s",
4505 program,
4506 rdc_decode_flag(parms.command,
4507 parms.options),
4508 fromhost,
4509 fromfile, frombitmap,
4510 tohost, tofile, tobitmap);
4511 rdc_err(&ustatus, 0);
4512 }
4513 /*
4514 * ok, we should've reported any errs
4515 * exit explictly
4516 */
4517 exit(1);
4518
4519 }
4520 }
4521 if (vol2 && nsc_lookup(volhash, vol2) == NULL) {
4522 if (cfg_vol_enable(cfg, vol2, ctag, "sndr")
4523 < 0) {
4524 spcs_log("sndr", NULL,
4525 "sv enable failed for %s, "
4526 "disabling Remote Mirror set %s:%s",
4527 vol1, tohost, tofile);
4528 /*
4529 * warn here, but we are going to exit
4530 * we want to catch any errors on the
4531 * way down, then exit
4532 */
4533
4534 rdc_warn(NULL,
4535 "unable to sv enable %s\n"
4536 "disabling Remote Mirror set %s:%s",
4537 vol2, tohost, tofile);
4538
4539 parms.command = RDC_CMD_DISABLE;
4540 ret = RDC_IOCTL(RDC_CONFIG, &parms,
4541 NULL, 0, 0, 0, ustatus);
4542 if (ret != SPCS_S_OK) {
4543 (void) fprintf(stderr,
4544 gettext("Remote Mirror:"
4545 " %s %s %s %s %s %s\n"),
4546 fromhost, fromfile,
4547 frombitmap, tohost, tofile,
4548 tobitmap);
4549 spcs_log("sndr", &ustatus,
4550 "%s %s %s %s %s %s %s %s",
4551 program,
4552 rdc_decode_flag(parms.command,
4553 parms.options),
4554 fromhost,
4555 fromfile, frombitmap,
4556 tohost, tofile, tobitmap);
4557 rdc_err(&ustatus, 0);
4558 }
4559 /*
4560 * ok, we should've reported any errs
4561 * exit explictly
4562 */
4563 exit(1);
4564
4565 }
4566 }
4567
4568 if (vol3 && nsc_lookup(volhash, diskqueue) == NULL) {
4569 if (cfg_vol_enable(cfg, diskqueue, ctag, "sndr")
4570 < 0) {
4571 spcs_log("sndr", NULL,
4572 "sv enable failed for %s, "
4573 "disabling Remote Mirror set %s:%s",
4574 diskqueue, tohost, tofile);
4575 if (cfg_vol_disable(cfg, vol1, ctag,
4576 "sndr") < 0)
4577 rdc_warn(NULL, gettext("Failed to "
4578 "remove volume [%s] from "
4579 "configuration"), vol1);
4580 if (cfg_vol_disable(cfg, vol2, ctag,
4581 "sndr") < 0)
4582 rdc_warn(NULL, gettext("Failed to "
4583 "remove volume [%s] from "
4584 "configuration"), vol2);
4585
4586 /*
4587 * warn here, but we are going to exit
4588 * we want to catch any errors on the
4589 * way down, then exit
4590 */
4591
4592 rdc_warn(NULL,
4593 "unable to sv enable %s\n"
4594 "disabling Remote Mirror set %s:%s",
4595 diskqueue, tohost, tofile);
4596
4597 parms.command = RDC_CMD_DISABLE;
4598 ret = RDC_IOCTL(RDC_CONFIG, &parms,
4599 NULL, 0, 0, 0, ustatus);
4600 if (ret != SPCS_S_OK) {
4601 (void) fprintf(stderr,
4602 gettext("Remote Mirror:"
4603 " %s %s %s %s %s %s\n"),
4604 fromhost, fromfile,
4605 frombitmap, tohost, tofile,
4606 tobitmap);
4607 spcs_log("sndr", &ustatus,
4608 "%s %s %s %s %s %s %s %s",
4609 program,
4610 rdc_decode_flag(parms.command,
4611 parms.options),
4612 fromhost,
4613 fromfile, frombitmap,
4614 tohost, tofile, tobitmap);
4615 rdc_err(&ustatus, 0);
4616 }
4617 /*
4618 * ok, we should've reported any errs
4619 * exit explictly
4620 */
4621 exit(1);
4622
4623 }
4624 }
4625 } else if (flag == RDC_CMD_DISABLE) {
4626 /*
4627 * If we're no longer using a volume, SV-disable it
4628 */
4629 volcount_t *vc;
4630
4631 vc = nsc_lookup(volhash, vol1);
4632 if (vc && (1 == vc->count)) {
4633 if (cfg_vol_disable(cfg, vol1, ctag, "sndr")
4634 < 0)
4635 rdc_warn(NULL, gettext("Failed to "
4636 "remove volume [%s] from "
4637 "configuration"), vol1);
4638
4639 } else if (!vc) {
4640 rdc_warn(NULL,
4641 gettext("Unable to find %s in config"),
4642 vol1);
4643 }
4644
4645 if (vol2) {
4646 vc = nsc_lookup(volhash, vol2);
4647 if (vc && (1 == vc->count)) {
4648 if (cfg_vol_disable(cfg, vol2, ctag,
4649 "sndr") < 0)
4650 rdc_warn(NULL, gettext("Failed to "
4651 "remove volume [%s] from "
4652 "configuration"), vol2);
4653 } else if (!vc) {
4654 rdc_warn(NULL, gettext("Unable to find"
4655 " %s in config"), vol2);
4656 }
4657 }
4658
4659 if (diskqueue != NULL && strlen(diskqueue) > 0) {
4660 vc = nsc_lookup(volhash, diskqueue);
4661 if (vc && (1 == vc->count)) {
4662 if (cfg_vol_disable(cfg, diskqueue, ctag,
4663 "sndr") < 0)
4664 rdc_warn(NULL, gettext("Failed to "
4665 "remove disk queue [%s] from "
4666 "configuration"), diskqueue);
4667 } else if (!vc) {
4668 rdc_warn(NULL, gettext("Unable to find"
4669 " %s in config"), diskqueue);
4670 }
4671 }
4672 /* WARNING about to go to 4 space indenting */
4673 } else if (flag == RDC_CMD_RECONFIG) {
4674 volcount_t *vc;
4675 /* disable ex-bitmaps, enable new bitmaps */
4676 if (parms.options & RDC_OPT_PRIMARY) {
4677 if (strcmp(orig_fbmp, frombitmap) != 0) {
4678 vc = nsc_lookup(volhash, orig_fbmp);
4679 if (vc && (vc->count == 1)) {
4680 if (cfg_vol_disable(cfg, orig_fbmp, ctag,
4681 "sndr") < 0)
4682 rdc_warn(NULL, gettext("Failed to "
4683 "remove bitmap [%s] from "
4684 "configuration"), orig_fbmp);
4685 } else if (!vc) {
4686 rdc_warn(NULL, gettext("Unable to find "
4687 "%s in config"), orig_fbmp);
4688 }
4689 if (nsc_lookup(volhash, frombitmap) == NULL) {
4690 if (cfg_vol_enable(cfg, frombitmap, ctag,
4691 "sndr") < 0) {
4692 spcs_log("sndr", NULL,
4693 "reconfig sv enable failed for %s, "
4694 "disabling Remote Mirror set %s:%s",
4695 frombitmap, tohost, tofile);
4696 rdc_warn(NULL,
4697 "unable to sv enable %s\n"
4698 "disabling Remote Mirror set %s:%s",
4699 frombitmap, tohost, tofile);
4700 parms.command = RDC_CMD_DISABLE;
4701 ret = RDC_IOCTL(RDC_CONFIG, &parms,
4702 NULL, 0, 0, 0, ustatus);
4703 if (ret != SPCS_S_OK) {
4704 (void) fprintf(stderr,
4705 gettext("Remote Mirror:"
4706 " %s %s %s %s %s %s\n"),
4707 fromhost, fromfile,
4708 frombitmap, tohost, tofile,
4709 tobitmap);
4710 spcs_log("sndr", &ustatus,
4711 "%s %s %s %s %s %s %s %s",
4712 program,
4713 rdc_decode_flag(parms.command,
4714 parms.options),
4715 fromhost,
4716 fromfile, frombitmap,
4717 tohost, tofile, tobitmap);
4718 rdc_warn(&ustatus, 0);
4719 }
4720 exit(1);
4721 }
4722 }
4723 } else if ((orig_diskq[0] != '\0') &&
4724 (strcmp(orig_diskq, diskqueue) != 0)) {
4725 vc = nsc_lookup(volhash, orig_diskq);
4726 if (vc && (vc->count == 1)) {
4727 if (cfg_vol_disable(cfg, orig_diskq, ctag,
4728 "sndr") < 0)
4729 rdc_warn(NULL, gettext("Failed to "
4730 "remove disk queue [%s] from "
4731 "configuration"), orig_diskq);
4732 } else if (!vc) {
4733 rdc_warn(NULL, gettext("Unable to find "
4734 "%s in config"), orig_diskq);
4735 }
4736 if (vol3 &&
4737 (nsc_lookup(volhash, diskqueue) == NULL)) {
4738 if (cfg_vol_enable(cfg, diskqueue, ctag,
4739 "sndr") < 0) {
4740 spcs_log("sndr", NULL, "reconfig sv "
4741 "enable of diskqueue %s failed, "
4742 "disabling Remote Mirror set %s:%s",
4743 diskqueue, tohost, tofile);
4744 rdc_warn(NULL, "reconfig sv "
4745 "enable of diskqueue %s failed."
4746 "disabling Remote Mirror set %s:%s",
4747 diskqueue, tohost, tofile);
4748 parms.command = RDC_CMD_DISABLE;
4749 ret = RDC_IOCTL(RDC_CONFIG, &parms,
4750 NULL, 0, 0, 0, ustatus);
4751 if (ret != SPCS_S_OK) {
4752 (void) fprintf(stderr,
4753 gettext("Remote Mirror:"
4754 " %s %s %s %s %s %s\n"),
4755 fromhost, fromfile,
4756 frombitmap, tohost, tofile,
4757 tobitmap);
4758 spcs_log("sndr", &ustatus,
4759 "%s %s %s %s %s %s %s %s",
4760 program,
4761 rdc_decode_flag(parms.command,
4762 parms.options),
4763 fromhost,
4764 fromfile, frombitmap,
4765 tohost, tofile, tobitmap);
4766 rdc_warn(&ustatus, 0);
4767 }
4768 exit(1);
4769 }
4770 }
4771 }
4772 } else if (flag != RDC_OPT_PRIMARY) {
4773 if (strcmp(orig_tbmp, tobitmap) != 0) {
4774 vc = nsc_lookup(volhash, orig_tbmp);
4775 if (vc && (vc->count == 1)) {
4776 if (cfg_vol_disable(cfg, orig_tbmp, ctag,
4777 "sndr") < 0)
4778 rdc_warn(NULL, gettext("Failed to "
4779 "remove bitmap [%s] from "
4780 "configuration"), orig_tbmp);
4781 } else if (!vc) {
4782 rdc_warn(NULL,
4783 gettext("Unable to find %s in config"),
4784 orig_tbmp);
4785 }
4786 if (nsc_lookup(volhash, tobitmap) == NULL) {
4787 if (cfg_vol_enable(cfg, tobitmap, ctag,
4788 "sndr") < 0) {
4789 spcs_log("sndr", NULL,
4790 "reconfig sv enable failed for %s, "
4791 "disabling Remote Mirror set %s:%s",
4792 tobitmap, tohost, tofile);
4793 rdc_warn(NULL,
4794 "unable to sv enable %s\n"
4795 "disabling Remote Mirror set %s:%s",
4796 tobitmap, tohost, tofile);
4797 parms.command = RDC_CMD_DISABLE;
4798 ret = RDC_IOCTL(RDC_CONFIG, &parms,
4799 NULL, 0, 0, 0, ustatus);
4800 if (ret != SPCS_S_OK) {
4801 (void) fprintf(stderr,
4802 gettext("Remote Mirror:"
4803 " %s %s %s %s %s %s\n"),
4804 fromhost, fromfile,
4805 frombitmap, tohost, tofile,
4806 tobitmap);
4807 spcs_log("sndr", &ustatus,
4808 "%s %s %s %s %s %s %s %s",
4809 program,
4810 rdc_decode_flag(parms.command,
4811 parms.options),
4812 fromhost, fromfile, frombitmap,
4813 tohost, tofile, tobitmap);
4814 rdc_warn(&ustatus, 0);
4815 }
4816 exit(1);
4817 }
4818 }
4819 }
4820 }
4821 /* END 4 space indenting */
4822 }
4823 }
4824 spcs_s_ufree(&ustatus);
4825
4826 return (0);
4827 }
4828
4829
4830 /*
4831 * read_config()
4832 *
4833 * DESCRIPTION: Read the lines in a configuration file and return the
4834 * pairs of devices to be mirrored/enabled/disabled/updated.
4835 * The format for the configuration file is as follows:
4836 *
4837 * fromhost fromfile frombitmap tohost tofile tobitmap
4838 *
4839 * where fromfile is the primary device which is local to the
4840 * fromhost subsystem, tofile is the secondary device which is
4841 * local to the tohost subsystem, and type is 1 if the device
4842 * a simckd device or 0 otherwise. Any line preceeded by a '#'
4843 * is considered to be a comment.
4844 *
4845 * Inputs:
4846 * char *config_file Name of configuration file for rdcadm
4847 *
4848 * Outputs:
4849 * int i Number of pairs of devices
4850 *
4851 * Side Effects: The 0 to i-1 entries in the pair_list are filled.
4852 *
4853 */
4854
4855 int
4856 read_config(int flag, char *config_file, char *group_arg, char *ctag_arg)
4857 {
4858 int ret;
4859 char dsk_flagstr[NSC_MAXPATH];
4860 char line[1024], tmp_line[1024];
4861 char fromhost[MAX_RDC_HOST_SIZE];
4862 char fromfile[NSC_MAXPATH];
4863 char frombitmap[NSC_MAXPATH];
4864 char tohost[MAX_RDC_HOST_SIZE];
4865 char tofile[NSC_MAXPATH];
4866 char tobitmap[NSC_MAXPATH];
4867 char directfile[NSC_MAXPATH];
4868 char sync[16];
4869 int doasync;
4870 FILE *fp;
4871 int i, j;
4872 char *extra_args[EXTRA_ARGS];
4873 char *tmp, *split_str = " \t\n";
4874
4875 for (j = 0; j < EXTRA_ARGS; j++)
4876 extra_args[j] = malloc(NSC_MAXPATH);
4877
4878 if (!(fp = fopen(config_file, "r"))) {
4879 rdc_err(NULL, gettext("error opening %s"), config_file);
4880 }
4881
4882 i = 0;
4883 while (fgets(line, sizeof (line), fp)) {
4884 if (line[0] == '#') /* this is a comment */
4885 continue;
4886
4887 ret = 0;
4888 (void) strcpy(tmp_line, line);
4889
4890 if ((tmp = strtok(tmp_line, split_str)) != NULL) {
4891 if (strlen(tmp) >= MAX_RDC_HOST_SIZE) {
4892 (void) printf(gettext("hostname is longer than %d "
4893 "characters\n"), (MAX_RDC_HOST_SIZE - 1));
4894 continue;
4895 }
4896 (void) strncpy(fromhost, tmp, (MAX_RDC_HOST_SIZE - 1));
4897 fromhost[(MAX_RDC_HOST_SIZE - 1)] = '\0';
4898 ret++;
4899 }
4900 if ((tmp = strtok(NULL, split_str)) != NULL) {
4901 if (strlen(tmp) >= NSC_MAXPATH) {
4902 (void) printf(gettext(
4903 "device name is longer than %d "
4904 "characters\n"), (NSC_MAXPATH - 1));
4905 continue;
4906 }
4907 (void) strncpy(fromfile, tmp, (NSC_MAXPATH - 1));
4908 fromfile[(NSC_MAXPATH - 1)] = '\0';
4909 ret++;
4910 }
4911 if ((tmp = strtok(NULL, split_str)) != NULL) {
4912 if (strlen(tmp) >= NSC_MAXPATH) {
4913 (void) printf(gettext(
4914 "device name is longer than %d "
4915 "characters\n"), (NSC_MAXPATH - 1));
4916 continue;
4917 }
4918 (void) strncpy(frombitmap, tmp, (NSC_MAXPATH - 1));
4919 frombitmap[(NSC_MAXPATH - 1)] = '\0';
4920 ret++;
4921 }
4922 if ((tmp = strtok(NULL, split_str)) != NULL) {
4923 if (strlen(tmp) >= MAX_RDC_HOST_SIZE) {
4924 (void) printf(gettext(
4925 "hostname is longer than %d "
4926 "characters\n"), (MAX_RDC_HOST_SIZE - 1));
4927 continue;
4928 }
4929 (void) strncpy(tohost, tmp, (MAX_RDC_HOST_SIZE - 1));
4930 tohost[(MAX_RDC_HOST_SIZE - 1)] = '\0';
4931 ret++;
4932 }
4933 if ((tmp = strtok(NULL, split_str)) != NULL) {
4934 if (strlen(tmp) >= NSC_MAXPATH) {
4935 (void) printf(gettext(
4936 "device name is longer than %d "
4937 "characters\n"), (NSC_MAXPATH - 1));
4938 continue;
4939 }
4940 (void) strncpy(tofile, tmp, (NSC_MAXPATH - 1));
4941 tofile[(NSC_MAXPATH - 1)] = '\0';
4942 ret++;
4943 }
4944 if ((tmp = strtok(NULL, split_str)) != NULL) {
4945 if (strlen(tmp) >= NSC_MAXPATH) {
4946 (void) printf(gettext(
4947 "device name is longer than %d "
4948 "characters\n"), (NSC_MAXPATH - 1));
4949 continue;
4950 }
4951 (void) strncpy(tobitmap, tmp, (NSC_MAXPATH - 1));
4952 tobitmap[(NSC_MAXPATH - 1)] = '\0';
4953 ret++;
4954 }
4955 if ((tmp = strtok(NULL, split_str)) != NULL) {
4956 (void) strncpy(dsk_flagstr, tmp, 15);
4957 dsk_flagstr[15] = '\0';
4958 ret++;
4959 }
4960 if ((tmp = strtok(NULL, split_str)) != NULL) {
4961 (void) strncpy(sync, tmp, 15);
4962 sync[15] = '\0';
4963 ret++;
4964 }
4965 for (j = 0; j < EXTRA_ARGS; j++) {
4966 if ((tmp = strtok(NULL, split_str)) != NULL) {
4967 (void) strncpy(extra_args[j], tmp,
4968 (NSC_MAXPATH - 1));
4969 extra_args[j][(NSC_MAXPATH - 1)] = '\0';
4970 ret++;
4971 }
4972 }
4973
4974 if (ret == 0) /* this is a blank line */
4975 continue;
4976
4977 if (ret < 8) {
4978 (void) fclose(fp);
4979 rdc_warn(NULL,
4980 gettext("invalid format in %s"), config_file);
4981 rdc_err(NULL, "%s", line);
4982 }
4983
4984 if (i >= rdc_maxsets) {
4985 (void) fclose(fp);
4986 rdc_err(NULL,
4987 gettext("number of Remote Mirror sets exceeds %d"),
4988 rdc_maxsets);
4989 }
4990
4991 #ifdef _RDC_CAMPUS
4992 if (dsk_flagstr[0] == '/') {
4993 /* fcal directio */
4994 (void) strncpy(directfile, dsk_flagstr, NSC_MAXPATH);
4995 } else if (strcmp(dsk_flagstr, "ip") != 0) {
4996 #else
4997 if (strcmp(dsk_flagstr, "ip") != 0) {
4998 #endif
4999 (void) fclose(fp);
5000 rdc_err(NULL,
5001 #ifdef _RDC_CAMPUS
5002 gettext("ip/fcal specification missing"));
5003 #else
5004 gettext("ip specification missing"));
5005 #endif
5006 } else
5007 (void) strcpy(directfile, "ip");
5008
5009 if (strcmp(sync, "sync") == 0)
5010 doasync = 0;
5011 else if (strcmp(sync, "async") == 0)
5012 doasync = 1;
5013 else {
5014 (void) fclose(fp);
5015 rdc_err(NULL,
5016 gettext("sync/async specification missing"));
5017 }
5018 (void) strncpy(pair_list[i].fhost, fromhost, MAX_RDC_HOST_SIZE);
5019 (void) strncpy(pair_list[i].ffile, fromfile, NSC_MAXPATH);
5020 (void) strncpy(pair_list[i].fbitmap, frombitmap, NSC_MAXPATH);
5021 (void) strncpy(pair_list[i].thost, tohost, MAX_RDC_HOST_SIZE);
5022 (void) strncpy(pair_list[i].tfile, tofile, NSC_MAXPATH);
5023 (void) strncpy(pair_list[i].tbitmap, tobitmap, NSC_MAXPATH);
5024 (void) strncpy(pair_list[i].directfile, directfile,
5025 NSC_MAXPATH);
5026 pair_list[i].doasync = doasync;
5027
5028 if (gethost_netaddrs(fromhost, tohost,
5029 (char *)pair_list[i].fnetaddr,
5030 (char *)pair_list[i].tnetaddr) < 0) {
5031 (void) fclose(fp);
5032 rdc_err(NULL, gettext("unable to determine IP "
5033 "addresses for hosts %s, %s"), fromhost, tohost);
5034 }
5035
5036 if (parse_extras(ret - 8, extra_args, i) < 0) {
5037 (void) fclose(fp);
5038 rdc_err(NULL, gettext("illegal option in:\n%s"),
5039 line);
5040 }
5041
5042 if (flag == RDC_CMD_ENABLE || flag == RDC_CMD_RECONFIG) {
5043 if (ctag_check(fromhost, fromfile, frombitmap,
5044 tohost, tofile, tobitmap, pair_list[i].ctag,
5045 pair_list[i].diskqueue) < 0)
5046 continue; /* Ignore illegal sets */
5047 if (pair_diskqueue_check(i))
5048 continue; /* ignore sets with incorrect diskq */
5049 }
5050
5051 /* Filter according to ctag and group arguments */
5052 if (strcmp(ctag_arg, "") &&
5053 strncmp(ctag_arg, pair_list[i].ctag,
5054 MAX_RDC_HOST_SIZE))
5055 continue;
5056 if (strcmp(group_arg, "") &&
5057 strncmp(group_arg, pair_list[i].group, NSC_MAXPATH))
5058 continue;
5059
5060 i++;
5061 }
5062 (void) fclose(fp);
5063 for (j = 0; j < EXTRA_ARGS; j++)
5064 free(extra_args[j]);
5065 return (i);
5066 }
5067
5068
5069 /*
5070 * read_libcfg()
5071 *
5072 * DESCRIPTION: Read the relevant config info via libcfg
5073 *
5074 * Outputs:
5075 * int i Number of pairs of devices
5076 *
5077 * Side Effects: The 0 to i-1 entries in the pair_list are filled.
5078 *
5079 */
5080 static int
5081 read_libcfg(int flag, char *group_arg, char *ctag_arg)
5082 {
5083 int rc;
5084 CFGFILE *cfg;
5085 int i;
5086 _sd_dual_pair_t *pairp;
5087 char buf[CFG_MAX_BUF];
5088 char key[CFG_MAX_KEY];
5089 int setnumber;
5090
5091 if ((cfg = cfg_open(NULL)) == NULL)
5092 rdc_err(NULL, gettext("unable to access configuration"));
5093
5094 if (!cfg_lock(cfg, CFG_RDLOCK))
5095 rdc_err(NULL, gettext("unable to lock configuration"));
5096
5097 if (strcmp(ctag_arg, ""))
5098 cfg_resource(cfg, ctag_arg);
5099 else {
5100 cfg_resource(cfg, NULL);
5101 }
5102
5103 setnumber = 0;
5104 /*CSTYLED*/
5105 for (i = 0; i < rdc_maxsets;) {
5106 setnumber++;
5107
5108 bzero(buf, CFG_MAX_BUF);
5109 (void) snprintf(key, sizeof (key), "sndr.set%d", setnumber);
5110 rc = cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF);
5111 if (rc < 0)
5112 break;
5113
5114 pairp = &pair_list[i];
5115 if (parse_cfg_buf(buf, pairp, NULL))
5116 continue;
5117
5118 if (strcmp(group_arg, "") &&
5119 strncmp(group_arg, pairp->group, NSC_MAXPATH))
5120 continue;
5121
5122 if (flag == RDC_CMD_RECONFIG) {
5123 if (reconfig_pbitmap)
5124 (void) strncpy(pairp->fbitmap, reconfig_pbitmap,
5125 NSC_MAXPATH);
5126 if (reconfig_sbitmap)
5127 (void) strncpy(pairp->tbitmap, reconfig_sbitmap,
5128 NSC_MAXPATH);
5129 #ifdef _RDC_CAMPUS
5130 if (reconfig_direct)
5131 (void) strncpy(directfile, reconfig_direct,
5132 NSC_MAXPATH);
5133 #endif
5134 if (reconfig_group)
5135 (void) strncpy(pairp->group, reconfig_group,
5136 NSC_MAXPATH);
5137
5138 if (strlen(reconfig_ctag) > 0)
5139 (void) strncpy(pairp->ctag, reconfig_ctag,
5140 MAX_RDC_HOST_SIZE);
5141
5142 if (reconfig_doasync != -1)
5143 pairp->doasync = reconfig_doasync;
5144 }
5145
5146
5147 if (ctag_check(pairp->fhost, pairp->ffile,
5148 pairp->fbitmap, pairp->thost, pairp->tfile,
5149 pairp->tbitmap, pairp->ctag, pairp->diskqueue) < 0)
5150 continue; /* Ignore illegal sets */
5151
5152 if (gethost_netaddrs(pairp->fhost, pairp->thost,
5153 (char *)pairp->fnetaddr,
5154 (char *)pairp->tnetaddr) < 0) {
5155 rdc_err(NULL, gettext("unable to determine IP "
5156 "addresses for hosts %s, %s"), pairp->fhost,
5157 pairp->thost);
5158 }
5159
5160 i++;
5161 }
5162
5163 cfg_close(cfg);
5164 return (i);
5165 }
5166
5167 void
5168 q_usage(int prhdr)
5169 {
5170 if (prhdr)
5171 (void) fprintf(stderr, gettext("disk queue usage:\n"));
5172
5173 (void) fprintf(stderr,
5174 gettext("\t%s -g <group> -q a <vol>\t\tadd disk queue to "
5175 "group\n"), program);
5176 (void) fprintf(stderr,
5177 gettext("\t%s -g <group> -q d \t\tremove disk queue from"
5178 " group\n"), program);
5179 (void) fprintf(stderr,
5180 gettext("\t%s -g <group> -q r <newvol>\treplace disk queue for a"
5181 " group\n"), program);
5182
5183 (void) fprintf(stderr,
5184 gettext("\t%s -q a <vol> <shost>:<sdev>\tadd disk queue to "
5185 "a set\n"), program);
5186 (void) fprintf(stderr,
5187 gettext("\t%s -q d <shost>:<sdev>\t\tremove disk queue from "
5188 "a set\n"), program);
5189 (void) fprintf(stderr,
5190 gettext("\t%s -q r <newvol> <shost>:<sdev>\treplace disk queue for "
5191 "a set\n"), program);
5192
5193 }
5194
5195 static void
5196 usage()
5197 {
5198 (void) fprintf(stderr, gettext("usage:\n"));
5199
5200 (void) fprintf(stderr,
5201 gettext("\t%s [opts] -a {on | off} [set]\t"
5202 "set autosync\n"), program);
5203
5204 (void) fprintf(stderr,
5205 gettext("\t%s [opts] -A <asyncthr> [set]\t"
5206 "set the number of asynchronous\n\t\t\t\t\t\tthreads\n"),
5207 program);
5208
5209 (void) fprintf(stderr,
5210 gettext("\t%s [opts] -d [set]\t\t\t"
5211 "disable\n"), program);
5212
5213 (void) fprintf(stderr,
5214 gettext("\t%s [opts] -e [set]\t\t\t"
5215 "enable with bits in bitmap set\n"), program);
5216
5217 (void) fprintf(stderr,
5218 gettext("\t%s [opts] -E [set]\t\t\t"
5219 "enable with bits in bitmap clear\n"), program);
5220
5221 (void) fprintf(stderr,
5222 gettext("\t%s [opts] -F <maxqfbas> [set]\t"
5223 "set maximum fbas to queue\n"), program);
5224
5225 (void) fprintf(stderr,
5226 gettext("\t%s [opts] -D {block | noblock} [set]\t"
5227 "set disk queue blocking mode\n"), program);
5228
5229 (void) fprintf(stderr,
5230 gettext("\t%s [opts] -H [set]\t\t\t"
5231 "report link health\n"), program);
5232
5233 (void) fprintf(stderr,
5234 gettext("\t%s -h\t\t\t\tusage message\n"), program);
5235
5236 (void) fprintf(stderr,
5237 gettext("\t%s -I a <master> <shadow> <bitmap>\t"
5238 "add ndr_ii config entry\n"), program);
5239
5240 (void) fprintf(stderr,
5241 gettext("\t%s -I d <master> <shadow> <bitmap>\t"
5242 "delete ndr_ii config entry\n"), program);
5243
5244 (void) fprintf(stderr,
5245 gettext("\t%s [opts] -i [set]\t\t\t"
5246 "print sets in config file format\n"), program);
5247
5248 (void) fprintf(stderr,
5249 gettext("\t%s [opts] -l [set]\t\t\t"
5250 "enter logging mode\n"), program);
5251
5252 (void) fprintf(stderr,
5253 gettext("\t%s [opts] -m [set]\t\t\t"
5254 "full sync\n"), program);
5255
5256 (void) fprintf(stderr,
5257 gettext("\t%s [opts] -m -r [set]\t\t"
5258 "full reverse sync\n"), program);
5259
5260 (void) fprintf(stderr,
5261 gettext("\t%s [opts] -P [set]\t\t\t"
5262 "print sets verbose\n"), program);
5263
5264 (void) fprintf(stderr,
5265 gettext("\t%s [opts] -p [set]\t\t\t"
5266 "print sets\n"), program);
5267
5268 (void) fprintf(stderr,
5269 gettext("\t%s [opts] -R\t\t\t"
5270 "reset error conditions\n"), program);
5271
5272 (void) fprintf(stderr,
5273 gettext("\t%s [opts] -R b p <bitmap> [set]\t"
5274 "reconfig primary bitmap\n"), program);
5275
5276 (void) fprintf(stderr,
5277 gettext("\t%s [opts] -R b s <bitmap> [set]\t"
5278 "reconfig secondary bitmap\n"), program);
5279
5280 if (clustered)
5281 (void) fprintf(stderr,
5282 gettext("\t%s [opts] -R C <ctag> [set]\t"
5283 "reconfig cluster tag\n"), program);
5284
5285 #ifdef _RDC_CAMPUS
5286 (void) fprintf(stderr,
5287 gettext("\t%s [opts] -R d <pathname> [set]\t"
5288 "reconfig campus direct file\n"), program);
5289 #endif
5290
5291 (void) fprintf(stderr,
5292 gettext("\t%s [opts] -R -f <volset-file> \t"
5293 "reconfig from file\n"), program);
5294
5295 (void) fprintf(stderr,
5296 gettext("\t%s [opts] -R g <group> [set]\t"
5297 "reconfig group\n"), program);
5298
5299 (void) fprintf(stderr,
5300 gettext("\t%s [opts] -R m {sync|async} [set]\t"
5301 "reconfig mode\n"), program);
5302
5303 if (allow_role)
5304 (void) fprintf(stderr,
5305 gettext("\t%s [opts] -R r [set]\t\t"
5306 "reverse roles\n"), program);
5307
5308 (void) fprintf(stderr,
5309 gettext("\t%s [opts] -u [set]\t\t\t"
5310 "update sync\n"), program);
5311
5312 (void) fprintf(stderr,
5313 gettext("\t%s [opts] -u -r [set]\t\t"
5314 "update reverse sync\n"), program);
5315
5316 (void) fprintf(stderr,
5317 gettext("\t%s -v\t\t\t\tdisplay version\n"), program);
5318
5319 (void) fprintf(stderr,
5320 gettext("\t%s [opts] -W <maxwrites> [set]\t"
5321 "set maximum writes to queue\n"), program);
5322
5323 (void) fprintf(stderr,
5324 gettext("\t%s [opts] -w [set]\t\t\t"
5325 "wait\n"), program);
5326 q_usage(0);
5327
5328 (void) fprintf(stderr, gettext("\nopts:\n"));
5329 (void) fprintf(stderr, gettext("\t-n\t\tnon-interactive mode "
5330 "(not valid for print operations)\n"));
5331 (void) fprintf(stderr, gettext(
5332 "\t-g <group>\toperate on sets in group only "
5333 "(not valid for enable\n\t\t\toperations)\n"));
5334 if (clustered)
5335 (void) fprintf(stderr,
5336 gettext("\t-C <ctag>\tignore sets not in cluster ctag "
5337 "(not valid for enable\n\t\t\toperations)\n"));
5338
5339 (void) fprintf(stderr, gettext("\nset:\n"));
5340 if (clustered)
5341 (void) fprintf(stderr,
5342 gettext("\t<phost> <pdev> <pbmp> "
5343 #ifdef _RDC_CAMPUS
5344 "<shost> <sdev> <sbmp> {ip | <directfile>} "
5345 #else
5346 "<shost> <sdev> <sbmp> ip "
5347 #endif
5348 "\\\n\t\t{sync | async} [g <group>] [q <qdev>] "
5349 "[C <ctag>]\n"));
5350 else
5351 (void) fprintf(stderr,
5352 gettext("\t<phost> <pdev> <pbmp> "
5353 #ifdef _RDC_CAMPUS
5354 "<shost> <sdev> <sbmp> {ip | <directfile>} "
5355 #else
5356 "<shost> <sdev> <sbmp> ip "
5357 #endif
5358 "\\\n\t\t{sync | async} [g <group>] [q <qdev>]\n"));
5359 (void) fprintf(stderr,
5360 gettext("\t<shost>:<sdev>\t\t"
5361 "operate on set matching shost and sdev\n"));
5362 (void) fprintf(stderr,
5363 gettext("\t-f volset-file\t\t"
5364 "operate on all sets specified in config file\n"
5365 "\t\t\t\tnote: not valid for single set operations. See\n"
5366 "\t\t\t\t%s(1RDC).\n"), program);
5367 (void) fprintf(stderr,
5368 gettext("\t<no arg>\t\toperate on all configured sets\n"));
5369 }
5370
5371 int
5372 prompt_user(int flag, int options)
5373 {
5374 int c;
5375
5376 switch (flag) {
5377 case RDC_CMD_DISABLE:
5378 (void) printf(gettext("Disable Remote Mirror? (Y/N) [N]: "));
5379 break;
5380 case RDC_CMD_ENABLE:
5381 (void) printf(gettext("Enable Remote Mirror? (Y/N) [N]: "));
5382 break;
5383 case RDC_CMD_HEALTH:
5384 (void) printf(gettext("Report Remote Mirror link health? (Y/N)"
5385 "[N]: "));
5386 break;
5387 case RDC_CMD_COPY:
5388 if (options & RDC_OPT_FULL) {
5389 if (options & RDC_OPT_REVERSE)
5390 (void) printf(gettext("Overwrite primary with"
5391 " secondary? (Y/N) [N]: "));
5392 else
5393 (void) printf(gettext("Overwrite secondary with"
5394 " primary? (Y/N) [N]: "));
5395 } else {
5396 if (options & RDC_OPT_REVERSE)
5397 (void) printf(gettext("Refresh primary with"
5398 " secondary? (Y/N) [N]: "));
5399 else
5400 (void) printf(gettext("Refresh secondary with"
5401 " primary? (Y/N) [N]: "));
5402 }
5403 break;
5404 case RDC_CMD_RECONFIG:
5405 (void) printf(gettext(
5406 "Perform Remote Mirror reconfiguration? (Y/N) [N]: "));
5407 break;
5408 case RDC_CMD_RESET:
5409 (void) printf(gettext("Perform Remote Mirror reset? (Y/N) "
5410 "[N]: "));
5411 break;
5412 case RDC_CMD_TUNABLE:
5413 (void) printf(gettext("Change Remote Mirror tunable? (Y/N) "
5414 "[N]: "));
5415 break;
5416 case RDC_CMD_LOG:
5417 (void) printf(gettext(
5418 "Put Remote Mirror into logging mode? (Y/N) [N]: "));
5419 break;
5420 case RDC_CMD_WAIT:
5421 (void) printf(gettext(
5422 "Wait for Remote Mirror sync completion? (Y/N) [N]: "));
5423 break;
5424 default:
5425 (void) printf(gettext("Perform Remote Mirror operation? (Y/N) "
5426 "[N]: "));
5427 }
5428
5429 c = getchar();
5430 if ((c != 'y') && (c != 'Y')) {
5431 (void) printf("\n");
5432 return (-1);
5433 }
5434 return (0);
5435 }
5436
5437 static void
5438 load_rdc_vols(CFGFILE *cfg)
5439 {
5440 int set;
5441 char key[ CFG_MAX_KEY ];
5442 char buf[ CFG_MAX_BUF ];
5443 _sd_dual_pair_t pair;
5444 char *vol, *bmp;
5445 char *host1 = pair.fhost, *host2 = pair.thost;
5446 char *diskqueue = pair.diskqueue;
5447 volcount_t *volcount;
5448 char lghn[ MAX_RDC_HOST_SIZE ];
5449
5450 if (volhash) {
5451 return;
5452 }
5453
5454 cfg_rewind(cfg, CFG_SEC_CONF);
5455 volhash = nsc_create_hash();
5456 for (set = 1; /*CSTYLED*/; set++) {
5457 (void) snprintf(key, CFG_MAX_KEY, "sndr.set%d", set);
5458 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF)) {
5459 break;
5460 }
5461
5462 if (parse_cfg_buf(buf, &pair, lghn))
5463 continue;
5464 vol = pair.ffile;
5465 bmp = pair.fbitmap;
5466
5467 /* use lghn if possible */
5468 if (*lghn) {
5469 if (strcmp(host2, lghn) == 0) {
5470 vol = pair.tfile;
5471 bmp = pair.tbitmap;
5472 }
5473 } else if (!self_check(host1)) {
5474 /* next one had better be ours */
5475 vol = pair.tfile;
5476 bmp = pair.tbitmap;
5477
5478 if (!self_check(host2)) {
5479 rdc_warn(NULL,
5480 gettext("config error: neither %s nor %s"
5481 " is localhost"), host1, host2);
5482 continue;
5483 }
5484 }
5485
5486 /* primary vol may be used more than once */
5487 volcount = (volcount_t *)nsc_lookup(volhash, vol);
5488 if (volcount) {
5489 volcount->count++;
5490 } else {
5491 volcount = (volcount_t *)malloc(sizeof (volcount_t));
5492 volcount->count = 1;
5493 (void) nsc_insert_node(volhash, volcount, vol);
5494 }
5495
5496 /* bitmap ought to be only used once */
5497 volcount = (volcount_t *)nsc_lookup(volhash, bmp);
5498 if (volcount) {
5499 /* argh */
5500 volcount->count++;
5501 } else {
5502 volcount = (volcount_t *)malloc(sizeof (volcount_t));
5503 volcount->count = 1;
5504 (void) nsc_insert_node(volhash, volcount, bmp);
5505 }
5506
5507 if (strcmp(diskqueue, place_holder) == 0)
5508 continue;
5509 /* diskqueue vol may be used more than once */
5510 volcount = (volcount_t *)nsc_lookup(volhash, diskqueue);
5511 if (volcount) {
5512 volcount->count++;
5513 } else {
5514 volcount = (volcount_t *)malloc(sizeof (volcount_t));
5515 volcount->count = 1;
5516 (void) nsc_insert_node(volhash, volcount, diskqueue);
5517 }
5518 }
5519 }
5520
5521 static void
5522 unload_rdc_vols()
5523 {
5524 nsc_remove_all(volhash, free);
5525 volhash = 0;
5526 }
5527
5528 static int
5529 perform_autosv()
5530 {
5531 if (!clustered) {
5532 return (1);
5533 } else {
5534 return (cfg_issuncluster());
5535 }
5536 }
5537
5538 /*
5539 * Check the user supplied fields against those in the dscfg for
5540 * this set.
5541 * Never returns on an error.
5542 */
5543 static void
5544 checkgfields(CFGFILE *cfg, int setnumber, char *fromhost, char *fromfile,
5545 char *frombitmap, char *tobitmap, char *type, char *mode, char *group,
5546 char *ctag, char *diskq)
5547 {
5548 if (fromhost[0])
5549 checkgfield(cfg, setnumber, "phost",
5550 gettext("primary host"), fromhost);
5551 if (fromfile[0])
5552 checkgfield(cfg, setnumber, "primary",
5553 gettext("primary volume"), fromfile);
5554 if (frombitmap[0])
5555 checkgfield(cfg, setnumber, "pbitmap",
5556 gettext("primary bitmap"), frombitmap);
5557 if (tobitmap[0])
5558 checkgfield(cfg, setnumber, "sbitmap",
5559 gettext("secondary bitmap"), tobitmap);
5560 if (type[0])
5561 checkgfield(cfg, setnumber, "type",
5562 gettext("type of connection"), type);
5563 if (mode[0])
5564 checkgfield(cfg, setnumber, "mode",
5565 gettext("mode of connection"), mode);
5566 if (group[0])
5567 checkgfield(cfg, setnumber, "group",
5568 gettext("group"), group);
5569 if (ctag[0])
5570 checkgfield(cfg, setnumber, "cnode",
5571 gettext("cluster tag"), ctag);
5572 if (diskq[0])
5573 checkgfield(cfg, setnumber, "diskq",
5574 gettext("disk queue volume"), diskq);
5575 }
5576
5577 /*
5578 * Check the 'fname' field in the dscfg file for set number 'setnumber'
5579 * If it does not match the user's data, 'data', then print the error
5580 * message using the friendly field name 'ufield'.
5581 * Never returns on an error.
5582 */
5583 static void
5584 checkgfield(CFGFILE *cfg, int setnumber, char *fname, char *ufield, char *data)
5585 {
5586 char buf[CFG_MAX_BUF];
5587 char key[CFG_MAX_KEY];
5588
5589 (void) snprintf(key, sizeof (key), "sndr.set%d.%s", setnumber, fname);
5590 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
5591 rdc_err(NULL, gettext("unable to fetch data for key %s"),
5592 key);
5593 }
5594 if (strcmp(buf, data) != 0) {
5595 rdc_err(NULL,
5596 gettext("the value specified for the %s field is not\nthe "
5597 "same as that contained within the configuration storage "
5598 "file for this set.\nYou specified \"%s\" "
5599 "expected \"%s\"."),
5600 ufield, data, buf);
5601 }
5602 }
5603
5604 /*
5605 * load and send the contents of the bitmap file to the kernel.
5606 */
5607 static int
5608 rdc_bitmapset(char *tohost, char *tofile, char *bitmap, int op,
5609 nsc_off_t offset)
5610 {
5611 rdc_bitmap_op_t bmop;
5612 int fd;
5613 void *buffer;
5614 int buffersz;
5615 struct stat s;
5616 int n;
5617 int ret;
5618 /*
5619 * open bitmap file for reading.
5620 */
5621 if ((fd = open(bitmap, O_RDONLY)) < 0) {
5622 rdc_warn(NULL, gettext("Unable to open bitmap file %s"),
5623 bitmap);
5624 return (1);
5625 }
5626 (void) fstat(fd, &s);
5627
5628 if (S_ISREG(s.st_mode) == 0) {
5629 rdc_warn(NULL, gettext("Bitmap %s is not a regular file"),
5630 bitmap);
5631 (void) close(fd);
5632 return (1);
5633 }
5634
5635 if (op == 0) {
5636 op = RDC_BITMAPOR;
5637 }
5638 /*
5639 * use the file size to allocate buffer. This
5640 * size should be a multiple of FBA, but don't check
5641 * it here.
5642 */
5643 buffersz = s.st_size;
5644 buffer = malloc(buffersz);
5645 if (buffer == NULL) {
5646 rdc_warn(NULL, gettext("Unable to allocate %d bytes "
5647 "for bitmap file %s"), buffersz, bitmap);
5648 (void) close(fd);
5649 return (1);
5650 }
5651 n = read(fd, buffer, buffersz);
5652 (void) close(fd);
5653 if (n != buffersz) {
5654 rdc_warn(NULL, gettext("Unable to read the bitmap file, "
5655 "read returned %d instead of %d"),
5656 n, buffersz);
5657 free(buffer);
5658 return (1);
5659 }
5660 bmop.offset = offset;
5661 bmop.op = op;
5662 (void) strncpy(bmop.sechost, tohost, MAX_RDC_HOST_SIZE);
5663 (void) strncpy(bmop.secfile, tofile, NSC_MAXPATH);
5664 bmop.len = buffersz;
5665 bmop.addr = (unsigned long)buffer;
5666 ret = rdc_ioctl_simple(RDC_BITMAPOP, &bmop);
5667 free(buffer);
5668 if (ret < 0) {
5669 rdc_warn(NULL, gettext("Setting bitmap ioctl failed for set "
5670 "%s:%s"), tohost, tofile);
5671
5672 switch (errno) {
5673 case EIO:
5674 rdc_warn(NULL, gettext("One of the sets is not "
5675 "enabled"));
5676 break;
5677 case ENXIO:
5678 rdc_warn(NULL, gettext("One of the sets is not "
5679 "logging"));
5680 break;
5681 default:
5682 break;
5683 }
5684 } else {
5685 ret = 0;
5686 }
5687 if (ret)
5688 ret = 1;
5689 return (ret);
5690 }
5691
5692 /*
5693 * verify_groupname: Check the group name for the following rules:
5694 * 1. The name does not start with a '-'
5695 * 2. The name does not contain any space characters as defined by
5696 * isspace(3C).
5697 *
5698 * If either of these rules are broken, error immediately.
5699 */
5700 static void
5701 verify_groupname(char *grp)
5702 {
5703 int i;
5704
5705 if (grp[0] == '-') {
5706 rdc_err(NULL, gettext("group name cannot start with a '-'"));
5707 }
5708
5709 for (i = 0; grp[i] != '\0'; i++) {
5710 if (isspace(grp[i])) {
5711 rdc_err(NULL, gettext("group name cannot contain a "
5712 "space"));
5713 }
5714 }
5715 }