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/wait.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <limits.h>
32 #include <fcntl.h>
33 #include <strings.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <pthread.h>
37 #include <thread.h>
38
39 #include <locale.h>
40 #include <langinfo.h>
41 #include <libintl.h>
42 #include <stdarg.h>
43
44 #include <sys/nsctl/rdc_io.h>
45 #include <sys/nsctl/rdc_ioctl.h>
46 #include <sys/nsctl/rdc_prot.h>
47
48 #include <sys/nsctl/cfg.h>
49
50 #include <sys/unistat/spcs_s.h>
51 #include <sys/unistat/spcs_s_u.h>
52 #include <sys/unistat/spcs_errors.h>
53
54 #include <sys/nsctl/librdc.h>
55
56 #include "rdcadm.h"
57
58
59 #define RDCADM "/usr/sbin/sndradm"
60 #define IIADM "/usr/sbin/iiadm"
61
62 #define UPDATE "update"
63 #define NOUPDATE "noupdate"
64
65 #define RESYNC_SLEEP (3 * 60) /* Three minutes */
66 #define MAIN_SLEEP (5 * 60) /* Five minutes */
67 #define CFG_WAIT_SLEEP (5) /* 5 sec */
68
69 #define MAXHOSTS 1024
70 mutex_t cfglock = DEFAULTMUTEX;
71 #define LOCKCFG() (void) mutex_lock(&cfglock);
72 #define UNLOCKCFG() (void) mutex_unlock(&cfglock);
73
74 typedef struct host_list_s {
75 char *hosts[MAXHOSTS];
76 int numhosts;
77 int configured[MAXHOSTS];
78 mutex_t hosts_mutex;
79 } host_list_t;
80
81 host_list_t *host_list;
82
83 extern char *basename(char *);
84 int rdc_maxsets;
85 char *program;
86
87 static int clustered = 0;
88
89 int isnewhost(char *host);
90 void *wait_sync_event();
91 void *wait_link_down(void *host);
92 void rdc_sync(char *tohost);
93 void remove_from_hostlist(char *host);
94 void sync_start(char *master);
95 void sync_complete(char *master);
96 void cleanup_hostlist();
97 void group_start(char *group);
98 void group_complete(char *group);
99
100
101 void
init_host_list(void)102 init_host_list(void)
103 {
104 host_list = calloc(1, sizeof (host_list_t));
105 if (host_list == NULL) {
106 spcs_log("sndr", NULL,
107 gettext("host list not initialized, cannot run"));
108 rdc_err(NULL, gettext("host list not initialized, cannot run"));
109 }
110 (void) mutex_init(&host_list->hosts_mutex, USYNC_THREAD, NULL);
111 }
112
113 /* ARGSUSED */
114 #ifdef lint
115 void
sndrsyncd_lintmain(argc,argv)116 sndrsyncd_lintmain(argc, argv)
117 #else
118 int
119 main(argc, argv)
120 #endif
121 int argc;
122 char **argv;
123 {
124 rdc_status_t *rdc_info;
125 int size;
126 int i;
127 pid_t pid;
128 spcs_s_info_t ustatus;
129 int rc, trc;
130 int first = 0;
131 char *required;
132
133 (void) setlocale(LC_ALL, "");
134 (void) textdomain("rdc");
135
136 ustatus = spcs_s_ucreate();
137
138 program = basename(argv[0]);
139
140 init_host_list();
141
142 rc = rdc_check_release(&required);
143 if (rc < 0) {
144 rdc_err(NULL,
145 gettext("unable to determine the current "
146 "Solaris release: %s\n"), strerror(errno));
147 /* NOTREACHED */
148 } else if (rc == FALSE) {
149 rdc_err(NULL,
150 gettext("incorrect Solaris release (requires %s)\n"),
151 required);
152 /* NOTREACHED */
153 }
154
155 clustered = cfg_iscluster();
156 if (clustered < 0) {
157 rdc_err(NULL, gettext("unable to ascertain environment"));
158 }
159
160 rdc_maxsets = rdc_get_maxsets();
161 if (rdc_maxsets == -1) {
162 spcs_log("sndr", NULL,
163 gettext("%s: unable to get maxsets value from kernel"),
164 program);
165 rdc_err(NULL,
166 gettext("unable to get maxsets value from kernel"));
167 }
168 size = sizeof (rdc_status_t) + (sizeof (rdc_set_t) * (rdc_maxsets - 1));
169 rdc_info = malloc(size);
170 if (rdc_info == NULL) {
171 spcs_log("sndr", NULL,
172 gettext("%s: unable to allocate %ld bytes"),
173 program, size);
174 rdc_err(NULL,
175 gettext("unable to allocate %ld bytes"), size);
176 }
177 bzero(rdc_info, size);
178
179 rdc_info->nset = rdc_maxsets;
180
181 /*
182 * Fork off a child that becomes the daemon.
183 */
184 if ((pid = fork()) > 0)
185 exit(0);
186 else if (pid < 0) {
187 spcs_log("sndr", NULL,
188 gettext("%s: cannot fork: %s"),
189 program, strerror(errno));
190 rdc_err(NULL, gettext("cannot fork: %s\n"),
191 strerror(errno));
192 }
193
194 /*
195 * In child - become daemon.
196 */
197
198 for (i = 0; i < 3; i++)
199 (void) close(i);
200
201 (void) open("/dev/console", O_WRONLY|O_APPEND);
202 (void) dup(0);
203 (void) dup(0);
204 (void) close(0);
205
206 (void) setpgrp();
207
208 (void) setlocale(LC_ALL, "");
209 (void) textdomain("rdc");
210
211 /* launch a thread to wait for sync start and sync stop events */
212
213 if ((trc = thr_create(NULL, 0, wait_sync_event, NULL,
214 THR_BOUND|THR_DETACHED, NULL)) != 0) {
215 spcs_log("sndr", NULL,
216 gettext("%s: unable to create thread wait_sync_event"),
217 program);
218 rdc_warn(NULL,
219 gettext("%s unable to create thread wait_sync_event"),
220 program);
221 } else {
222 #ifdef DEBUG
223 spcs_log("sndr", NULL,
224 gettext("%s: thread wait_sync_event started"), program);
225 #endif
226 ;
227 }
228
229 for (;;) {
230 if (!first) {
231 first++;
232 (void) sleep(15);
233 } else
234 (void) sleep(MAIN_SLEEP);
235
236 bzero(rdc_info, size);
237 rdc_info->nset = rdc_maxsets;
238 if (RDC_IOCTL(RDC_STATUS, rdc_info, 0, 0, 0, 0, ustatus)
239 != SPCS_S_OK) {
240 spcs_log("sndr", &ustatus,
241 gettext("%s: status ioctl"),
242 program);
243 rdc_warn(&ustatus, gettext("status ioctl"));
244 continue;
245 }
246
247 cleanup_hostlist(rdc_info); /* remove non-existent hosts */
248
249 /*
250 * Check all enabled sets to see if a new remote host has
251 * appeared.
252 */
253 for (i = 0; i < rdc_maxsets; i++) {
254 if (!(rdc_info->rdc_set[i].flags & RDC_ENABLED))
255 continue;
256 /* spawn a new thread for each new host found */
257 if (isnewhost(rdc_info->rdc_set[i].secondary.intf)) {
258 /*
259 * right now, we could be here before
260 * the database did the write for this set
261 * I could check the lock on the database
262 * but I am just going to give up some time here
263 * instead. Why do the allocations etc, etc
264 * if the set is enabled in the kernel and not
265 * in the config, we know that this set has the
266 * lock. Why bother adding more contention to
267 * the lock.
268 * this is a daemon, afterall. its got time
269 */
270 (void) sleep(CFG_WAIT_SLEEP);
271
272 spcs_log("sndr", NULL,
273 gettext("%s: new host found (%s) starting "
274 "its autosync thread"), program,
275 rdc_info->rdc_set[i].secondary.intf);
276
277 trc = thr_create(NULL, 0, wait_link_down,
278 (void *) rdc_info->rdc_set[i].\
279 secondary.intf, THR_BOUND|THR_DETACHED, NULL);
280
281 if (trc != 0) {
282 spcs_log("sndr", NULL,
283 gettext(
284 "%s create new autosync "
285 "thread failed"), program);
286 rdc_warn(NULL, gettext(
287 "%s create new autosync "
288 "thread failed"), program);
289 }
290 }
291 }
292 }
293 /* NOTREACHED */
294 }
295
296
297 /*
298 * The kernel wakes up this function every time it detects the link to the
299 * specified host has dropped.
300 */
301 void *
wait_link_down(void * thehost)302 wait_link_down(void *thehost)
303 {
304 char *host = (char *)thehost;
305 char tmphost[MAX_RDC_HOST_SIZE] = { '\0' };
306 spcs_s_info_t ustatus;
307
308 if (host)
309 (void) strncpy(tmphost, host, MAX_RDC_HOST_SIZE);
310
311 ustatus = spcs_s_ucreate();
312
313 /* Never give up */
314 for (;;) {
315 #ifdef DEBUG
316 spcs_log("sndr", NULL,
317 gettext("%s: awaiting link down ioctl for %s"),
318 program, host[0] == '\0' ? tmphost : host);
319 #endif
320 if (RDC_IOCTL(RDC_LINK_DOWN, host, 0, 0, 0, 0, ustatus)
321 != SPCS_S_OK) {
322 spcs_log("sndr", &ustatus,
323 gettext("%s: link down ioctl"),
324 program);
325 rdc_warn(&ustatus, gettext("link down ioctl"));
326 continue;
327 }
328 #ifdef DEBUG
329
330 spcs_log("sndr", NULL,
331 gettext("%s: received link down ioctl for %s"),
332 program, host[0] == '\0' ? tmphost : host);
333 #endif
334 rdc_sync(host[0] == '\0' ? tmphost : host);
335 }
336 /* LINTED */
337 }
338
339
340 /*
341 * Called when the link to the specified host has dropped.
342 * For all Remote Mirror sets using the link that have autosync on,
343 * issue rdcadm -u commands until they complete successfully.
344 */
345 void
rdc_sync(char * tohost)346 rdc_sync(char *tohost)
347 {
348 rdc_set_t *rdc_set = NULL;
349 int *sync_done = NULL;
350 int sets = 0;
351 int syncs_done = 0;
352 char cmd[256];
353 rdc_config_t parms = { 0 };
354 spcs_s_info_t ustatus;
355 int i;
356 int setnumber;
357 int numfound = 0;
358 char buf[CFG_MAX_BUF];
359 char key[CFG_MAX_KEY];
360 CFGFILE *cfg = NULL;
361 int size;
362 int first = 0;
363 int death = 0;
364 int cfglocked = 0;
365
366 ustatus = spcs_s_ucreate();
367
368 size = sizeof (rdc_set_t) * rdc_maxsets;
369 rdc_set = malloc(size);
370 if (rdc_set == NULL) {
371 spcs_log("sndr", NULL,
372 gettext("%s: unable to allocate %ld bytes"),
373 program, size);
374 rdc_warn(NULL,
375 gettext("unable to allocate %ld bytes"), size);
376 goto done;
377 }
378 bzero(rdc_set, size);
379 size = sizeof (int) * rdc_maxsets;
380 sync_done = malloc(size);
381 if (sync_done == NULL) {
382 spcs_log("sndr", NULL,
383 gettext("%s: unable to allocate %ld bytes"),
384 program, size);
385 rdc_warn(NULL,
386 gettext("unable to allocate %ld bytes"), size);
387 goto done;
388 }
389 bzero(sync_done, size);
390
391 /*
392 * Get all sndr entries with shost matching tohost, and save the
393 * details in an array.
394 */
395 for (i = 0; i < rdc_maxsets; i++) {
396 setnumber = i + 1;
397 bzero(buf, sizeof (buf));
398 bzero(key, sizeof (key));
399
400 (void) snprintf(key, sizeof (key), "sndr.set%d.shost",
401 setnumber);
402
403 if (!cfglocked) {
404 LOCKCFG();
405 if ((cfg = cfg_open(NULL)) == NULL) {
406 spcs_log("sndr", NULL,
407 gettext("%s: error opening config"),
408 program);
409
410 rdc_warn(NULL,
411 gettext("error opening config"));
412 UNLOCKCFG();
413 goto done;
414 }
415
416 if (!cfg_lock(cfg, CFG_RDLOCK)) {
417 spcs_log("sndr", NULL,
418 gettext("%s: error locking config"),
419 program);
420 rdc_warn(NULL, gettext("error locking config"));
421 goto done;
422 }
423 }
424
425 cfglocked = 1;
426
427 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
428 if (numfound == 0) /* no matching hosts */
429 death = 1; /* thread will exit */
430 break;
431 }
432 if (strcmp(buf, tohost) != 0)
433 continue;
434
435 numfound++;
436 (void) strncpy(rdc_set[sets].secondary.intf, buf,
437 MAX_RDC_HOST_SIZE);
438
439 /* Got a matching entry */
440
441 (void) snprintf(key, sizeof (key), "sndr.set%d.phost",
442 setnumber);
443 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
444 break;
445 (void) strncpy(rdc_set[sets].primary.intf, buf,
446 MAX_RDC_HOST_SIZE);
447
448 (void) snprintf(key, sizeof (key), "sndr.set%d.primary",
449 setnumber);
450 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
451 break;
452 (void) strncpy(rdc_set[sets].primary.file, buf, NSC_MAXPATH);
453
454 (void) snprintf(key, sizeof (key), "sndr.set%d.secondary",
455 setnumber);
456 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
457 break;
458 (void) strncpy(rdc_set[sets].secondary.file, buf, NSC_MAXPATH);
459
460 parms.command = RDC_CMD_STATUS;
461 bcopy((void *)(&rdc_set[sets]), (void *)(&parms.rdc_set[0]),
462 sizeof (rdc_set_t));
463
464 /*
465 * release cfg before diving into the kernel
466 * this prevents a possible deadlock when doing
467 * a reverse sync whick will wake up the sync_event
468 * thread which will try and iiadm -c and hang
469 * because we still have the cfg_lock. the timed
470 * wait cv in the kernel will fail the sync and things
471 * will undeadlock.
472 */
473
474 cfg_close(cfg);
475 cfg = NULL;
476 cfglocked = 0;
477 UNLOCKCFG();
478
479 if (RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus) < 0) {
480 continue;
481 }
482 if ((parms.rdc_set[0].autosync == 0) ||
483 (!(parms.rdc_set[0].flags & RDC_LOGGING))) {
484 continue;
485 }
486
487 /* Found a suitable set with autosync on, in logging mode */
488 sets++;
489 }
490
491 if (cfg) {
492 cfg_close(cfg);
493 cfg = NULL;
494 UNLOCKCFG();
495 }
496
497 if (sets == 0) {
498 #ifdef DEBUG
499 spcs_log("sndr", NULL,
500 gettext("%s: no sets requiring autosync found for %s"),
501 program, tohost);
502 #endif
503 if (death) {
504 spcs_log("sndr", NULL,
505 gettext("%s: autosync thread stopping for %s "
506 "(host deconfigured)"), program, tohost);
507 }
508 goto done;
509 }
510
511 /* Keep issuing rdcadm -u commands until they have all completed */
512 for (;;) {
513 if (!first)
514 first++;
515 else
516 (void) sleep(RESYNC_SLEEP);
517
518 /* Issue rdcadm -u commands for all remaining sets */
519 for (i = 0; i < sets; i++) {
520 if (sync_done[i])
521 continue;
522
523 /*
524 * Need to check if autosync was turned off for a set
525 * while we were sleeping. We could have the case where
526 * an update sync failed and autosync was disabled
527 * while we were sleeping and didn't detect the disable.
528 * See BugID 4814213.
529 */
530 parms.command = RDC_CMD_STATUS;
531 bcopy((void *)(&rdc_set[i]),
532 (void *)(&parms.rdc_set[0]), sizeof (rdc_set_t));
533 if (RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0,
534 ustatus) < 0) {
535 spcs_log("sndr", &ustatus, gettext("%s: "
536 "status not available for %s:%s, stopping "
537 "this autosync attempt"), program, tohost,
538 rdc_set[i].secondary.file);
539 sync_done[i] = 1;
540 syncs_done++;
541 continue;
542 }
543 if (!(parms.rdc_set[0].autosync)) {
544 #ifdef DEBUG
545 spcs_log("sndr", NULL, gettext("%s: autosync disabled during sleep, "
546 "stopping attempt for set %s:%s"), program, tohost,
547 rdc_set[i].secondary.file);
548 #endif
549 sync_done[i] = 1;
550 syncs_done++;
551 continue;
552 }
553
554 (void) sprintf(cmd, "%s -un %s:%s", RDCADM, tohost,
555 rdc_set[i].secondary.file);
556 spcs_log("sndr", NULL,
557 gettext("%s: issuing update sync for %s:%s"),
558 program, tohost, rdc_set[i].secondary.file);
559 (void) system(cmd);
560 }
561
562 /* Issue rdcadm -w commands to wait for updates to finish */
563 for (i = 0; i < sets; i++) {
564 if (sync_done[i])
565 continue;
566
567 (void) sprintf(cmd, "%s -wn %s:%s", RDCADM, tohost,
568 rdc_set[i].secondary.file);
569 spcs_log("sndr", NULL,
570 gettext("%s: issuing wait for %s:%s"),
571 program, tohost, rdc_set[i].secondary.file);
572
573 (void) system(cmd);
574
575 parms.command = RDC_CMD_STATUS;
576 bcopy((void *)(&rdc_set[i]),
577 (void *)(&parms.rdc_set[0]), sizeof (rdc_set_t));
578
579 if (RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0,
580 ustatus) < 0) {
581 spcs_log("sndr", &ustatus,
582 gettext("%s: status not available for "
583 "%s:%s, stopping this autosync attempt"),
584 program, tohost, rdc_set[i].secondary.file);
585 sync_done[i] = 1;
586 syncs_done++;
587 continue;
588 }
589 /* Check if completed OK, failed or autosync off */
590 if (!(parms.rdc_set[0].autosync) ||
591 !(parms.rdc_set[0].flags & RDC_LOGGING) &&
592 !(parms.rdc_set[0].flags & RDC_SYNCING)) {
593 sync_done[i] = 1;
594 syncs_done++;
595 }
596 }
597
598 if (syncs_done == sets)
599 break; /* All completed OK */
600 }
601
602 done:
603 if (cfg) {
604 cfg_close(cfg);
605 UNLOCKCFG();
606 }
607 spcs_s_ufree(&ustatus);
608 if (sync_done)
609 free(sync_done);
610 if (rdc_set)
611 free(rdc_set);
612 if (death) { /* bye bye */
613 /*
614 * if perhaps we lost some race, lets remove this entry from
615 * the list. Then, if something did go wrong, and we did kill
616 * a valid thread, it will be detected on the next go around
617 * of the thread who is looking for new hosts to spawn threads
618 */
619
620 remove_from_hostlist(tohost);
621 thr_exit(0);
622 }
623
624 (void) sleep(RESYNC_SLEEP);
625 }
626
627 /*
628 * Wait for notification by the kernel of a sync start or a sync completed OK
629 */
630 void *
wait_sync_event()631 wait_sync_event()
632 {
633 spcs_s_info_t ustatus;
634 char master[NSC_MAXPATH];
635 char group[NSC_MAXPATH];
636 int state;
637
638 ustatus = spcs_s_ucreate();
639
640 master[0] = '\0';
641 group[0] = '\0';
642
643 /* Never give up */
644 for (;;) {
645 /* Kernel tells us which volume and group the event is for */
646 state = RDC_IOCTL(RDC_SYNC_EVENT, master, group, 0, 0, 0,
647 ustatus);
648 if (state < SPCS_S_OK) {
649 if (errno != EAGAIN) {
650 spcs_log("sndr", &ustatus,
651 gettext("%s: update ioctl"),
652 program);
653 rdc_warn(&ustatus, gettext("update ioctl"));
654 continue;
655 }
656 master[0] = '\0';
657 continue;
658 }
659
660 /*
661 * If target is mounted at the start of a sync or reverse sync,
662 * return a negative ack.
663 */
664 if ((state == RDC_SYNC_START || state == RDC_RSYNC_START) &&
665 mounted(master)) {
666 spcs_log("sndr", NULL,
667 gettext("%s: %s has a file system mounted"),
668 program, master);
669 rdc_warn(NULL,
670 gettext("%s has a file system mounted"),
671 master);
672 master[0] = '\0'; /* negative ack */
673 continue;
674 }
675
676 switch (state) {
677 case RDC_SYNC_START:
678 if (group[0])
679 group_start(group);
680 else
681 sync_start(master);
682 break;
683
684 case RDC_SYNC_DONE:
685 if (group[0])
686 group_complete(group);
687 else
688 sync_complete(master);
689 break;
690
691 default:
692 break;
693 }
694 }
695 /* LINTED */
696 }
697
698
699 /*
700 * A sync has completed OK to a volume not belonging to a group.
701 * Set the state of the ndr_ii config entry to "update".
702 */
703 void
sync_complete(char * master)704 sync_complete(char *master)
705 {
706 CFGFILE *cfg = NULL;
707 char buf[CFG_MAX_BUF];
708 char key[CFG_MAX_KEY];
709 int i;
710 int setnumber;
711 int sev;
712
713 LOCKCFG();
714 if ((cfg = cfg_open(NULL)) == NULL) {
715 spcs_log("sndr", NULL,
716 gettext("%s: error opening config"),
717 program);
718 rdc_warn(NULL, gettext("error opening config"));
719 UNLOCKCFG();
720 return;
721 }
722 if (!cfg_lock(cfg, CFG_WRLOCK)) {
723 spcs_log("sndr", NULL,
724 gettext("%s: error locking config"),
725 program);
726 rdc_warn(NULL, gettext("error locking config"));
727 cfg_close(cfg);
728 UNLOCKCFG();
729 return;
730 }
731
732 /* get ndr_ii entries until a match is found */
733 for (i = 0; ; i++) {
734 setnumber = i + 1;
735
736 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.secondary",
737 setnumber);
738 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
739 break;
740 if (strcmp(buf, master) != 0)
741 continue;
742
743 /* Found the matching entry */
744
745 /*
746 * Set state to "update" so that starting another sync will
747 * cause a new Point-in-Time Copy snapshot to be taken.
748 */
749 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.state",
750 setnumber);
751 if ((cfg_put_cstring(cfg, key, UPDATE, strlen(UPDATE)) < 0) ||
752 (cfg_commit(cfg) < 0)) {
753 spcs_log("sndr", NULL,
754 gettext("%s: unable to update \"%s\" "
755 "in configuration storage: %s"),
756 program, buf, cfg_error(&sev));
757 rdc_warn(NULL,
758 gettext("unable to update \"%s\" "
759 "in configuration storage: %s"),
760 buf, cfg_error(&sev));
761 }
762 break;
763 }
764
765 cfg_close(cfg);
766 UNLOCKCFG();
767 }
768
769
770 /*
771 * Starting a sync to the specified master volume.
772 * Check the ndr_ii config entries to see if a Point-in-Time Copy
773 * snapshot should be taken.
774 */
775 void
sync_start(char * master)776 sync_start(char *master)
777 {
778 char cmd[256];
779 char buf[CFG_MAX_BUF];
780 char key[CFG_MAX_KEY];
781 CFGFILE *cfg = NULL;
782 int i;
783 int setnumber;
784 int found;
785 int sev;
786 char shadow[NSC_MAXPATH];
787 char bitmap[NSC_MAXPATH];
788 char *ctag = NULL;
789
790 LOCKCFG();
791 if ((cfg = cfg_open(NULL)) == NULL) {
792 spcs_log("sndr", NULL,
793 gettext("%s: error opening config"),
794 program);
795 rdc_warn(NULL,
796 gettext("error opening config"));
797 UNLOCKCFG();
798 return;
799 }
800 if (!cfg_lock(cfg, CFG_RDLOCK)) {
801 spcs_log("sndr", NULL,
802 gettext("%s: error locking config"),
803 program);
804 rdc_warn(NULL, gettext("error locking config"));
805 cfg_close(cfg);
806 UNLOCKCFG();
807 return;
808 }
809
810 found = 0;
811 /* get ndr_ii entries until a match is found */
812 for (i = 0; ; i++) {
813 setnumber = i + 1;
814
815 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.secondary",
816 setnumber);
817 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
818 break;
819 if (strcmp(buf, master) != 0)
820 continue;
821
822 /* Got a matching entry */
823
824 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.shadow",
825 setnumber);
826 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
827 break;
828 (void) strncpy(shadow, buf, NSC_MAXPATH);
829
830 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.bitmap",
831 setnumber);
832 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
833 break;
834 (void) strncpy(bitmap, buf, NSC_MAXPATH);
835
836 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.state",
837 setnumber);
838 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
839 break;
840
841 /*
842 * If an PIT snapshot has already been taken, and syncing did
843 * not complete, the state will be "noupdate", to indicate we
844 * should not take another one at this point.
845 */
846 if (strcmp(buf, NOUPDATE) != 0)
847 found = 1;
848
849 break;
850 }
851
852 if (!found) {
853 cfg_close(cfg);
854 UNLOCKCFG();
855 return;
856 }
857
858 found = 0;
859 /* get ii entries until a match is found */
860 for (i = 0; ; i++) {
861 setnumber = i + 1;
862
863 (void) snprintf(key, sizeof (key), "ii.set%d.shadow",
864 setnumber);
865 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
866 break;
867 if (strcmp(buf, shadow) != 0)
868 continue;
869
870 /* Matching shadow found, so ii already enabled */
871 found = 1;
872 break;
873 }
874
875 if (found) {
876 /* Already PIT enabled, so just take a snapshot */
877
878 /* Get cluster tag of matching entry */
879 (void) snprintf(key, sizeof (key), "ii.set%d.cnode", setnumber);
880 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) >= 0)
881 if ((strlen(buf) == 0) || (buf[0] == '-'))
882 ctag = "-C local";
883 else
884 ctag = "";
885 (void) sprintf(cmd, "%s %s -u s %s", IIADM, ctag, shadow);
886 } else {
887 /*
888 * If clustered, need to enable PIT Copy sets in the same
889 * cluster as the Remote Mirror set
890 */
891
892 if (clustered) {
893 /* Find a RM set with master as the local volume */
894
895 for (i = 0; i < rdc_maxsets; i++) {
896 setnumber = i + 1;
897 (void) snprintf(key, sizeof (key),
898 "sndr.set%d.phost", setnumber);
899 if (cfg_get_cstring(cfg, key, buf,
900 CFG_MAX_BUF) < 0)
901 break;
902
903 if (self_check(buf))
904 (void) snprintf(key, sizeof (key),
905 "sndr.set%d.primary", setnumber);
906 else
907 (void) snprintf(key, sizeof (key),
908 "sndr.set%d.secondary", setnumber);
909 if (cfg_get_cstring(cfg, key, buf,
910 CFG_MAX_BUF) < 0)
911 break;
912
913 if (strcmp(buf, master) != 0)
914 continue;
915
916 /* Get cluster tag of matching entry */
917
918 (void) snprintf(key, sizeof (key),
919 "sndr.set%d.cnode", setnumber);
920 if (cfg_get_cstring(cfg, key, buf,
921 CFG_MAX_BUF) < 0)
922 break;
923 if ((strlen(buf) == 0) || (buf[0] == '-'))
924 ctag = strdup("local");
925 else
926 ctag = strdup(buf);
927 break;
928 }
929 }
930
931 /* Not already enabled, so enable a dependent */
932 if (ctag) {
933 (void) sprintf(cmd, "%s -C %s -e dep %s %s %s", IIADM,
934 ctag, master, shadow, bitmap);
935 free(ctag);
936 } else
937 (void) sprintf(cmd, "%s -e dep %s %s %s", IIADM, master,
938 shadow, bitmap);
939 }
940
941 cfg_close(cfg);
942
943 if (system(cmd) != 0) {
944 spcs_log("sndr", NULL,
945 gettext("Point-in-Time Copy snapshot failed for %s %s %s."
946 " Please check validity of ndr_ii entry"),
947 master, shadow, bitmap);
948 cfg_close(cfg);
949 UNLOCKCFG();
950 return;
951 }
952
953 /*
954 * PIT Copy enable or update was fine, so update the ndr_ii entry
955 * to "noupdate", to prevent invalid point in time copies.
956 */
957
958 if ((cfg = cfg_open(NULL)) == NULL) {
959 spcs_log("sndr", NULL,
960 gettext("%s: error opening config"),
961 program);
962 rdc_warn(NULL,
963 gettext("error opening config"));
964 UNLOCKCFG();
965 return;
966 }
967 if (!cfg_lock(cfg, CFG_WRLOCK)) {
968 spcs_log("sndr", NULL,
969 gettext("%s: error locking config"),
970 program);
971 rdc_warn(NULL, gettext("error locking config"));
972 cfg_close(cfg);
973 UNLOCKCFG();
974 return;
975 }
976
977 /* get ndr_ii entries until a match is found */
978 for (i = 0; ; i++) {
979 setnumber = i + 1;
980
981 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.shadow",
982 setnumber);
983 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
984 break;
985 if (strcmp(buf, shadow) != 0)
986 continue;
987
988 /* Found the matching entry */
989
990 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.state",
991 setnumber);
992 if ((cfg_put_cstring(cfg, key, NOUPDATE,
993 strlen(NOUPDATE)) < 0) || (cfg_commit(cfg) < 0)) {
994 spcs_log("sndr", NULL,
995 gettext("%s: unable to update \"%s\" "
996 "in configuration storage: %s"),
997 program, buf, cfg_error(&sev));
998 rdc_warn(NULL,
999 gettext("unable to update \"%s\" "
1000 "in configuration storage: %s"),
1001 buf, cfg_error(&sev));
1002 }
1003 break;
1004 }
1005 cfg_close(cfg);
1006 UNLOCKCFG();
1007 }
1008
1009 void
cleanup_hostlist(rdc_status_t * rdc_info)1010 cleanup_hostlist(rdc_status_t *rdc_info)
1011 {
1012 int i, j, k;
1013 char *host, *exhost;
1014
1015
1016 (void) mutex_lock(&host_list->hosts_mutex);
1017 for (i = 0; i < host_list->numhosts; i++) {
1018 int found = 0;
1019 for (j = 0; (j < rdc_maxsets) && !found; j++) {
1020 if (!rdc_info->rdc_set[j].flags & RDC_ENABLED)
1021 continue;
1022 if ((!host_list->configured[i]) ||
1023 (host_list->hosts[i] == '\0')) {
1024 (void) mutex_unlock(&host_list->hosts_mutex);
1025 return;
1026 }
1027
1028 host = rdc_info->rdc_set[j].secondary.intf;
1029 if (strcmp(host_list->hosts[i], host) == 0)
1030 found++;
1031 }
1032 if (j == rdc_maxsets) {
1033 /*
1034 * this set is not in the kernel, so remove from list
1035 */
1036 exhost = host_list->hosts[i];
1037 if (exhost) {
1038 free(exhost);
1039 exhost = NULL;
1040 }
1041
1042 k = i;
1043 while (k < host_list->numhosts) {
1044 host_list->hosts[k] = k < host_list->numhosts - 1 ?
1045 host_list->hosts[k+1] : NULL;
1046 k++;
1047 }
1048 host_list->numhosts--;
1049
1050 bcopy(&host_list->configured[i+1],
1051 &host_list->configured[i],
1052 (MAXHOSTS - i + 1) * sizeof (int));
1053 host_list->configured[MAXHOSTS - 1] = 0;
1054 }
1055 }
1056 (void) mutex_unlock(&host_list->hosts_mutex);
1057 }
1058
1059 /*
1060 * explicity remove a host from the host list
1061 * also update the configured array
1062 * called in rdc_sync, just before exiting a thread.
1063 */
1064 void
remove_from_hostlist(char * host)1065 remove_from_hostlist(char *host)
1066 {
1067 int i, k;
1068 char *exhost;
1069
1070 /* why bother? */
1071 if ((!host) || (host[0] == '\0'))
1072 return;
1073
1074 (void) mutex_lock(&host_list->hosts_mutex);
1075 for (i = 0; i < host_list->numhosts; i++) {
1076 if (strcmp(host, host_list->hosts[i]) == 0) { /* found it */
1077 exhost = host_list->hosts[i];
1078 if (exhost) {
1079 free(exhost);
1080 exhost = NULL;
1081 }
1082 k = i;
1083 while (k < host_list->numhosts) {
1084 host_list->hosts[k] = k < host_list->numhosts - 1 ?
1085 host_list->hosts[k+1] : NULL;
1086 k++;
1087 }
1088 host_list->numhosts--;
1089 bcopy(&host_list->configured[i+1],
1090 &host_list->configured[i],
1091 (MAXHOSTS - i + 1) * sizeof (int));
1092 host_list->configured[MAXHOSTS - 1] = 0;
1093 }
1094
1095 }
1096 (void) mutex_unlock(&host_list->hosts_mutex);
1097 }
1098 /*
1099 * Check to see if this host isn't in our list, so needs a new rdcsyncd proc
1100 */
1101 int
isnewhost(char * host)1102 isnewhost(char *host)
1103 {
1104 int i;
1105 int new;
1106
1107 if (self_check(host)) {
1108 return (0);
1109 }
1110
1111 (void) mutex_lock(&host_list->hosts_mutex);
1112 new = 1;
1113 for (i = 0; i < MAXHOSTS; i++) {
1114 if (host_list->configured[i] == 0) {
1115 host_list->configured[i] = 1;
1116 host_list->hosts[i] = strdup(host);
1117 host_list->numhosts++;
1118 break;
1119 }
1120 if (strcmp(host, host_list->hosts[i]) == 0) {
1121 new = 0;
1122 break;
1123 }
1124 }
1125 (void) mutex_unlock(&host_list->hosts_mutex);
1126 if (i == MAXHOSTS)
1127 new = 0;
1128 return (new);
1129 }
1130
1131
1132 /*
1133 * Look for a matching volume name in our remembered list.
1134 */
1135 int
volume_match(char * buf,char ** volume_list,int volumes)1136 volume_match(char *buf, char **volume_list, int volumes)
1137 {
1138 int i;
1139 char *vol;
1140
1141 for (i = 0; i < volumes; i++) {
1142 vol = volume_list[i];
1143 if (strcmp(buf, vol) == 0) {
1144 return (1);
1145 }
1146 }
1147 return (0);
1148 }
1149
1150
1151 /*
1152 * A sync has completed to a group. We can only update the ndr_ii entries
1153 * if all the members of the group have completed their syncs OK.
1154 * It would be bad to allow some members of the group to have PIT Copy snapshots
1155 * taken and others not, as they need to be consistent.
1156 */
1157 void
group_complete(char * group)1158 group_complete(char *group)
1159 {
1160 char **volumes = NULL;
1161 spcs_s_info_t ustatus;
1162 rdc_config_t parms = { 0 };
1163 char buf[CFG_MAX_BUF];
1164 char key[CFG_MAX_KEY];
1165 CFGFILE *cfg = NULL;
1166 int i;
1167 int setnumber;
1168 int found;
1169 int replicating = 0;
1170 char primary[NSC_MAXPATH];
1171 char secondary[NSC_MAXPATH];
1172 char phost[MAX_RDC_HOST_SIZE];
1173 char shost[MAX_RDC_HOST_SIZE];
1174 rdc_set_t *rdc_set;
1175 int sev;
1176 char *local_file;
1177 int size;
1178
1179 ustatus = spcs_s_ucreate();
1180
1181 size = sizeof (char *) * rdc_maxsets;
1182 volumes = malloc(size);
1183 if (volumes == NULL) {
1184 spcs_log("sndr", NULL,
1185 gettext("%s: unable to allocate %ld bytes"),
1186 program, size);
1187 rdc_warn(NULL,
1188 gettext("unable to allocate %ld bytes"), size);
1189 goto done;
1190 }
1191 bzero(volumes, size);
1192
1193 /*
1194 * If all members of this group are replicating
1195 * set ii_ndr state to "update". Otherwise leave them alone.
1196 */
1197 LOCKCFG();
1198 if ((cfg = cfg_open(NULL)) == NULL) {
1199 spcs_log("sndr", NULL,
1200 gettext("%s: error opening lconfig"),
1201 program);
1202 rdc_warn(NULL, gettext("error opening config"));
1203 UNLOCKCFG();
1204 goto done;
1205 }
1206
1207 if (!cfg_lock(cfg, CFG_RDLOCK)) {
1208 spcs_log("sndr", NULL,
1209 gettext("%s: error locking config"),
1210 program);
1211 rdc_warn(NULL, gettext("error locking config"));
1212 goto done;
1213 }
1214
1215 found = 0;
1216
1217 /* get all RM entries, with a matching group, that are replicating */
1218 for (i = 0; i < rdc_maxsets; i++) {
1219 setnumber = i + 1;
1220
1221 (void) snprintf(key, sizeof (key),
1222 "sndr.set%d.group", setnumber);
1223 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
1224 break;
1225
1226 if (strcmp(buf, group) != 0)
1227 continue;
1228
1229 /* Found a matching entry */
1230
1231 (void) snprintf(key, sizeof (key),
1232 "sndr.set%d.primary", setnumber);
1233 if (cfg_get_cstring(cfg, key, primary, sizeof (primary)) < 0)
1234 break;
1235 (void) strcpy(parms.rdc_set->primary.file, primary);
1236
1237 (void) snprintf(key, sizeof (key),
1238 "sndr.set%d.phost", setnumber);
1239 if (cfg_get_cstring(cfg, key, phost, sizeof (phost)) < 0)
1240 break;
1241 (void) strcpy(parms.rdc_set->primary.intf, phost);
1242
1243 (void) snprintf(key, sizeof (key),
1244 "sndr.set%d.secondary", setnumber);
1245 if (cfg_get_cstring(cfg, key, secondary,
1246 sizeof (secondary)) < 0)
1247 break;
1248 (void) strcpy(parms.rdc_set->secondary.file, secondary);
1249
1250 (void) snprintf(key, sizeof (key),
1251 "sndr.set%d.shost", setnumber);
1252 if (cfg_get_cstring(cfg, key, shost, sizeof (shost)) < 0)
1253 break;
1254 (void) strcpy(parms.rdc_set->secondary.intf, shost);
1255
1256 parms.command = RDC_CMD_STATUS;
1257 if (RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus) < 0) {
1258 continue;
1259 }
1260
1261 /* We found a matching set */
1262 found++;
1263
1264 if (self_check(phost))
1265 local_file = primary;
1266 else
1267 local_file = secondary;
1268
1269 rdc_set = &parms.rdc_set[0];
1270 if (!(rdc_set->flags & RDC_LOGGING) &&
1271 !(rdc_set->flags & RDC_SYNCING)) {
1272 volumes[replicating] = strdup(local_file);
1273 if (volumes[replicating] == NULL) {
1274 size = strlen(local_file);
1275 spcs_log("sndr", NULL,
1276 gettext("%s: unable to allocate %ld bytes"),
1277 program, size);
1278 rdc_warn(NULL,
1279 gettext("unable to allocate %ld bytes"),
1280 size);
1281 goto done;
1282 }
1283 /* We remember all replicating sets */
1284 replicating++;
1285 } else
1286 break; /* Not all replicating, so done */
1287 }
1288
1289 if (found != replicating)
1290 goto done;
1291
1292 /* All replicating, so update ndr_ii state fields */
1293
1294 cfg_unlock(cfg);
1295
1296 if (!cfg_lock(cfg, CFG_WRLOCK)) {
1297 spcs_log("sndr", NULL,
1298 gettext("%s: error locking lconfig"),
1299 program);
1300 rdc_warn(NULL, gettext("error locking config"));
1301 goto done;
1302 }
1303
1304 /*
1305 * Search through the ndr_ii entries for entries
1306 * that match the saved secondary volume names.
1307 * Set state to "update".
1308 */
1309
1310 for (i = 0; ; i++) {
1311 setnumber = i + 1;
1312
1313 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.secondary",
1314 setnumber);
1315 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
1316 break;
1317
1318 if (!volume_match(buf, volumes, found)) {
1319 continue;
1320 }
1321
1322 /* Got a matching entry */
1323
1324 (void) snprintf(key, sizeof (key),
1325 "ndr_ii.set%d.state", setnumber);
1326 if ((cfg_put_cstring(cfg, key, UPDATE, strlen(UPDATE)) < 0) ||
1327 (cfg_commit(cfg) < 0)) {
1328 spcs_log("sndr", NULL,
1329 gettext("%s: unable to update \"%s\" "
1330 "in configuration storage: %s"),
1331 program, buf, cfg_error(&sev));
1332 rdc_warn(NULL,
1333 gettext("unable to update \"%s\" "
1334 "in configuration storage: %s"),
1335 buf, cfg_error(&sev));
1336 }
1337 }
1338
1339
1340 done:
1341 if (cfg) {
1342 cfg_close(cfg);
1343 UNLOCKCFG();
1344 }
1345 spcs_s_ufree(&ustatus);
1346 if (volumes) {
1347 for (i = 0; i < replicating; i++)
1348 free(volumes[i]);
1349 free(volumes);
1350 }
1351 }
1352
1353
1354 /*
1355 * Sync started to a member of a group.
1356 * If all members of the group are in ndr_ii state "update" then take an PIT
1357 * snapshot on all of them. This will provide a consistent point-in-time
1358 * copy until whatever syncs take place are all completed.
1359 */
1360 void
group_start(char * group)1361 group_start(char *group)
1362 {
1363 char **masters = NULL;
1364 char **shadows = NULL;
1365 char **bitmaps = NULL;
1366 char cmd[256];
1367 char buf[CFG_MAX_BUF];
1368 char key[CFG_MAX_KEY];
1369 CFGFILE *cfg = NULL;
1370 int i;
1371 int j;
1372 int setnumber;
1373 int found;
1374 int sndr_sets = 0;
1375 int update_needed = 0;
1376 int sev;
1377 char *ctag = NULL;
1378 int commit = 0;
1379 int size;
1380
1381 size = sizeof (char *) * rdc_maxsets;
1382 masters = malloc(size);
1383 if (masters == NULL) {
1384 spcs_log("sndr", NULL,
1385 gettext("%s: unable to allocate %ld bytes"),
1386 program, size);
1387 rdc_warn(NULL,
1388 gettext("unable to allocate %ld bytes"), size);
1389 goto done;
1390 }
1391 bzero(masters, size);
1392 shadows = malloc(size);
1393 if (shadows == NULL) {
1394 spcs_log("sndr", NULL,
1395 gettext("%s: unable to allocate %ld bytes"),
1396 program, size);
1397 rdc_warn(NULL,
1398 gettext("unable to allocate %ld bytes"), size);
1399 goto done;
1400 }
1401 bzero(shadows, size);
1402 bitmaps = malloc(size);
1403 if (bitmaps == NULL) {
1404 spcs_log("sndr", NULL,
1405 gettext("%s: unable to allocate %ld bytes"),
1406 program, size);
1407 rdc_warn(NULL,
1408 gettext("unable to allocate %ld bytes"), size);
1409 goto done;
1410 }
1411 bzero(bitmaps, size);
1412
1413 LOCKCFG();
1414 if ((cfg = cfg_open(NULL)) == NULL) {
1415 spcs_log("sndr", NULL,
1416 gettext("%s: error opening config"),
1417 program);
1418 rdc_warn(NULL,
1419 gettext("error opening config"));
1420 UNLOCKCFG();
1421 goto done;
1422 }
1423
1424 if (!cfg_lock(cfg, CFG_WRLOCK)) {
1425 spcs_log("sndr", NULL,
1426 gettext("%s: error locking config"),
1427 program);
1428 rdc_warn(NULL, gettext("error locking config"));
1429 goto done;
1430 }
1431
1432 /* Now get all Remote Mirror entries with a matching group */
1433 for (i = 0; i < rdc_maxsets; i++) {
1434 setnumber = i + 1;
1435
1436 (void) snprintf(key, sizeof (key),
1437 "sndr.set%d.group", setnumber);
1438 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
1439 break;
1440
1441 if (strcmp(buf, group) != 0)
1442 continue;
1443
1444 /* Found a matching entry */
1445
1446 (void) snprintf(key, sizeof (key),
1447 "sndr.set%d.phost", setnumber);
1448 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0)
1449 break;
1450
1451 if (self_check(buf)) {
1452 (void) snprintf(key, sizeof (key), "sndr.set%d.primary",
1453 setnumber);
1454 } else {
1455 (void) snprintf(key, sizeof (key),
1456 "sndr.set%d.secondary", setnumber);
1457 }
1458 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0)
1459 break;
1460
1461 masters[sndr_sets] = strdup(buf);
1462 if (masters[sndr_sets] == NULL) {
1463 size = strlen(buf);
1464 spcs_log("sndr", NULL,
1465 gettext("%s: unable to allocate %ld bytes"),
1466 program, size);
1467 rdc_warn(NULL,
1468 gettext("unable to allocate %ld bytes"), size);
1469 goto done;
1470 }
1471 sndr_sets++;
1472
1473 if (ctag == NULL && clustered) {
1474 /* Get cluster tag of matching entry */
1475
1476 (void) snprintf(key, sizeof (key), "sndr.set%d.cnode",
1477 setnumber);
1478 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) >= 0)
1479 ctag = strdup(buf);
1480 }
1481 }
1482
1483 /*
1484 * Search through the ndr_ii entries for entries
1485 * that match the saved local volume names and are in "update" state.
1486 */
1487
1488 update_needed = 0;
1489
1490 for (i = 0; ; i++) {
1491 setnumber = i + 1;
1492
1493 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.secondary",
1494 setnumber);
1495 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
1496 break;
1497
1498 if (!volume_match(buf, masters, sndr_sets))
1499 continue;
1500
1501 /* Got a matching entry */
1502
1503 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.shadow",
1504 setnumber);
1505 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
1506 break;
1507 shadows[update_needed] = strdup(buf);
1508 if (shadows[update_needed] == NULL) {
1509 size = strlen(buf);
1510 spcs_log("sndr", NULL,
1511 gettext("%s: unable to allocate %ld bytes"),
1512 program, size);
1513 rdc_warn(NULL,
1514 gettext("unable to allocate %ld bytes"), size);
1515 goto done;
1516 }
1517
1518 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.bitmap",
1519 setnumber);
1520 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
1521 break;
1522 }
1523 bitmaps[update_needed] = strdup(buf);
1524 if (bitmaps[update_needed] == NULL) {
1525 size = strlen(buf);
1526 spcs_log("sndr", NULL,
1527 gettext("%s: unable to allocate %ld bytes"),
1528 program, size);
1529 rdc_warn(NULL,
1530 gettext("unable to allocate %ld bytes"), size);
1531 goto done;
1532 }
1533
1534 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.state",
1535 setnumber);
1536 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
1537 break;
1538 }
1539 if (strcmp(buf, UPDATE) != 0) {
1540 break;
1541 }
1542
1543 update_needed++;
1544 }
1545
1546 if (update_needed != sndr_sets) {
1547 #ifdef DEBUG
1548 spcs_log("sndr", NULL,
1549 gettext("%s: group sync: no Point-in-Time Copy snapshot "
1550 "for %s"), program, group);
1551 #endif
1552 goto done;
1553 }
1554
1555 /* All RM sets in the group have an ndr_ii entry in "update" state */
1556
1557 /* Issue PIT Copy snapshot commands for all sets in the group */
1558 for (j = 0; j < sndr_sets; j++) {
1559 found = 0;
1560
1561 /* get ii entries until a match is found */
1562 for (i = 0; ; i++) {
1563 setnumber = i + 1;
1564
1565 (void) snprintf(key, sizeof (key), "ii.set%d.shadow",
1566 setnumber);
1567 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
1568 break;
1569 if (strcmp(buf, shadows[j]) != 0)
1570 continue;
1571
1572 /* Matching shadow found, so ii already enabled */
1573 found = 1;
1574 break;
1575 }
1576
1577 if (commit)
1578 if (cfg_commit(cfg) < 0)
1579 rdc_warn(NULL, gettext("commit config error"));
1580 cfg_close(cfg);
1581
1582 if (found) {
1583 (void) sprintf(cmd, "%s -u s %s", IIADM, shadows[j]);
1584 } else {
1585 if (ctag) {
1586 (void) sprintf(cmd, "%s -C %s -e dep %s %s %s",
1587 IIADM, ctag, masters[j], shadows[j],
1588 bitmaps[j]);
1589 free(ctag);
1590 ctag = NULL;
1591 } else
1592 (void) sprintf(cmd, "%s -e dep %s %s %s", IIADM,
1593 masters[j], shadows[j], bitmaps[j]);
1594 }
1595
1596 if (system(cmd) != 0) {
1597 spcs_log("sndr", NULL,
1598 gettext("%s: group sync: Point-in-Time Copy"
1599 " snapshot failed for %s"),
1600 program, masters[j]);
1601
1602 goto done;
1603 }
1604
1605 if ((cfg = cfg_open(NULL)) == NULL) {
1606 spcs_log("sndr", NULL,
1607 gettext("%s: error opening config"),
1608 program);
1609 rdc_warn(NULL,
1610 gettext("error opening config"));
1611 goto done;
1612 }
1613 if (!cfg_lock(cfg, CFG_WRLOCK)) {
1614 spcs_log("sndr", NULL,
1615 gettext("%s: error locking config"),
1616 program);
1617 rdc_warn(NULL, gettext("error locking config"));
1618 goto done;
1619 }
1620 commit = 0;
1621
1622 /* PIT enable or update was fine, so update the ndr_ii entry */
1623
1624 /* get ndr_ii entries until a match is found */
1625 for (i = 0; ; i++) {
1626 setnumber = i + 1;
1627
1628 (void) snprintf(key, sizeof (key),
1629 "ndr_ii.set%d.shadow", setnumber);
1630 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0)
1631 break;
1632 if (strcmp(buf, shadows[j]) != 0)
1633 continue;
1634
1635 /* Found the matching entry */
1636
1637 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.state",
1638 setnumber);
1639 if (cfg_put_cstring(cfg, key, NOUPDATE,
1640 strlen(NOUPDATE)) < 0) {
1641 spcs_log("sndr", NULL,
1642 gettext("%s: unable to update \"%s\" "
1643 "in configuration storage: %s"),
1644 program, buf, cfg_error(&sev));
1645 rdc_warn(NULL,
1646 gettext("unable to update \"%s\" "
1647 "in configuration storage: %s"),
1648 buf, cfg_error(&sev));
1649 } else
1650 commit = 1;
1651 break;
1652 }
1653 }
1654
1655 if (commit)
1656 if (cfg_commit(cfg) < 0)
1657 rdc_warn(NULL, gettext("commit config error"));
1658
1659 spcs_log("sndr", NULL,
1660 gettext("%s: group sync: Point-in-Time Copy snapshots completed "
1661 "for %s"), program, group);
1662
1663 done:
1664 if (ctag)
1665 free(ctag);
1666
1667 if (cfg) {
1668 cfg_close(cfg);
1669 UNLOCKCFG();
1670 }
1671
1672 if (masters) {
1673 for (i = 0; i < sndr_sets; i++) {
1674 if (masters[i])
1675 free(masters[i]);
1676 }
1677 free(masters);
1678 }
1679
1680 if (shadows) {
1681 for (i = 0; i < update_needed; i++) {
1682 if (shadows[i])
1683 free(shadows[i]);
1684 }
1685 free(shadows);
1686 }
1687
1688 if (bitmaps) {
1689 for (i = 0; i < update_needed; i++) {
1690 if (bitmaps[i])
1691 free(bitmaps[i]);
1692 }
1693 free(bitmaps);
1694 }
1695 }
1696