8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / avs / dsw / iiadm.c
blobdd49e10e4e918a8ee9f2da8738eec48d2ae737f0
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <errno.h>
29 #include <signal.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <values.h>
36 #include <locale.h>
37 #include <langinfo.h>
38 #include <sys/mman.h>
39 #include <sys/stat.h>
40 #include <sys/wait.h>
41 #include <strings.h>
42 #include <stdarg.h>
43 #include <ctype.h>
44 #include <math.h>
45 #include <sys/param.h>
46 #include <sys/mnttab.h>
47 #include <nsctl.h>
48 #include <netdb.h>
49 #include <search.h>
51 #include <sys/nsctl/cfg.h>
52 #include <sys/nsctl/nsc_hash.h>
54 #include <sys/unistat/spcs_s.h>
55 #include <sys/unistat/spcs_s_u.h>
56 #include <sys/unistat/spcs_errors.h>
57 #include <sys/nsctl/dsw.h>
58 #include <sys/nsctl/dsw_dev.h> /* for bit map header format */
60 #include <sys/nskernd.h>
62 typedef struct mstcount_s {
63 int count;
64 } mstcount_t;
65 typedef struct shdvol_s {
66 char master[ DSW_NAMELEN ];
67 } shdvol_t;
68 typedef struct grptag_s {
69 char ctag[ DSW_NAMELEN ];
70 } grptag_t;
71 hash_node_t **volhash = NULL;
73 #define DSW_TEXT_DOMAIN "II"
75 #include <dlfcn.h>
76 #define RDC_LIB "/usr/lib/librdc.so.1"
77 static int (*self_check)(char *);
80 * Support for the special cluster tag "local" to be used with -C in a
81 * cluster for local volumes.
83 #define II_LOCAL_TAG "local"
85 #define II_NOT_CLUSTER 1
86 #define II_CLUSTER 2
87 #define II_CLUSTER_LCL 3
89 static char *cfg_cluster_tag = NULL;
90 static CFGFILE *cfg = NULL;
92 void sigterm(int sig);
94 #define SD_BIT_CLR(bmap, bit) (bmap &= ~(1 << bit))
95 #define SD_BIT_ISSET(bmap, bit) ((bmap & (1 << bit)) != 0)
97 #define MAX_LINE_SIZE 256 /* maximum characters per line in config file */
98 #define MAX_GROUPS 1024 /* maximum number of groups to support */
99 #define MAX_CLUSTERS 1024 /* maximum number of resource groups */
101 unsigned long bm_size; /* size in bytes of bitmap */
102 unsigned long bm_actual; /* original number of bits in bitmap */
103 int debug = 0;
105 int dsw_fd;
107 #define LD_II 0x00000001
108 #define LD_DSVOLS 0x00000002
109 #define LD_SVOLS 0x00000004
110 #define LD_SHADOWS 0x00000008
112 static int reload_vols = 0;
113 static int config_locked = 0;
114 static int last_lock;
117 * names for do_copy() flags.
120 enum copy_update {Copy = 0, Update};
121 enum copy_direction {ToShadow = 0, ToMaster};
122 enum copy_wait {WaitForStart = 0, WaitForEnd};
124 char *cmdnam;
126 unsigned char *allocate_bitmap(char *);
127 void usage(char *);
128 void enable(char *, char *, char *, char *);
129 int disable(char *);
130 void bitmap_op(char *, int, int, int, int);
131 void print_status(dsw_config_t *, int);
132 int abort_copy(char *);
133 int reset(char *);
134 int overflow(char *);
135 void iiversion(void);
136 int wait_for_copy(char *);
137 int export(char *);
138 void list_volumes(void);
139 void dsw_error(char *, spcs_s_info_t *);
140 void InitEnv();
141 static void check_dg_is_local(char *dgname);
142 static int check_resource_group(char *volume);
143 static int check_diskgroup(char *path, char *result);
144 static int check_cluster();
145 static void unload_ii_vols();
146 static void load_ii_vols(CFGFILE *);
147 static int perform_autosv();
148 static int is_exported(char *);
149 static void conform_name(char **);
150 static void do_attach(dsw_config_t *);
151 static int ii_lock(CFGFILE *, int);
152 static void verify_groupname(char *grp, int testDash);
154 void dsw_list_clusters(char *);
155 void dsw_enable(int, char **);
156 void dsw_disable(int, char **);
157 void dsw_copy_to_shadow(int, char **);
158 void dsw_update_shadow(int, char **);
159 void dsw_copy_to_master(int, char **);
160 void dsw_update_master(int, char **);
161 void dsw_abort_copy(int, char **);
162 void dsw_display_status(int, char **);
163 void dsw_display_bitmap(int, char **);
164 void dsw_reset(int, char **);
165 void dsw_overflow(int, char **);
166 void dsw_version(int, char **);
167 void dsw_wait(int, char **);
168 void dsw_list_volumes(int, char **);
169 void dsw_list_group_volumes();
170 void dsw_export(int, char **);
171 void dsw_import(int, char **);
172 void dsw_join(int, char **);
173 void dsw_attach(int, char **);
174 void dsw_detach(int, char **);
175 void dsw_params(int, char **);
176 void dsw_olist(int, char **);
177 void dsw_ostat(int, char **);
178 void dsw_move_2_group(int, char **);
179 void dsw_list_groups();
180 void check_iishadow(char *);
182 extern char *optarg;
183 extern int optind, opterr, optopt;
185 int Aflg;
186 int Cflg;
187 int CLflg;
188 int Dflg;
189 int Eflg;
190 int Iflg;
191 int Jflg;
192 int Lflg;
193 int Oflg;
194 int Pflg;
195 int Qflg;
196 int Rflg;
197 int aflg;
198 int bflg;
199 int cflg;
200 int dflg;
201 int eflg;
202 int fflg;
203 int gflg;
204 int gLflg;
205 int hflg;
206 int iflg;
207 int lflg;
208 int mflg;
209 int nflg;
210 int pflg;
211 int uflg;
212 int vflg;
213 int wflg;
215 int errflg;
216 #ifdef DEBUG
217 const char single_opts[] =
218 "a:b:c:d:e:f:g:hilmnpu:vw:A:C:D:E:I:J:LO:PQ:R:";
219 #else
220 /* no b or f flags */
221 const char single_opts[] = "a:c:d:e:g:hilmnpu:vw:A:C:D:E:I:J:LO:PQ:R:";
222 #endif
223 const char group_opts[] = "ac:de:ilmnpu:wA:C:DELPR";
224 const char *opt_list = single_opts;
226 char buf[CFG_MAX_BUF];
227 char key[CFG_MAX_KEY];
228 char last_overflow[DSW_NAMELEN];
229 int setnumber;
230 char *group_name;
231 char **group_volumes;
232 enum copy_direction direction;
233 char *param_delay, *param_unit;
234 char *overflow_file;
236 #ifdef lint
238 iiadm_lintmain(int argc, char *argv[])
239 #else
241 main(int argc, char *argv[])
242 #endif
244 int c;
245 int actions = 0;
246 int ac;
247 char *av[1024];
249 InitEnv();
251 (void) memset(av, 0, sizeof (av));
252 cmdnam = argv[0];
253 while ((c = getopt(argc, argv, opt_list)) != EOF)
254 switch (c) {
255 case 'c':
256 cflg++;
257 actions++;
258 if (strcmp(optarg, "m") == 0) {
259 av[0] = "copy_to_master";
260 direction = ToMaster;
261 } else if (strcmp(optarg, "s") == 0) {
262 av[0] = "copy_to_shadow";
263 direction = ToShadow;
264 } else {
265 errflg ++;
266 usage(gettext(
267 "must specify m or s with -c"));
269 ac = 2;
270 break;
271 case 'd':
272 dflg++;
273 actions++;
274 av[0] = "disable";
275 av[1] = optarg;
276 ac = 2;
277 break;
278 case 'e':
279 eflg++;
280 actions++;
281 av[0] = "enable";
282 if (strcmp(optarg, "ind") == 0)
283 av[4] = "independent";
284 else if (strcmp(optarg, "dep") == 0)
285 av[4] = "dependent";
286 else {
287 errflg ++;
288 usage(gettext(
289 "must specify ind or dep with -e"));
291 ac = 1;
292 break;
293 case 'g':
294 gflg++;
295 opt_list = group_opts;
296 group_name = optarg;
297 if (group_name && *group_name == '-') {
298 gLflg = (strcmp("-L", group_name) == 0);
299 if (gLflg)
300 actions++;
302 verify_groupname(group_name, !gLflg);
303 break;
304 case 'h':
305 hflg++;
306 actions++;
307 break;
308 case 'u':
309 uflg++;
310 actions++;
311 if (strcmp(optarg, "m") == 0) {
312 av[0] = "update_master";
313 direction = ToMaster;
314 } else if (strcmp(optarg, "s") == 0) {
315 av[0] = "update_shadow";
316 direction = ToShadow;
317 } else {
318 errflg ++;
319 usage(gettext(
320 "must specify m or s with -u"));
322 ac = 2;
323 break;
324 case 'i':
325 iflg++;
326 actions++;
327 av[0] = "display_status";
328 break;
329 case 'l':
330 lflg++;
331 actions++;
332 av[0] = "list_config";
333 ac = 1;
334 break;
335 case 'm':
336 mflg++;
337 actions++;
338 av[0] = "move_to_group";
339 ac = 1;
340 break;
341 case 'n':
342 nflg++;
343 break;
344 case 'p':
345 pflg++;
346 break;
347 case 'b':
348 bflg++;
349 actions++;
350 av[0] = "display_bitmap";
351 av[1] = optarg;
352 ac = 2;
353 break;
354 case 'a':
355 aflg++;
356 actions++;
357 av[0] = "abort_copy";
358 av[1] = optarg;
359 ac = 2;
360 break;
361 case 'v':
362 vflg++;
363 actions++;
364 av[1] = "version";
365 ac = 1;
366 break;
367 case 'w':
368 wflg++;
369 actions++;
370 av[0] = "wait";
371 av[1] = optarg;
372 ac = 2;
373 break;
374 case 'A':
375 Aflg++;
376 actions++;
377 av[0] = "attach";
378 av[1] = optarg;
379 ac = 2;
380 break;
381 case 'C':
382 Cflg++;
383 cfg_cluster_tag = optarg;
384 if (cfg_cluster_tag && *cfg_cluster_tag == '-') {
385 CLflg = (strcmp("-L", cfg_cluster_tag) == 0);
386 if (CLflg)
387 actions++;
389 break;
390 case 'D':
391 Dflg++;
392 actions++;
393 av[0] = "detach";
394 av[1] = optarg;
395 ac = 2;
396 break;
397 case 'O':
398 Oflg++;
399 actions++;
400 av[0] = "overflow";
401 av[1] = optarg;
402 ac = 2;
403 break;
404 case 'R':
405 Rflg++;
406 actions++;
407 av[0] = "reset";
408 av[1] = optarg;
409 ac = 2;
410 break;
411 case 'E':
412 Eflg++;
413 actions++;
414 av[0] = "export";
415 av[1] = optarg;
416 ac = 2;
417 break;
418 case 'I':
419 Iflg++;
420 actions++;
421 av[0] = "import";
422 av[1] = optarg;
423 ac = 2;
424 break;
425 case 'J':
426 Jflg++;
427 actions++;
428 av[0] = "join";
429 av[1] = optarg;
430 ac = 2;
431 break;
432 case 'P':
433 Pflg++;
434 actions++;
435 av[0] = "parameter";
436 ac = 1;
437 break;
438 case 'L':
439 Lflg++;
440 actions++;
441 /* If -g group -L, force error */
442 if (group_name) actions++;
443 av[0] = "LIST";
444 ac = 1;
445 break;
446 case 'Q':
447 Qflg++;
448 actions++;
449 av[0] = "query";
450 av[1] = optarg;
451 ac = 2;
452 break;
453 case '?':
454 errflg++;
455 break;
457 if (hflg) {
458 usage(NULL);
459 exit(0);
462 if (errflg)
463 usage(gettext("unrecognized argument"));
464 switch (actions) {
465 case 0:
466 if (argc > 1)
467 usage(gettext("must specify an action flag"));
469 /* default behavior is to list configuration */
470 lflg++; av[0] = "list_config"; ac = 1;
471 break;
472 case 1:
473 break;
474 default:
475 usage(gettext("too many action flags"));
476 break;
479 if (gflg && (Iflg || Jflg || Oflg || Qflg))
480 usage(gettext("can't use a group with this option"));
481 if (!gflg && (mflg))
482 usage(gettext("must use a group with this option"));
485 * Open configuration file.
487 if ((cfg = cfg_open(NULL)) == NULL) {
488 perror("unable to access configuration");
489 exit(2);
493 * Set write locking (CFG_WRLOCK) for:
494 * iiadm -e (enable)
495 * iiadm -d (disable)
496 * iiadm -A (attach overflow)
497 * iiadm -D (detach overflow)
498 * iiadm -g grp -m volume (move volume into group)
499 * iiadm -E (export shadow [needs to update dsvol section])
500 * iiadm -I (import shadow [ditto])
501 * iiadm -J (join shadow [ditto])
502 * read locking (CFG_RDLOCK) for all other commands
504 last_lock = (eflg || dflg || mflg || Aflg || Dflg || Eflg || Iflg ||
505 Jflg)? CFG_WRLOCK : CFG_RDLOCK;
506 if (!cfg_lock(cfg, last_lock)) {
507 perror("unable to lock configuration");
508 exit(2);
510 config_locked = 1;
513 * If we are in a cluster, set or derive a valid disk group
515 switch (check_cluster()) {
516 case II_CLUSTER:
518 * If in a Sun Cluster, can't Import an II shadow
519 * Must be done as -C local
521 if (Iflg)
522 dsw_error(gettext(
523 "-I (import) only allowed as -C local"), NULL);
524 /*FALLTHRU*/
525 case II_CLUSTER_LCL:
527 * If a cluster tag was specified or derived, set it
529 if (CLflg) {
530 dsw_list_clusters(argv[optind]);
531 cfg_close(cfg);
532 exit(0);
533 } else {
534 cfg_resource(cfg, cfg_cluster_tag);
536 break;
537 case II_NOT_CLUSTER:
538 if (cfg_cluster_tag != NULL)
539 dsw_error(gettext(
540 "-C is valid only in a Sun Cluster"), NULL);
541 break;
542 default:
543 dsw_error(gettext(
544 "Unexpected return from check_cluster()"), NULL);
547 /* preload the ii config */
548 load_ii_vols(cfg);
549 reload_vols |= LD_II;
551 if (eflg) {
552 if (argc - optind != 3)
553 usage(gettext("must specify 3 volumes with -e"));
554 av[1] = argv[optind++];
555 av[2] = argv[optind++];
556 av[3] = argv[optind++];
557 ac = 5;
558 dsw_enable(ac, av);
559 } else if (dflg) {
560 dsw_disable(ac, av);
561 } else if (uflg) {
562 if (argv[optind] == NULL && group_name == NULL)
563 usage(gettext("must specify volume with -u"));
564 for (c = 1; argv[optind] != NULL; optind++)
565 av[c++] = argv[optind];
566 av[c] = NULL;
568 if (direction == ToMaster)
569 dsw_update_master(ac, av);
570 else
571 dsw_update_shadow(ac, av);
572 } else if (iflg) {
573 if (argv[optind]) {
574 av[1] = argv[optind];
575 ac = 2;
576 } else
577 ac = 1;
578 dsw_display_status(ac, av);
579 } else if (bflg) {
580 dsw_display_bitmap(ac, av);
581 } else if (cflg) {
582 if (argv[optind] == NULL && group_name == NULL)
583 usage(gettext("must specify volume with -c"));
584 for (c = 1; argv[optind] != NULL; optind++)
585 av[c++] = argv[optind];
586 av[c] = NULL;
588 if (direction == ToMaster)
589 dsw_copy_to_master(ac, av);
590 else
591 dsw_copy_to_shadow(ac, av);
592 } else if (aflg) {
593 dsw_abort_copy(ac, av);
594 } else if (Eflg) {
595 dsw_export(ac, av);
596 } else if (Iflg) {
597 if (argc - optind != 1)
598 usage(gettext("must specify 2 volumes with -I"));
599 av[2] = argv[optind++];
600 ac = 3;
601 dsw_import(ac, av);
602 } else if (Aflg) {
603 if (group_name) {
604 if (argc - optind != 0)
605 usage(gettext("must specify overflow volume " \
606 "when using groups with -A"));
607 ac = 2;
608 } else {
609 if (argc - optind != 1)
610 usage(gettext("specify 2 volumes with -A"));
611 ac = 3;
612 av[2] = argv[optind++];
614 dsw_attach(ac, av);
615 } else if (Dflg) {
616 dsw_detach(ac, av);
617 } else if (Jflg) {
618 if (argc - optind != 1)
619 usage(gettext("must specify 2 volumes with -J"));
620 av[2] = argv[optind++];
621 ac = 3;
622 dsw_join(ac, av);
623 } else if (Pflg) {
624 if (argc - optind == ((group_name) ? 0 : 1)) {
625 av[1] = argv[optind++];
626 ac = (group_name) ? 0 : 2;
627 } else if (argc - optind == ((group_name) ? 2 : 3)) {
628 av[1] = argv[optind++];
629 av[2] = argv[optind++];
630 av[3] = argv[optind++];
631 ac = (group_name) ? 2 : 4;
632 } else
633 usage(gettext(
634 "must specify delay, unit and shadow with -P"));
635 dsw_params(ac, av);
636 } else if (Oflg) {
637 dsw_overflow(ac, av);
638 } else if (Rflg) {
639 dsw_reset(ac, av);
640 } else if (vflg) {
641 dsw_version(ac, av);
642 } else if (wflg) {
643 dsw_wait(ac, av);
644 } else if (lflg) {
645 if ((gflg) && (!group_name))
646 dsw_list_group_volumes();
647 else
648 dsw_list_volumes(ac, av);
649 } else if (Lflg) {
650 dsw_olist(ac, av);
651 } else if (gLflg) {
652 dsw_list_groups();
653 } else if (Qflg) {
654 dsw_ostat(ac, av);
655 } else if (mflg) {
656 if (argc - optind < 1)
657 usage(gettext("must specify one or more volumes"));
658 for (c = 1; argv[optind] != NULL; optind++)
659 av[c++] = argv[optind];
660 av[c] = NULL;
661 dsw_move_2_group(ac, av);
663 if (cfg)
664 cfg_close(cfg);
666 exit(0);
667 return (0);
670 static int
671 ii_lock(CFGFILE *cfg, int locktype)
673 last_lock = locktype;
674 return (cfg_lock(cfg, locktype));
677 static int
678 do_ioctl(int fd, int cmd, void *arg)
680 int unlocked = 0;
681 int rc;
682 int save_errno;
684 if (config_locked) {
685 switch (cmd) {
686 case DSWIOC_ENABLE:
687 case DSWIOC_RESUME:
688 case DSWIOC_SUSPEND:
689 case DSWIOC_COPY:
690 case DSWIOC_BITMAP:
691 case DSWIOC_DISABLE:
692 case DSWIOC_SHUTDOWN:
693 case DSWIOC_ABORT:
694 case DSWIOC_RESET:
695 case DSWIOC_OFFLINE:
696 case DSWIOC_WAIT:
697 case DSWIOC_ACOPY:
698 case DSWIOC_EXPORT:
699 case DSWIOC_IMPORT:
700 case DSWIOC_JOIN:
701 case DSWIOC_COPYP:
702 case DSWIOC_OATTACH:
703 case DSWIOC_ODETACH:
704 case DSWIOC_SBITSSET:
705 case DSWIOC_CBITSSET:
706 case DSWIOC_SEGMENT:
707 case DSWIOC_MOVEGRP:
708 case DSWIOC_CHANGETAG:
709 cfg_unlock(cfg);
710 unlocked = 1;
711 break;
713 case DSWIOC_STAT:
714 case DSWIOC_VERSION:
715 case DSWIOC_LIST:
716 case DSWIOC_OCREAT:
717 case DSWIOC_OLIST:
718 case DSWIOC_OSTAT:
719 case DSWIOC_OSTAT2:
720 case DSWIOC_LISTLEN:
721 case DSWIOC_OLISTLEN:
722 case DSWIOC_CLIST:
723 case DSWIOC_GLIST:
724 break;
726 default:
727 (void) fprintf(stderr,
728 "cfg locking needs to be set for %08x\n", cmd);
729 exit(1);
730 break;
733 if (unlocked) {
734 /* unload vol hashes */
735 if (reload_vols & LD_II)
736 unload_ii_vols();
737 if (reload_vols & LD_SHADOWS)
738 cfg_unload_shadows();
739 if (reload_vols & LD_DSVOLS)
740 cfg_unload_dsvols();
741 if (reload_vols & LD_SVOLS)
742 cfg_unload_svols();
744 rc = ioctl(fd, cmd, arg);
745 save_errno = errno;
746 if (config_locked && unlocked) {
747 (void) cfg_lock(cfg, last_lock);
749 if (unlocked) {
750 /* reload vol hashes */
751 if (reload_vols & LD_SVOLS)
752 (void) cfg_load_svols(cfg);
753 if (reload_vols & LD_DSVOLS)
754 (void) cfg_load_dsvols(cfg);
755 if (reload_vols & LD_SHADOWS)
756 (void) cfg_load_shadows(cfg);
757 if (reload_vols & LD_II)
758 load_ii_vols(cfg);
761 errno = save_errno;
762 return (rc);
765 static int
766 get_dsw_config(int setno, dsw_config_t *parms)
768 char buf[CFG_MAX_BUF];
769 char key[CFG_MAX_KEY];
771 bzero(parms, sizeof (dsw_config_t));
772 (void) snprintf(key, sizeof (key), "ii.set%d.master", setno);
773 if (cfg_get_cstring(cfg, key, parms->master_vol, DSW_NAMELEN) < 0)
774 return (-1);
776 (void) snprintf(key, sizeof (key), "ii.set%d.shadow", setno);
777 (void) cfg_get_cstring(cfg, key, parms->shadow_vol, DSW_NAMELEN);
779 (void) snprintf(key, sizeof (key), "ii.set%d.bitmap", setno);
780 (void) cfg_get_cstring(cfg, key, parms->bitmap_vol, DSW_NAMELEN);
782 (void) snprintf(key, sizeof (key), "ii.set%d.mode", setno);
783 (void) cfg_get_cstring(cfg, key, buf, sizeof (buf));
784 if (strcmp(buf, "I") == 0)
785 parms->flag |= DSW_GOLDEN;
787 (void) snprintf(key, sizeof (key), "ii.set%d.overflow", setno);
788 (void) cfg_get_cstring(cfg, key, last_overflow, DSW_NAMELEN);
790 (void) snprintf(key, sizeof (key), "ii.set%d.group", setno);
791 (void) cfg_get_cstring(cfg, key, parms->group_name, DSW_NAMELEN);
793 (void) snprintf(key, sizeof (key), "ii.set%d.cnode", setno);
794 (void) cfg_get_cstring(cfg, key, parms->cluster_tag, DSW_NAMELEN);
795 return (0);
798 static int
799 find_next_cf_line(char *volume, int next)
801 dsw_config_t cf_line;
803 for (setnumber = next; get_dsw_config(setnumber, &cf_line) == 0;
804 setnumber++) {
805 if (strncmp(volume, cf_line.master_vol, DSW_NAMELEN) == 0 ||
806 strncmp(volume, cf_line.shadow_vol, DSW_NAMELEN) == 0 ||
807 strncmp(volume, cf_line.bitmap_vol, DSW_NAMELEN) == 0)
808 return (1);
810 return (0);
813 find_any_cf_line(char *volume)
815 return (find_next_cf_line(volume, 1));
818 static int
819 find_next_shadow_line(char *volume, int next)
821 dsw_config_t cf_line;
823 for (setnumber = next; get_dsw_config(setnumber, &cf_line) == 0;
824 setnumber++) {
825 if (strncmp(volume, cf_line.shadow_vol, DSW_NAMELEN) == 0)
826 return (1);
828 return (0);
831 find_shadow_line(char *volume)
833 return (find_next_shadow_line(volume, 1));
837 * this function is designed to be called once, subsequent calls won't
838 * free memory allocated by earlier invocations.
840 char *
841 get_overflow_list()
843 dsw_aioctl_t *acopy_args;
844 int rc, num;
846 num = do_ioctl(dsw_fd, DSWIOC_OLISTLEN, NULL);
847 if (num < 0)
848 dsw_error(gettext("Can't get overflow list length"), NULL);
850 acopy_args = malloc(sizeof (dsw_aioctl_t) + num * DSW_NAMELEN);
851 if (acopy_args == NULL)
852 dsw_error(gettext("Can't get memory for list enquiry"), NULL);
854 acopy_args->count = num;
855 acopy_args->flags = 0;
856 acopy_args->status = spcs_s_ucreate();
858 rc = do_ioctl(dsw_fd, DSWIOC_OLIST, acopy_args);
859 if (rc == -1)
860 dsw_error(gettext("Overflow list access failure"),
861 &acopy_args->status);
862 else
863 acopy_args->shadow_vol[DSW_NAMELEN*acopy_args->count] = NULL;
865 return (acopy_args->shadow_vol);
869 * this function is designed to be called once, subsequent calls won't
870 * free memory allocated by earlier invocations.
874 find_group_members(char *group)
876 int nmembers = 0;
877 int vector_len = 0;
879 group_volumes = NULL;
880 for (setnumber = 1; /*CSTYLED*/; setnumber++) {
881 (void) snprintf(key, sizeof (key), "ii.set%d.group", setnumber);
882 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0)
883 break;
885 if (strcmp(group, buf))
886 continue;
888 (void) snprintf(key, sizeof (key), "ii.set%d.shadow",
889 setnumber);
890 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0)
891 break;
893 if (nmembers >= vector_len) {
894 vector_len += 10;
895 group_volumes = realloc(group_volumes, (1+vector_len) *
896 sizeof (char *));
898 group_volumes[nmembers] = strdup(buf);
899 nmembers++;
901 if (group_volumes)
902 group_volumes[nmembers] = NULL; /* terminate list */
903 return (nmembers);
906 static int
907 find_next_matching_cf_line(
908 char *volume, dsw_config_t *conf, dsw_ioctl_t *io, int next)
910 dsw_config_t config;
912 if (!find_next_cf_line(volume, next)) {
913 return (0);
916 if (conf == NULL)
917 conf = &config;
918 (void) get_dsw_config(setnumber, conf);
919 if (io) {
920 (void) strlcpy(io->shadow_vol, conf->shadow_vol, DSW_NAMELEN);
922 return (1);
926 find_matching_cf_line(char *volume, dsw_config_t *conf, dsw_ioctl_t *io)
928 return (find_next_matching_cf_line(volume, conf, io, 1));
932 find_shadow_config(char *volume, dsw_config_t *conf, dsw_ioctl_t *io)
934 dsw_config_t *c, cf;
936 if (io) {
937 bzero(io, sizeof (dsw_ioctl_t));
939 c = conf ? conf : &cf;
940 setnumber = 1;
941 /* perform action for each line of the stored config file */
942 for ((void) snprintf(key, sizeof (key), "ii.set%d.shadow", setnumber);
943 cfg_get_cstring(cfg, key, c->shadow_vol, DSW_NAMELEN) >= 0;
944 (void) snprintf(key, sizeof (key), "ii.set%d.shadow",
945 ++setnumber)) {
946 if (strncmp(volume, c->shadow_vol, DSW_NAMELEN) == 0) {
947 (void) get_dsw_config(setnumber, c);
949 if (check_resource_group(c->bitmap_vol)) {
950 setnumber = 0;
951 continue;
954 switch (check_cluster()) {
955 case II_CLUSTER:
956 if ((cfg_cluster_tag) &&
957 (strcmp(cfg_cluster_tag, c->cluster_tag)))
958 continue;
959 break;
960 case II_CLUSTER_LCL:
961 if (strlen(c->cluster_tag))
962 continue;
963 break;
966 if (io) {
967 (void) strlcpy(io->shadow_vol, c->shadow_vol,
968 DSW_NAMELEN);
970 return (1);
973 return (0);
976 void
977 add_cfg_entry(dsw_config_t *parms)
979 /* insert the well-known fields first */
980 (void) snprintf(buf, sizeof (buf), "%s %s %s %s",
981 parms->master_vol, parms->shadow_vol, parms->bitmap_vol,
982 (parms->flag & DSW_GOLDEN) ? "I" : "D");
984 if (cfg_put_cstring(cfg, "ii", buf, strlen(buf)) >= 0) {
985 /* if we have a group name, add it */
986 if (group_name) {
987 if (find_any_cf_line(parms->shadow_vol)) {
988 (void) sprintf(buf, "ii.set%d.group",
989 setnumber);
990 if (cfg_put_cstring(cfg, buf,
991 group_name, strlen(group_name)) < 0)
992 perror("cfg_put_cstring");
994 else
995 perror("cfg_location");
998 /* commit the record */
999 (void) cfg_commit(cfg);
1001 else
1002 perror("cfg_put_string");
1005 void
1006 remove_iiset(int setno, char *shadow, int shd_exp)
1008 mstcount_t *mdata;
1009 shdvol_t *sdata;
1010 char sn[CFG_MAX_BUF];
1012 if (perform_autosv()) {
1013 if (volhash) {
1014 unload_ii_vols();
1016 load_ii_vols(cfg);
1017 if (cfg_load_dsvols(cfg) < 0 || cfg_load_svols(cfg) < 0) {
1018 dsw_error(gettext("Unable to parse config file"), NULL);
1021 sdata = (shdvol_t *)nsc_lookup(volhash, shadow);
1022 if (sdata) {
1024 * Handle the normal cases of disabling a set that is
1025 * not an imported shadow volume
1027 if (strcmp(sdata->master, II_IMPORTED_SHADOW)) {
1029 * Handle multiple-shadows of single master
1031 mdata = (mstcount_t *)
1032 nsc_lookup(volhash, sdata->master);
1033 if ((mdata) && (mdata->count == 1)) {
1034 if (cfg_vol_disable(cfg, sdata->master,
1035 cfg_cluster_tag, "ii") < 0)
1036 dsw_error(gettext(
1037 "SV disable of master "
1038 "failed"),
1039 NULL);
1044 * Handle disk group name of different shadow
1046 if (shd_exp) {
1048 * If shadow is exported, then do nothing
1050 /*EMPTY*/;
1051 } else if (cfg_cluster_tag &&
1052 strcmp(cfg_cluster_tag, "") &&
1053 cfg_dgname(shadow, sn, sizeof (sn)) &&
1054 strlen(sn) &&
1055 strcmp(sn, cfg_cluster_tag)) {
1056 /* reload disk group volumes */
1057 cfg_resource(cfg, sn);
1058 cfg_unload_dsvols();
1059 cfg_unload_svols();
1060 (void) cfg_load_dsvols(cfg);
1061 (void) cfg_load_svols(cfg);
1062 if (cfg_vol_disable(cfg, shadow, sn,
1063 "ii") < 0) {
1064 dsw_error(gettext(
1065 "SV disable of shadow "
1066 "failed"),
1067 NULL);
1069 cfg_resource(cfg, cfg_cluster_tag);
1070 } else {
1071 if (cfg_vol_disable(cfg, shadow,
1072 cfg_cluster_tag, "ii") < 0)
1073 dsw_error(gettext(
1074 "SV disable of shadow failed"),
1075 NULL);
1078 cfg_unload_svols();
1079 cfg_unload_dsvols();
1080 unload_ii_vols();
1081 reload_vols &= ~(LD_SVOLS | LD_DSVOLS | LD_II);
1084 (void) sprintf(key, "ii.set%d", setno);
1085 if (cfg_put_cstring(cfg, key, NULL, 0) < 0) {
1086 perror("cfg_put_cstring");
1088 (void) cfg_commit(cfg);
1092 * determine if we are running in a Sun Cluster Environment
1095 check_cluster()
1097 static int is_cluster = -1;
1098 int rc;
1099 #ifdef DEBUG
1100 char *cdebug = getenv("II_SET_CLUSTER");
1101 #endif
1104 * If this routine was previously called, just return results
1106 if (is_cluster != -1)
1107 return (is_cluster);
1110 * See if Sun Cluster was installed on this node
1112 #ifdef DEBUG
1113 if (cdebug) rc = atoi(cdebug);
1114 else
1115 #endif
1116 rc = cfg_iscluster();
1117 if (rc > 0) {
1119 * Determine if user specified -C local
1121 if ((cfg_cluster_tag == NULL) ||
1122 (strcmp(cfg_cluster_tag, II_LOCAL_TAG))) {
1124 * We're in a Sun Cluster, and no "-C local"
1126 is_cluster = II_CLUSTER;
1127 } else {
1129 * We're in a Sun Cluster, but "-C local" was specified
1131 is_cluster = II_CLUSTER_LCL;
1132 cfg_cluster_tag = "";
1134 return (is_cluster);
1135 } else if (rc == 0) {
1137 * Not in a Sun Cluster
1139 is_cluster = II_NOT_CLUSTER;
1140 return (is_cluster);
1141 } else {
1142 dsw_error(gettext("unable to ascertain environment"), NULL);
1143 /*NOTREACHED*/
1146 /* gcc */
1147 return (is_cluster);
1151 * Determine if we need to set a cfg_resource based on this volume
1153 static int
1154 check_resource_group(char *volume)
1156 char diskgroup[CFG_MAX_BUF];
1159 * If we are in a cluster, attempt to derive a new resource group
1162 #ifdef DEBUG
1163 if (getenv("II_SET_CLUSTER") || (check_cluster() == II_CLUSTER)) {
1164 #else
1165 if (check_cluster() == II_CLUSTER) {
1166 #endif
1167 if (check_diskgroup(volume, diskgroup)) {
1168 if (cfg_cluster_tag == NULL) {
1169 cfg_cluster_tag = strdup(diskgroup);
1170 if (cfg_cluster_tag == NULL)
1171 dsw_error(gettext(
1172 "Memory allocation failure"), NULL);
1173 cfg_resource(cfg, cfg_cluster_tag);
1174 return (1);
1175 } else {
1177 * Check dgname and cluster tag from -C are
1178 * the same.
1180 if (strcmp(diskgroup, cfg_cluster_tag) != 0) {
1181 char error_buffer[128];
1182 (void) snprintf(error_buffer,
1183 sizeof (error_buffer),
1184 gettext("-C (%s) does not match "
1185 "disk group name (%s) for %s"),
1186 cfg_cluster_tag, diskgroup, volume);
1187 spcs_log("ii", NULL, error_buffer);
1188 dsw_error(error_buffer, NULL);
1191 } else if (cfg_cluster_tag == NULL)
1192 dsw_error(gettext(
1193 "Point-in-Time Copy volumes, that are not "
1194 "in a device group which has been "
1195 "registered with SunCluster, "
1196 "require usage of \"-C\""), NULL);
1198 return (0);
1201 static void
1202 check_dg_is_local(char *dgname)
1204 char error_buffer[128];
1205 char *othernode;
1206 int rc;
1209 * check where this disk service is mastered
1211 rc = cfg_dgname_islocal(dgname, &othernode);
1212 if (rc < 0) {
1213 (void) snprintf(error_buffer, sizeof (error_buffer),
1214 gettext("Unable to find disk service:%s"), dgname);
1215 dsw_error(error_buffer, NULL);
1216 } else if (rc == 0) {
1217 (void) snprintf(error_buffer, sizeof (error_buffer),
1218 gettext("disk service, %s, is active on node \"%s\"\n"
1219 "Please re-issue the command on that node"), dgname,
1220 othernode);
1221 dsw_error(error_buffer, NULL);
1226 * Carry out cluster based checks for a specified volume, or just
1227 * global options.
1229 static int
1230 check_diskgroup(char *path, char *result)
1232 char dgname[CFG_MAX_BUF];
1233 char error_buffer[128];
1235 #ifdef DEBUG
1236 char *override = getenv("II_CLUSTER_TAG");
1237 if (override) {
1238 (void) strcpy(result, override);
1239 return (1);
1241 #endif
1243 * Check on path name, a returned NULL dgname is valid
1245 if (cfg_dgname(path, dgname, sizeof (dgname)) == NULL) {
1246 (void) snprintf(error_buffer, sizeof (error_buffer), gettext(
1247 "unable to determine disk group name for %s"), path);
1248 dsw_error(error_buffer, NULL);
1250 if (strcmp(dgname, "") == 0)
1251 return (0);
1254 * See if disk group is local to this node
1256 check_dg_is_local(dgname);
1259 * Copy dgname into result
1261 (void) strcpy(result, dgname);
1262 return (1);
1266 * sigterm (): traps specified signal , usually termination one
1268 void
1269 sigterm(int sig)
1271 spcs_log("ii", NULL, gettext("%s received signal %d"), cmdnam, sig);
1272 exit(1);
1276 * sigchild; reap child and collect status.
1279 volatile pid_t dead_child;
1280 int dead_stat;
1282 /*ARGSUSED*/
1283 void
1284 sigchild(int sig)
1286 dead_child = wait(&dead_stat);
1290 * InitEnv(): initializes environment
1292 void
1293 InitEnv()
1295 (void) setlocale(LC_ALL, "");
1296 (void) textdomain(DSW_TEXT_DOMAIN);
1298 #ifndef DEBUG
1299 (void) sigset(SIGHUP, sigterm);
1300 (void) sigset(SIGINT, sigterm);
1301 (void) sigset(SIGQUIT, sigterm);
1302 (void) sigset(SIGILL, sigterm);
1303 (void) sigset(SIGEMT, sigterm);
1304 (void) sigset(SIGABRT, sigterm);
1305 (void) sigset(SIGFPE, sigterm);
1306 (void) sigset(SIGBUS, sigterm);
1307 (void) sigset(SIGSEGV, sigterm);
1308 (void) sigset(SIGTERM, sigterm);
1309 (void) sigset(SIGPWR, sigterm);
1310 (void) sigset(SIGSTOP, sigterm);
1311 (void) sigset(SIGTSTP, sigterm);
1312 #endif
1314 dsw_fd = open(DSWDEV, O_RDONLY);
1315 if (dsw_fd < 0) {
1316 perror(DSWDEV);
1317 exit(1);
1320 (void) setsid();
1324 * print an error message, followed by decoded errno then exit.
1326 void
1327 dsw_error(char *str, spcs_s_info_t *status)
1329 char *sp;
1331 (void) fprintf(stderr, "%s: %s:\n", cmdnam, str);
1332 if (status == NULL) {
1333 /* deflect ESRCH */
1334 if (ESRCH == errno) {
1335 sp = "Set/volume not found";
1336 } else {
1337 sp = strerror(errno);
1339 (void) fprintf(stderr, "%s\n", sp ? sp : "");
1340 } else {
1341 spcs_s_report(*status, stderr);
1342 spcs_s_ufree(status);
1344 if (cfg)
1345 cfg_close(cfg);
1346 exit(2);
1350 #undef size
1352 void
1353 free_bitmap(unsigned char *bitmap)
1355 free(bitmap);
1360 get_bitmap(master_volume, shd_bitmap, copy_bitmap, size)
1361 char *master_volume;
1362 unsigned char *shd_bitmap;
1363 unsigned char *copy_bitmap;
1364 unsigned long size;
1366 dsw_bitmap_t parms;
1368 (void) strlcpy(parms.shadow_vol, master_volume, DSW_NAMELEN);
1369 parms.shd_bitmap = shd_bitmap;
1370 parms.shd_size = size;
1371 parms.copy_bitmap = copy_bitmap;
1372 parms.copy_size = size;
1374 return (do_ioctl(dsw_fd, DSWIOC_BITMAP, &parms));
1377 unsigned char *
1378 allocate_bitmap(char *shadow_volume)
1380 unsigned char *shd_bitmap;
1381 unsigned char *copy_bitmap;
1382 unsigned char *p;
1383 unsigned char *q;
1384 int i;
1385 dsw_stat_t args;
1386 int stat_flags;
1388 (void) strlcpy(args.shadow_vol, shadow_volume, DSW_NAMELEN);
1390 args.status = spcs_s_ucreate();
1391 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1)
1392 dsw_error(gettext("Stat failed"), &args.status);
1394 stat_flags = args.stat;
1395 if (stat_flags & DSW_BMPOFFLINE)
1396 return (NULL);
1398 bm_size = args.size;
1399 bm_size = (bm_size + DSW_SIZE-1) / DSW_SIZE;
1400 bm_actual = bm_size;
1401 bm_size = (bm_size + DSW_BITS-1) / DSW_BITS;
1402 spcs_s_ufree(&args.status);
1404 p = shd_bitmap = (unsigned char *) malloc(bm_size);
1405 if (!shd_bitmap) {
1406 perror(gettext("malloc bitmap"));
1407 return (NULL);
1410 q = copy_bitmap = (unsigned char *) malloc(bm_size);
1411 if (!copy_bitmap) {
1412 perror(gettext("malloc bitmap"));
1413 free(shd_bitmap);
1414 return (NULL);
1417 (void) memset(shd_bitmap, 0, bm_size);
1418 (void) memset(copy_bitmap, 0, bm_size);
1420 if (get_bitmap(shadow_volume, shd_bitmap, copy_bitmap, bm_size) < 0) {
1421 free(copy_bitmap);
1422 free(shd_bitmap);
1423 return (NULL);
1427 * "or" the copy and shadow bitmaps together to return a composite
1428 * bitmap that contains the total set of differences between the
1429 * volumes.
1431 for (i = bm_size; i-- > 0; /*CSTYLED*/)
1432 *p++ |= *q++;
1434 free(copy_bitmap);
1436 return (shd_bitmap);
1440 * print usage message and exit.
1442 void
1443 usage(char *why)
1445 if (why) {
1446 (void) fprintf(stderr, "%s: %s\n", cmdnam, why);
1448 (void) fprintf(stderr, "%s\n",
1449 gettext("\nBrief summary:"));
1450 (void) fprintf(stderr, "%s\n",
1451 gettext("\t-e {ind|dep} master_vol shadow_vol "
1452 "bitmap_vol"));
1453 (void) fprintf(stderr, "%s\n",
1454 gettext("\t-[cu {s|m}] volume_set"));
1455 (void) fprintf(stderr, "%s\n",
1456 gettext("\t-i all"));
1457 (void) fprintf(stderr, "%s\n",
1458 gettext("\t-[adDEilPRw] volume_set"));
1459 (void) fprintf(stderr, "%s\n",
1460 gettext("\t-g group_name [options]"));
1461 (void) fprintf(stderr, "%s\n",
1462 gettext("\t-C cluster_tag [options]"));
1463 (void) fprintf(stderr, "%s\n",
1464 gettext("\t-[hilLv]"));
1465 (void) fprintf(stderr, "%s\n",
1466 gettext("\t-[IJ] volume_set bitmap"));
1467 (void) fprintf(stderr, "%s\n",
1468 gettext("\t-A overflow_vol volume_set"));
1469 (void) fprintf(stderr, "%s\n",
1470 gettext("\t-[OQ] overflow_vol"));
1471 (void) fprintf(stderr, "%s\n",
1472 gettext("\t-P {delay} {units} volume_set"));
1474 /* assume we came here due to a user mistake */
1475 exit(1);
1476 /* NOTREACHED */
1477 } else {
1479 (void) fprintf(stdout, "%s\n",
1480 gettext("Point-in-Time Copy Administrator CLI options"));
1481 (void) fprintf(stdout, "%s\n",
1482 gettext("Usage summary:"));
1483 (void) fprintf(stdout, "%s\n",
1484 gettext("\t-e ind m s b\tenable independent master shadow "
1485 "bitmap"));
1486 (void) fprintf(stdout, "%s\n",
1487 gettext("\t-e dep m s b\tenable dependent master shadow "
1488 "bitmap"));
1489 if (check_cluster() == II_CLUSTER)
1490 (void) fprintf(stdout, "%s\n",
1491 gettext("\t-ne ind m s b\tenable exportable master "
1492 "shadow bitmap"));
1493 (void) fprintf(stdout, "%s\n",
1494 gettext("\t-d v\t\tdisable volume"));
1495 (void) fprintf(stdout, "%s\n",
1496 gettext("\t-u s v\t\tupdate shadow volume"));
1497 (void) fprintf(stdout, "%s\n",
1498 gettext("\t-u m v\t\tupdate master volume"));
1499 (void) fprintf(stdout, "%s\n",
1500 gettext("\t-c s v\t\tcopy to shadow volume"));
1501 (void) fprintf(stdout, "%s\n",
1502 gettext("\t-c m v\t\tcopy to master volume"));
1503 (void) fprintf(stdout, "%s\n",
1504 gettext("\t-a v\t\tabort copy volume"));
1505 (void) fprintf(stdout, "%s\n",
1506 gettext("\t-w v\t\twait volume"));
1507 (void) fprintf(stdout, "%s\n",
1508 gettext("\t-i v\t\tdisplay volume status"));
1509 (void) fprintf(stdout, "%s\n",
1510 gettext("\t-i all\t\tdisplay all volume status"));
1511 (void) fprintf(stdout, "%s\n",
1512 gettext("\t-l\t\tlist all volumes"));
1513 (void) fprintf(stdout, "%s\n",
1514 gettext("\t-R v\t\treset volume"));
1515 (void) fprintf(stdout, "%s\n",
1516 gettext("\t-A o v\t\tattach overflow to volume"));
1517 (void) fprintf(stdout, "%s\n",
1518 gettext("\t-D v\t\tdetach overflow from volume"));
1519 (void) fprintf(stdout, "%s\n",
1520 gettext("\t-L\t\tlist all overflow volumes"));
1521 (void) fprintf(stdout, "%s\n",
1522 gettext("\t-O o\t\tinitialize overflow"));
1523 (void) fprintf(stdout, "%s\n",
1524 gettext("\t-Q o\t\tquery status of overflow"));
1525 (void) fprintf(stdout, "%s\n",
1526 gettext("\t-E v\t\texport shadow volume"));
1527 (void) fprintf(stdout, "%s\n",
1528 gettext("\t-I v b\t\timport volume bitmap"));
1529 (void) fprintf(stdout, "%s\n",
1530 gettext("\t-J v b\t\tjoin volume bitmap"));
1531 (void) fprintf(stdout, "%s\n",
1532 gettext("\t-P d u v\tset copy delay/units for volume"));
1533 (void) fprintf(stdout, "%s\n",
1534 gettext("\t-P v\t\tget copy delay/units for volume"));
1535 (void) fprintf(stdout, "%s\n",
1536 gettext("\t-C tag\t\tcluster resource tag"));
1537 #ifdef DEBUG
1538 (void) fprintf(stdout, "%s\n",
1539 gettext("\t-b v\t\tdisplay bitmap volume"));
1540 (void) fprintf(stdout, "%s\n",
1541 gettext("\t-f f\t\tuse private configuration file"));
1542 #endif
1543 (void) fprintf(stdout, "%s\n",
1544 gettext("\t-v\t\tprint software versions"));
1545 (void) fprintf(stdout, "%s\n",
1546 gettext("\t-n\t\tperform action without question"));
1547 (void) fprintf(stdout, "%s\n",
1548 gettext("\t-p [-c|-u] {m|s}"
1549 "enable PID locking on copy or update"));
1550 (void) fprintf(stdout, "%s\n",
1551 gettext("\t-p -w v\t\tdisable PID locking"));
1552 (void) fprintf(stdout, "%s\n",
1553 gettext("\t-h\t\tiiadm usage summary"));
1554 (void) fprintf(stdout, "%s\n",
1555 gettext("\nUsage summary for options that support "
1556 "grouping (-g g):"));
1557 (void) fprintf(stdout, "%s\n",
1558 gettext("\t-g g -e ind m s b group enable independent "
1559 "master shadow bitmap"));
1560 (void) fprintf(stdout, "%s\n",
1561 gettext("\t-g g -e dep m s b group enable dependent "
1562 "master shadow bitmap"));
1563 (void) fprintf(stdout, "%s\n",
1564 gettext("\t-g g -d\t\tdisable group"));
1565 (void) fprintf(stdout, "%s\n",
1566 gettext("\t-g g -u s\tupdate shadow for all volumes in "
1567 "group"));
1568 (void) fprintf(stdout, "%s\n",
1569 gettext("\t-g g -u m\tupdate master for all volumes in "
1570 "group"));
1571 (void) fprintf(stdout, "%s\n",
1572 gettext("\t-g g -c s\tcopy to shadow for all volumes in "
1573 "group"));
1574 (void) fprintf(stdout, "%s\n",
1575 gettext("\t-g g -c m\tcopy to master for all volumes in "
1576 "group"));
1577 (void) fprintf(stdout, "%s\n",
1578 gettext("\t-g g -a\t\tabort copy for all volumes in "
1579 "group"));
1580 (void) fprintf(stdout, "%s\n",
1581 gettext("\t-g g -w\t\twait for all volumes in group"));
1582 (void) fprintf(stdout, "%s\n",
1583 gettext("\t-g g -i\t\tdisplay status of all volumes in "
1584 "group"));
1585 (void) fprintf(stdout, "%s\n",
1586 gettext("\t-g g -l\t\tlist all volumes in group"));
1587 (void) fprintf(stdout, "%s\n",
1588 gettext("\t-g -L\t\tlist all groups"));
1589 (void) fprintf(stdout, "%s\n",
1590 gettext("\t-g g -m v v\tmove one or more volumes into "
1591 "group"));
1592 (void) fprintf(stdout, "%s\n",
1593 gettext("\t-g \"\" -m v\tremove volume from group"));
1594 (void) fprintf(stdout, "%s\n",
1595 gettext("\t-g g -R\t\treset all volumes in group"));
1596 (void) fprintf(stdout, "%s\n",
1597 gettext("\t-g g -A o\tattach overflow to all volumes in "
1598 "group"));
1599 (void) fprintf(stdout, "%s\n",
1600 gettext("\t-g g -D\t\tdetach overflow from all volumes in "
1601 "group"));
1602 (void) fprintf(stdout, "%s\n",
1603 gettext("\t-g g -E\t\texport shadow volume for all "
1604 "volumes in group"));
1605 (void) fprintf(stdout, "%s\n",
1606 gettext("\t-g g -P d u\tset copy delay/units for all "
1607 "volumes in group"));
1608 (void) fprintf(stdout, "%s\n",
1609 gettext("\t-g g -P\t\tget copy delay/units for all "
1610 "volumes in group"));
1611 (void) fprintf(stdout, "%s\n",
1612 gettext("\nLegend summary:"));
1613 (void) fprintf(stdout, "%s\n",
1614 gettext("\tind\t\tindependent volume set"));
1615 (void) fprintf(stdout, "%s\n",
1616 gettext("\tdep\t\tdependent volume set"));
1617 (void) fprintf(stdout, "%s\n",
1618 gettext("\tall\t\tall configured volumes"));
1619 (void) fprintf(stdout, "%s\n",
1620 gettext("\tm\t\tmaster volume"));
1621 (void) fprintf(stdout, "%s\n",
1622 gettext("\ts\t\tshadow volume"));
1623 (void) fprintf(stdout, "%s\n",
1624 gettext("\tv\t\tshadow volume (reference name)"));
1625 (void) fprintf(stdout, "%s\n",
1626 gettext("\to\t\toverflow volume"));
1627 (void) fprintf(stdout, "%s\n",
1628 gettext("\tb\t\tbitmap volume"));
1629 #ifdef DEBUG
1630 (void) fprintf(stdout, "%s\n",
1631 gettext("\tf\t\tconfiguration file name"));
1632 #endif
1633 (void) fprintf(stdout, "%s\n",
1634 gettext("\td\t\tdelay tick interval"));
1635 (void) fprintf(stdout, "%s\n",
1636 gettext("\tu\t\tunit size"));
1637 (void) fprintf(stdout, "%s\n",
1638 gettext("\tg\t\tgroup name"));
1640 /* assume we came here because user request help text */
1641 exit(0);
1642 /* NOTREACHED */
1647 static char yeschr[MAX_LINE_SIZE + 2];
1648 static char nochr[MAX_LINE_SIZE + 2];
1650 static int
1651 yes(void)
1653 int i, b;
1654 char ans[MAX_LINE_SIZE + 1];
1656 for (i = 0; /*CSTYLED*/; i++) {
1657 b = getchar();
1658 if (b == '\n' || b == '\0' || b == EOF) {
1659 if (i < MAX_LINE_SIZE)
1660 ans[i] = 0;
1661 break;
1663 if (i < MAX_LINE_SIZE)
1664 ans[i] = b;
1666 if (i >= MAX_LINE_SIZE) {
1667 i = MAX_LINE_SIZE;
1668 ans[MAX_LINE_SIZE] = 0;
1670 if ((i == 0) || (strncmp(yeschr, ans, i))) {
1671 if (strncmp(nochr, ans, i) == 0)
1672 return (0);
1673 else if (strncmp(yeschr, ans, i) == 0)
1674 return (1);
1675 else {
1676 (void) fprintf(stderr, "%s %s/%s\n",
1677 gettext("You have to respond with"),
1678 yeschr, nochr);
1679 return (2);
1682 return (1);
1685 static int
1686 convert_int(char *str)
1688 int result, rc;
1689 char *buf;
1691 buf = (char *)calloc(strlen(str) + 256, sizeof (char));
1692 rc = sscanf(str, "%d%s", &result, buf);
1694 if (rc != 1) {
1695 (void) sprintf(buf, gettext("'%s' is not a valid number"), str);
1696 /* dsw_error calls exit which frees 'buf' */
1697 errno = EINVAL;
1698 dsw_error(buf, NULL);
1700 free(buf);
1702 return (result);
1705 void
1706 check_action(char *will_happen)
1708 int answer;
1710 if (nflg || !isatty(fileno(stdin)))
1711 return;
1712 (void) strncpy(yeschr, nl_langinfo(YESSTR), MAX_LINE_SIZE + 1);
1713 (void) strncpy(nochr, nl_langinfo(NOSTR), MAX_LINE_SIZE + 1);
1715 /*CONSTCOND*/
1716 while (1) {
1717 (void) printf("%s %s/%s ", will_happen, yeschr, nochr);
1718 answer = yes();
1719 if (answer == 1 || answer == 0)
1720 break;
1722 if (answer == 1)
1723 return;
1724 exit(1);
1727 enum child_event {Status, CopyStart};
1730 * Wait for child process to get to some state, where some state may be:
1732 * Status Set up the shadow enough so that it responds
1733 * to status requests.
1734 * CopyStart Start copy/update operations.
1738 child_wait(pid_t child, enum child_event event, char *volume)
1740 dsw_stat_t args;
1741 int rc;
1743 (void) strlcpy(args.shadow_vol, volume, DSW_NAMELEN);
1745 for (; dead_child != child; (void) sleep(1)) {
1747 /* poll shadow group with a status ioctl() */
1748 args.status = spcs_s_ucreate();
1749 errno = 0;
1750 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &args);
1752 spcs_s_ufree(&args.status);
1754 if (event == Status) {
1755 /* keep polling while we fail with DSW_ENOTFOUND */
1756 if (rc != -1 || errno != DSW_ENOTFOUND)
1757 return (0);
1758 } else {
1759 /* event == CopyStart */
1760 if (rc == -1) {
1761 return (1); /* something wrong */
1763 if (args.stat & DSW_COPYINGP)
1764 return (0); /* copying underway */
1767 /* child died */
1768 if (WIFEXITED(dead_stat))
1769 return (WEXITSTATUS(dead_stat));
1770 else
1771 return (1);
1775 mounted(char *t)
1777 int rdsk;
1778 int i;
1779 FILE *mntfp;
1780 struct mnttab mntref;
1781 struct mnttab mntent;
1782 char target[DSW_NAMELEN];
1783 char *s;
1785 rdsk = i = 0;
1786 for (s = target; i < DSW_NAMELEN && (*s = *t++); i++) {
1787 if (*s == 'r' && rdsk == 0)
1788 rdsk = 1;
1789 else
1790 s++;
1792 *s = '\0';
1794 mntref.mnt_special = target;
1795 mntref.mnt_mountp = NULL;
1796 mntref.mnt_fstype = NULL;
1797 mntref.mnt_mntopts = NULL;
1798 mntref.mnt_time = NULL;
1800 if ((mntfp = fopen("/etc/mnttab", "r")) == NULL) {
1801 dsw_error(gettext("Can not check volume against mount table"),
1802 NULL);
1804 if (getmntany(mntfp, &mntent, &mntref) != -1) {
1805 /* found something before EOF */
1806 (void) fclose(mntfp);
1807 return (1);
1809 (void) fclose(mntfp);
1810 return (0);
1813 void
1814 enable(char *master_volume, char *shadow_volume,
1815 char *bitmap_volume, char *copy_type)
1817 dsw_config_t parms;
1818 dsw_ioctl_t temp;
1819 char *p;
1820 int rc;
1821 pid_t child;
1822 spcs_s_info_t *sp_info;
1823 struct stat mstat, sstat, bstat;
1824 char mst_dg[DSW_NAMELEN] = {0};
1825 char shd_dg[DSW_NAMELEN] = {0};
1826 char bmp_dg[DSW_NAMELEN] = {0};
1827 int mvol_enabled;
1828 char *altname;
1829 grptag_t *gdata;
1831 bzero(&parms, sizeof (dsw_config_t));
1833 if (strcmp(copy_type, "independent") == 0 ||
1834 strcmp(copy_type, gettext("independent")) == 0)
1835 parms.flag = DSW_GOLDEN;
1836 else if (strcmp(copy_type, "dependent") == 0 ||
1837 strcmp(copy_type, gettext("dependent")) == 0)
1838 parms.flag = 0;
1839 else
1840 dsw_error(gettext("don't understand shadow type"), NULL);
1842 /* validate volume names */
1843 if (perform_autosv()) {
1844 if (cfg_load_svols(cfg) < 0 || cfg_load_dsvols(cfg) < 0 ||
1845 cfg_load_shadows(cfg) < 0) {
1846 dsw_error(gettext("Unable to parse config file"), NULL);
1848 load_ii_vols(cfg);
1849 reload_vols = LD_SVOLS | LD_DSVOLS | LD_SHADOWS | LD_II;
1851 /* see if it's been used before under a different name */
1852 conform_name(&master_volume);
1853 conform_name(&shadow_volume);
1854 rc = cfg_get_canonical_name(cfg, bitmap_volume, &altname);
1855 if (rc < 0) {
1856 dsw_error(gettext("Unable to parse config file"), NULL);
1858 if (rc) {
1859 errno = EBUSY;
1860 dsw_error(gettext("Bitmap in use"), NULL);
1865 * If not local, determine disk group names for volumes in II set
1867 switch (check_cluster()) {
1868 case II_CLUSTER:
1870 * Check if none or all volumes are in a disk group
1872 rc = 0;
1873 if (check_diskgroup(master_volume, mst_dg)) rc++;
1874 if (check_diskgroup(shadow_volume, shd_dg)) rc++;
1875 if (check_diskgroup(bitmap_volume, bmp_dg)) rc++;
1876 if ((rc != 0) && (rc != 3))
1877 dsw_error(gettext(
1878 "Not all Point-in-Time Copy volumes are "
1879 "in a disk group"), NULL);
1882 * If volumes are not in a disk group, but are in a
1883 * cluster, then "-C <tag>", must be set
1885 if (rc == 0 && cfg_cluster_tag == NULL)
1886 dsw_error(gettext(
1887 "Point-in-Time Copy volumes, that are not "
1888 "in a device group which has been "
1889 "registered with SunCluster, "
1890 "require usage of \"-C\""), NULL);
1893 * the same disk group
1894 * If -n, plus mst_dg==bmp_dg, then allow E/I/J in SunCluster
1896 if ((strcmp(mst_dg, bmp_dg)) ||
1897 (strcmp(mst_dg, shd_dg) && (!nflg)))
1898 dsw_error(gettext(
1899 "Volumes are not in same disk group"), NULL);
1902 * Can never enable the same shadow twice, regardless of
1903 * exportable shadow device group movement
1905 if (find_shadow_line(shadow_volume))
1906 dsw_error(gettext(
1907 "Shadow volume is already configured"), NULL);
1910 * Groups cannot span multiple clusters
1912 if (group_name && perform_autosv()) {
1913 gdata = (grptag_t *)nsc_lookup(volhash, group_name);
1914 if (gdata &&
1915 strncmp(gdata->ctag, mst_dg, DSW_NAMELEN) != 0) {
1916 errno = EINVAL;
1917 dsw_error(gettext("Group contains sets not "
1918 "in the same cluster resource"), NULL);
1923 * Check cluster tag and bitmap disk group
1924 * set latter if different
1926 if (check_resource_group(bitmap_volume)) {
1928 * Unload and reload in the event cluster tag has
1929 * changed
1931 if (perform_autosv()) {
1932 unload_ii_vols();
1933 cfg_unload_shadows();
1934 cfg_unload_dsvols();
1935 cfg_unload_svols();
1936 if (cfg_load_svols(cfg) < 0 ||
1937 cfg_load_dsvols(cfg) < 0 ||
1938 cfg_load_shadows(cfg) < 0) {
1939 dsw_error(gettext(
1940 "Unable to parse config "
1941 "file"), NULL);
1943 load_ii_vols(cfg);
1947 * Copy cluster name into config
1949 (void) strncpy(parms.cluster_tag, cfg_cluster_tag, DSW_NAMELEN);
1950 break;
1952 case II_CLUSTER_LCL:
1953 /* ensure that the -C local won't interfere with the set */
1954 if (group_name && perform_autosv()) {
1955 gdata = (grptag_t *)nsc_lookup(volhash, group_name);
1956 if (gdata) {
1957 if (strlen(gdata->ctag) != 0) {
1958 errno = EINVAL;
1959 dsw_error(gettext("Unable to put set "
1960 "into -C local and specified "
1961 "group"), NULL);
1965 break;
1969 * If we've got a group name, add it into the config
1971 if (group_name) {
1972 (void) strncpy(parms.group_name, group_name, DSW_NAMELEN);
1976 * Determine accessability of volumes
1978 if (stat(master_volume, &mstat) != 0)
1979 dsw_error(gettext(
1980 "Unable to access master volume"), NULL);
1981 if (!S_ISCHR(mstat.st_mode))
1982 dsw_error(gettext(
1983 "Master volume is not a character device"), NULL);
1984 /* check the shadow_vol hasn't be used as SNDR secondary vol */
1985 check_iishadow(shadow_volume);
1986 if (stat(shadow_volume, &sstat) != 0)
1987 dsw_error(gettext(
1988 "Unable to access shadow volume"), NULL);
1989 if (!S_ISCHR(sstat.st_mode))
1990 dsw_error(gettext(
1991 "Shadow volume is not a character device"), NULL);
1992 if (mounted(shadow_volume)) {
1993 errno = EBUSY;
1994 dsw_error(gettext(
1995 "Shadow volume is mounted, unmount it first"), NULL);
1997 if (mstat.st_rdev == sstat.st_rdev) {
1998 errno = EINVAL;
1999 dsw_error(gettext(
2000 "Master and shadow are the same device"), NULL);
2002 if (stat(bitmap_volume, &bstat) != 0) {
2003 dsw_error(gettext("Unable to access bitmap"), NULL);
2005 if (!S_ISCHR(bstat.st_mode))
2006 dsw_error(gettext(
2007 "Bitmap volume is not a character device"), NULL);
2008 if (S_ISCHR(bstat.st_mode)) {
2009 if (mstat.st_rdev == bstat.st_rdev) {
2010 errno = EINVAL;
2011 dsw_error(gettext(
2012 "Master and bitmap are the same device"), NULL);
2013 } else if (sstat.st_rdev == bstat.st_rdev) {
2014 errno = EINVAL;
2015 dsw_error(gettext(
2016 "Shadow and bitmap are the same device"), NULL);
2020 (void) strncpy(parms.master_vol, master_volume, DSW_NAMELEN);
2021 (void) strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
2022 (void) strncpy(parms.bitmap_vol, bitmap_volume, DSW_NAMELEN);
2023 errno = 0;
2024 parms.status = spcs_s_ucreate();
2027 * Check that none of the member volumes forms part of another
2028 * InstantImage group.
2030 * -- this check has been removed; it is done in the kernel instead
2031 * -- PJW
2035 * Check against overflow volumes
2037 for (p = get_overflow_list(); *p != NULL; p += DSW_NAMELEN) {
2038 if (strncmp(master_volume, p, DSW_NAMELEN) == 0)
2039 dsw_error(gettext(
2040 "Master volume is already an overflow volume"),
2041 NULL);
2042 else if (strncmp(shadow_volume, p, DSW_NAMELEN) == 0)
2043 dsw_error(gettext(
2044 "Shadow volume is already an overflow volume"),
2045 NULL);
2046 else if (strncmp(bitmap_volume, p, DSW_NAMELEN) == 0)
2047 dsw_error(gettext(
2048 "Bitmap volume is already an overflow volume"),
2049 NULL);
2053 * Make sure that the shadow volume is not already configured
2055 if (find_shadow_config(shadow_volume, NULL, &temp))
2056 dsw_error(gettext(
2057 "Shadow volume is already configured"), NULL);
2058 if (perform_autosv()) {
2060 * parse the dsvol entries to see if we need to place
2061 * the master or shadow under SV control
2063 if (nsc_lookup(volhash, master_volume) == NULL) {
2064 if (cfg_vol_enable(cfg, master_volume, cfg_cluster_tag,
2065 "ii") < 0) {
2066 dsw_error(
2067 gettext("Cannot enable master volume"),
2068 NULL);
2070 mvol_enabled = 1;
2071 } else {
2072 mvol_enabled = 0;
2074 if (nsc_lookup(volhash, shadow_volume) == NULL) {
2075 if (nflg) {
2076 cfg_resource(cfg, shd_dg);
2077 rc = cfg_vol_enable(cfg, shadow_volume,
2078 shd_dg, "ii");
2079 cfg_resource(cfg, cfg_cluster_tag);
2080 } else {
2081 rc = cfg_vol_enable(cfg, shadow_volume,
2082 cfg_cluster_tag, "ii");
2084 if (rc < 0) {
2085 if (mvol_enabled) {
2086 if (cfg_vol_disable(cfg,
2087 master_volume, cfg_cluster_tag,
2088 "ii") < 0)
2089 dsw_error(gettext(
2090 "SV disable of master "
2091 "failed"),
2092 NULL);
2094 dsw_error(
2095 gettext("Cannot enable shadow volume"),
2096 NULL);
2099 unload_ii_vols();
2100 cfg_unload_shadows();
2101 cfg_unload_dsvols();
2102 cfg_unload_svols();
2103 reload_vols = 0;
2106 add_cfg_entry(&parms);
2107 cfg_unlock(cfg);
2108 config_locked = 0;
2110 (void) sigset(SIGCHLD, sigchild);
2111 switch (child = fork()) {
2113 case (pid_t)-1:
2114 dsw_error(gettext("Unable to fork"), NULL);
2115 break;
2117 case 0:
2118 rc = do_ioctl(dsw_fd, DSWIOC_ENABLE, &parms);
2119 if (rc == -1 && errno != DSW_EABORTED && errno != DSW_EIO) {
2121 * Failed to enable shadow group, log problem and remove
2122 * the shadow group from the config file.
2124 spcs_log("ii", &parms.status,
2125 gettext("Enable failed %s %s %s (%s)"),
2126 master_volume, shadow_volume, bitmap_volume,
2127 parms.flag & DSW_GOLDEN ?
2128 "independent" : "dependent");
2130 if (!ii_lock(cfg, CFG_WRLOCK) ||
2131 !find_shadow_config(shadow_volume, NULL, &temp)) {
2132 dsw_error(gettext(
2133 "Enable failed, can't tidy up cfg"),
2134 &parms.status);
2136 config_locked = 1;
2137 remove_iiset(setnumber, shadow_volume, 0);
2138 dsw_error(gettext("Enable failed"), &parms.status);
2141 if (rc == -1)
2142 sp_info = &parms.status;
2143 else
2144 sp_info = NULL;
2145 spcs_log("ii", sp_info, gettext("Enabled %s %s %s (%s)"),
2146 master_volume, shadow_volume, bitmap_volume,
2147 parms.flag & DSW_GOLDEN ? "independent" : "dependent");
2148 spcs_s_ufree(&parms.status);
2149 break;
2151 default:
2152 exit(child_wait(child, Status, shadow_volume));
2153 break;
2158 reset(char *volume)
2160 dsw_ioctl_t args;
2161 dsw_config_t parms;
2162 int rc;
2163 int wait_loc;
2164 pid_t child = (pid_t)0;
2165 enum copy_wait wait_action;
2166 spcs_s_info_t *stat;
2167 dsw_stat_t prev_stat;
2168 int stat_flags;
2169 static int unlocked = 0;
2170 int do_enable = 0;
2171 char key[CFG_MAX_KEY];
2172 char optval[CFG_MAX_BUF];
2173 unsigned int flags;
2175 wait_action = WaitForStart;
2177 if (unlocked && !ii_lock(cfg, CFG_RDLOCK)) {
2178 dsw_error(gettext("Unable to set locking on the configuration"),
2179 NULL);
2181 config_locked = 1;
2182 if (!find_shadow_config(volume, &parms, &args))
2183 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2184 "group"), NULL);
2186 cfg_unlock(cfg);
2187 config_locked = 0;
2188 unlocked = 1;
2190 spcs_log("ii", NULL, gettext("Start reset %s"), volume);
2191 (void) strlcpy(prev_stat.shadow_vol, volume, DSW_NAMELEN);
2192 prev_stat.status = spcs_s_ucreate();
2193 if (do_ioctl(dsw_fd, DSWIOC_STAT, &prev_stat) == -1) {
2194 /* set is suspended, so we do the enable processing instead */
2195 do_enable = 1;
2197 /* first check to see whether the set was offline */
2198 (void) snprintf(key, CFG_MAX_KEY, "ii.set%d.options",
2199 setnumber);
2200 if (!ii_lock(cfg, CFG_RDLOCK)) {
2201 dsw_error(gettext("Unable to set locking on the "
2202 "configuration"), NULL);
2204 config_locked = 1;
2205 unlocked = 0;
2206 if (cfg_get_single_option(cfg, CFG_SEC_CONF, key,
2207 NSKERN_II_BMP_OPTION, optval, CFG_MAX_BUF) < 0) {
2208 dsw_error(gettext("unable to read config file"), NULL);
2210 cfg_unlock(cfg);
2211 config_locked = 0;
2212 unlocked = 1;
2213 (void) sscanf(optval, "%x", &flags);
2214 if ((flags & DSW_OFFLINE) == 0) {
2215 /* set wasn't offline - don't reset */
2216 dsw_error(gettext("Set not offline, will not reset"),
2217 NULL);
2219 parms.status = spcs_s_ucreate();
2220 stat = &parms.status;
2221 stat_flags = DSW_BMPOFFLINE;
2222 } else {
2223 args.status = spcs_s_ucreate();
2224 stat = &args.status;
2225 stat_flags = prev_stat.stat;
2227 spcs_s_ufree(&prev_stat.status);
2229 if (wait_action == WaitForStart)
2230 (void) sigset(SIGCHLD, sigchild);
2232 switch (child = fork()) {
2234 case (pid_t)-1:
2235 dsw_error(gettext("Unable to fork"), NULL);
2236 break;
2238 case 0:
2239 if (do_enable) {
2240 rc = do_ioctl(dsw_fd, DSWIOC_ENABLE, &parms);
2241 } else {
2242 rc = do_ioctl(dsw_fd, DSWIOC_RESET, &args);
2244 if (rc == -1 && errno != DSW_EABORTED && errno != DSW_EIO) {
2245 spcs_log("ii", stat, gettext("Fail reset %s"), volume);
2246 dsw_error(gettext("Reset shadow failed"), stat);
2248 /* last_overflow is set during find_shadow_config */
2249 if (strlen(last_overflow) > 0 &&
2250 (stat_flags & (DSW_SHDOFFLINE | DSW_BMPOFFLINE)) != 0) {
2251 /* reattach it */
2252 (void) strncpy(parms.bitmap_vol, last_overflow,
2253 DSW_NAMELEN);
2254 do_attach(&parms);
2256 spcs_log("ii", stat, gettext("Finish reset %s"), volume);
2257 spcs_s_ufree(stat);
2259 exit(0);
2260 break;
2261 default:
2262 if (wait_action == WaitForStart) {
2263 rc = child_wait(child, CopyStart, args.shadow_vol);
2264 } else { /* wait_action == WaitForEnd */
2265 wait_loc = 0;
2266 (void) wait(&wait_loc);
2267 if (WIFEXITED(wait_loc) && (WEXITSTATUS(wait_loc) == 0))
2268 rc = 0;
2269 else
2270 rc = -1;
2272 break;
2274 /* if successful, remove flags entry from options field */
2275 if (rc >= 0) {
2276 if (!ii_lock(cfg, CFG_WRLOCK)) {
2277 dsw_error(gettext("Unable to set locking on the "
2278 "configuration"), NULL);
2280 config_locked = 1;
2281 if (!find_shadow_config(volume, &parms, &args)) {
2282 dsw_error(gettext("Volume is not in a Point-in-Time "
2283 "Copy group"), NULL);
2285 (void) snprintf(key, CFG_MAX_KEY, "ii.set%d.options",
2286 setnumber);
2287 if (cfg_del_option(cfg, CFG_SEC_CONF, key, NSKERN_II_BMP_OPTION)
2288 < 0) {
2289 dsw_error(gettext("Update of config failed"), NULL);
2291 (void) cfg_commit(cfg);
2292 cfg_unlock(cfg);
2293 config_locked = 0;
2296 return (rc);
2300 overflow(char *volume)
2302 dsw_ioctl_t args;
2303 int rc;
2304 spcs_s_info_t *stat;
2306 check_action(gettext("Initialize this overflow volume?"));
2307 if (find_matching_cf_line(volume, NULL, &args))
2308 dsw_error(gettext("Volume is part of a Point-in-Time Copy "
2309 "group"), NULL);
2310 args.status = spcs_s_ucreate();
2311 (void) strncpy(args.shadow_vol, volume, DSW_NAMELEN);
2312 rc = do_ioctl(dsw_fd, DSWIOC_OCREAT, &args);
2313 if (rc == -1) {
2314 spcs_log("ii", &args.status,
2315 gettext("Create overflow failed %s"), volume);
2316 dsw_error(gettext("Create overflow failed"), &args.status);
2318 if (rc == -1)
2319 stat = &args.status;
2320 else
2321 stat = NULL;
2322 spcs_log("ii", stat, gettext("Create overflow succeeded %s"), volume);
2323 spcs_s_ufree(&args.status);
2325 return (0);
2328 void
2329 bitmap_op(char *master_volume, int print_bitmap, int bitmap_percent, int used,
2330 int is_compact)
2332 unsigned char *bitmap;
2333 char *name;
2334 int i, x, y;
2335 unsigned j;
2336 unsigned long n;
2337 unsigned long percent;
2339 bitmap = allocate_bitmap(master_volume);
2340 if (bitmap == NULL)
2341 return;
2343 if (bitmap_percent) {
2344 /* count the number of bits set in bitmap */
2345 for (i = n = 0; i < bm_size; i++)
2346 for (j = (unsigned)bitmap[i]; j; j &= j -1)
2347 n++;
2348 if (is_compact)
2349 (void) printf(gettext("Chunks in map: %d used: %d\n"),
2350 used, n);
2351 if (bm_actual < 100) {
2352 percent = 0;
2353 } else {
2354 percent = (n * 100) / bm_actual;
2356 (void) printf(gettext("Percent of bitmap set: %u\n"), percent);
2357 percent = percent/100;
2358 /* distinguish between 0.0000% and 0.n% of bitmap set */
2359 if (percent < 1)
2360 (void) printf("\t(%s)\n", n > 0 ?
2361 gettext("bitmap dirty") : gettext("bitmap clean"));
2364 if (print_bitmap) {
2365 name = strrchr(master_volume, '/');
2366 if (name++ == NULL)
2367 name = master_volume;
2368 i = bm_size * 8;
2369 x = (int)ceil(sqrt((double)i));
2370 x += (8 - (x % 8)); /* round up to nearest multiple of 8 */
2371 y = i / x;
2372 if (y * x < i)
2373 y++;
2374 (void) printf("#define bm%s_width %d\n#define bm%s_height %d\n",
2375 name, x, name, y);
2376 (void) printf("#define bm%s_x_hot 0\n#define bm%s_y_hot 0\n",
2377 name, name);
2378 (void) printf("static char bm%s_bits[] = {\n", name);
2379 for (i = 0; i < bm_size; i++) {
2380 if (i % 12 == 0)
2381 (void) printf("\n");
2382 (void) printf("0x%02x, ", bitmap[i]);
2384 y = x * y;
2385 for (; i < y; i++) {
2386 if (i % 12 == 0)
2387 (void) printf("\n");
2388 (void) printf("0x00, ");
2390 (void) printf("\n};\n");
2393 free_bitmap(bitmap);
2396 static int
2397 validate_group_names(char **vol_list, char *group)
2399 ENTRY item, *found;
2400 int i, rc, count;
2401 dsw_aioctl_t *group_list;
2402 char *ptr;
2404 if (group == NULL || *group == NULL) {
2405 /* no group set, just count volume list */
2406 for (i = 0; *vol_list++ != NULL; i++)
2408 return (i);
2411 if ((count = do_ioctl(dsw_fd, DSWIOC_LISTLEN, NULL)) < 0)
2412 dsw_error("DSWIOC_LISTLEN", NULL);
2414 group_list = malloc(sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
2415 if (group_list == NULL)
2416 dsw_error(gettext("Failed to allocate memory"), NULL);
2418 bzero(group_list, sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
2419 group_list->count = count;
2420 group_list->flags = 0;
2421 group_list->status = spcs_s_ucreate();
2422 (void) strncpy(group_list->shadow_vol, group, DSW_NAMELEN);
2424 rc = do_ioctl(dsw_fd, DSWIOC_GLIST, group_list);
2425 if (rc < 0)
2426 dsw_error(gettext("Group list access failure"),
2427 &group_list->status);
2429 group_list->shadow_vol[DSW_NAMELEN * group_list->count] = '\0';
2431 /* create hash and enter all volumes into it */
2432 if (hcreate(group_list->count) == 0)
2433 dsw_error(gettext("Failed to allocate memory"), NULL);
2434 ptr = group_list->shadow_vol;
2435 count = group_list->count;
2436 i = 0;
2437 while (i < count) {
2438 ptr[ DSW_NAMELEN - 1 ] = '\0';
2439 item.key = ptr;
2440 item.data = (void *) 0;
2441 (void) hsearch(item, ENTER);
2442 ++i;
2443 ptr += DSW_NAMELEN;
2446 /* now compare the volume list with the hash */
2447 for (i = 0; vol_list[ i ]; i++) {
2448 item.key = vol_list[ i ];
2449 found = hsearch(item, FIND);
2450 if (!found)
2451 dsw_error(gettext("Group config does not match kernel"),
2452 NULL);
2453 if (found->data != (void *) 0)
2454 dsw_error(gettext("Duplicate volume specified"), NULL);
2455 found->data = (void *) 1;
2457 if (i != count)
2458 dsw_error(gettext("Group config does not match kernel"), NULL);
2460 /* everything checks out */
2461 free(group_list);
2462 hdestroy();
2464 return (count);
2468 do_acopy(char **vol_list, enum copy_update update_mode,
2469 enum copy_direction direction)
2471 dsw_aioctl_t *acopy_args;
2472 dsw_ioctl_t copy_args;
2473 dsw_config_t parms;
2474 dsw_stat_t stat_s;
2475 int i;
2476 int rc;
2477 int n_vols;
2478 char *t;
2479 char buf[1024];
2480 char *sp;
2481 char *ppid;
2483 n_vols = validate_group_names(vol_list, group_name);
2485 acopy_args = calloc(sizeof (dsw_aioctl_t) + n_vols * DSW_NAMELEN, 1);
2486 if (acopy_args == NULL)
2487 dsw_error(gettext("Too many volumes given for update"), NULL);
2489 acopy_args->count = n_vols;
2491 acopy_args->flags = 0;
2493 if (update_mode == Update)
2494 acopy_args->flags |= CV_BMP_ONLY;
2495 if (direction == ToMaster)
2496 acopy_args->flags |= CV_SHD2MST;
2497 if (pflg) {
2498 acopy_args->flags |= CV_LOCK_PID;
2499 #ifdef DEBUG
2500 ppid = getenv("IIADM_PPID");
2501 if (ppid) {
2502 acopy_args->pid = atoi(ppid);
2503 (void) fprintf(stderr, "(using %s for ppid)\n", ppid);
2504 } else {
2505 acopy_args->pid = getppid();
2507 #else
2508 acopy_args->pid = getppid();
2509 #endif
2512 for (i = 0; i < n_vols; i++) {
2513 if (!find_shadow_config(vol_list[i], &parms, &copy_args))
2514 dsw_error(gettext("Volume is not in a Point-in-Time "
2515 "group"), NULL);
2516 if (direction == ToMaster) {
2517 t = parms.master_vol;
2518 } else {
2519 t = parms.shadow_vol;
2522 if (mounted(t)) {
2523 errno = EBUSY;
2524 dsw_error(gettext("Target of copy/update is mounted, "
2525 "unmount it first"), NULL);
2528 (void) strlcpy(stat_s.shadow_vol, parms.shadow_vol,
2529 DSW_NAMELEN);
2530 stat_s.status = spcs_s_ucreate();
2531 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &stat_s);
2532 spcs_s_ufree(&stat_s.status);
2533 if (rc == -1) {
2534 (void) sprintf(buf,
2535 gettext("Shadow group %s is suspended"),
2536 vol_list[i]);
2537 dsw_error(buf, NULL);
2540 if (stat_s.stat & DSW_COPYINGP) {
2541 (void) fprintf(stderr, "%s: %s\n", cmdnam,
2542 gettext("Copy already in progress"));
2543 exit(1);
2546 acopy_args->status = spcs_s_ucreate();
2547 for (i = 0; i < n_vols; i++) {
2548 spcs_log("ii", NULL, gettext("Atomic %s %s %s"),
2549 update_mode == Update ? gettext("update") : gettext("copy"),
2550 vol_list[i],
2551 direction == ToMaster ? gettext("from shadow") :
2552 gettext("to shadow"));
2554 if (group_name == NULL || *group_name == NULL) {
2555 sp = acopy_args->shadow_vol;
2556 for (i = 0; i < n_vols; i++, sp += DSW_NAMELEN)
2557 (void) strncpy(sp, vol_list[i], DSW_NAMELEN);
2558 } else {
2559 (void) strncpy(acopy_args->shadow_vol, group_name, DSW_NAMELEN);
2560 acopy_args->flags |= CV_IS_GROUP;
2562 rc = do_ioctl(dsw_fd, DSWIOC_ACOPY, acopy_args);
2563 if (rc == -1) {
2564 i = acopy_args->count;
2565 if (i < 0 || i >= n_vols) {
2566 spcs_log("ii", NULL, gettext("Atomic update failed"));
2567 (void) sprintf(buf, gettext("Update failed"));
2568 } else {
2569 spcs_log("ii", NULL,
2570 gettext("Atomic update of %s failed"),
2571 vol_list[acopy_args->count]);
2572 (void) sprintf(buf, gettext("Update of %s failed"),
2573 vol_list[acopy_args->count]);
2575 dsw_error(buf, &(acopy_args->status));
2577 return (rc);
2581 do_copy(char **vol_list, enum copy_update update_mode,
2582 enum copy_direction direction, enum copy_wait wait_action)
2584 dsw_ioctl_t copy_args;
2585 dsw_config_t parms;
2586 dsw_stat_t stat_s;
2587 int rc;
2588 int wait_loc;
2589 char *t;
2590 char *volume;
2591 pid_t child = (pid_t)0;
2592 char *ppid;
2594 if (vol_list[0] && vol_list[1])
2595 return (do_acopy(vol_list, update_mode, direction));
2597 volume = vol_list[0];
2598 if (!find_shadow_config(volume, &parms, &copy_args))
2599 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2600 "group"), NULL);
2602 cfg_unlock(cfg);
2603 config_locked = 0;
2604 copy_args.flags = 0;
2606 if (update_mode == Update)
2607 copy_args.flags |= CV_BMP_ONLY;
2608 if (direction == ToMaster) {
2609 copy_args.flags |= CV_SHD2MST;
2610 t = parms.master_vol;
2611 } else {
2612 t = parms.shadow_vol;
2614 if (pflg) {
2615 copy_args.flags |= CV_LOCK_PID;
2616 #ifdef DEBUG
2617 ppid = getenv("IIADM_PPID");
2618 if (ppid) {
2619 copy_args.pid = atoi(ppid);
2620 (void) fprintf(stderr, "(using %s for ppid)\n", ppid);
2621 } else {
2622 copy_args.pid = getppid();
2624 #else
2625 copy_args.pid = getppid();
2626 #endif
2629 if (mounted(t)) {
2630 errno = EBUSY;
2631 dsw_error(gettext("Target of copy/update is mounted, "
2632 "unmount it first"), NULL);
2635 (void) strlcpy(stat_s.shadow_vol, copy_args.shadow_vol, DSW_NAMELEN);
2636 stat_s.status = spcs_s_ucreate();
2637 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &stat_s);
2638 spcs_s_ufree(&stat_s.status);
2639 if (rc == -1)
2640 dsw_error(gettext("Shadow group suspended"), NULL);
2642 if (stat_s.stat & DSW_COPYINGP) {
2643 (void) fprintf(stderr, "%s: %s\n", cmdnam,
2644 gettext("Copy already in progress"));
2645 exit(1);
2648 copy_args.status = spcs_s_ucreate();
2649 spcs_log("ii", NULL, gettext("Start %s %s %s"),
2650 update_mode == Update ? gettext("update") : gettext("copy"),
2651 volume,
2652 direction == ToMaster ? gettext("from shadow") :
2653 gettext("to shadow"));
2655 if (wait_action == WaitForStart)
2656 (void) sigset(SIGCHLD, sigchild);
2657 switch (child = fork()) {
2659 case (pid_t)-1:
2660 dsw_error(gettext("Unable to fork"),
2661 NULL);
2662 break;
2664 case 0:
2665 rc = do_ioctl(dsw_fd, DSWIOC_COPY, &copy_args);
2666 if (rc == -1) {
2667 spcs_log("ii", &copy_args.status,
2668 gettext("Fail %s %s %s"),
2669 update_mode == Update ?
2670 gettext("update") : gettext("copy"),
2671 volume,
2672 direction == ToMaster ?
2673 gettext("from shadow") : gettext("to shadow"));
2674 dsw_error(gettext("Copy failed"), &copy_args.status);
2676 spcs_s_ufree(&copy_args.status);
2677 spcs_log("ii", NULL, gettext("Finish %s %s %s"),
2678 update_mode == Update ? gettext("update") : gettext("copy"),
2679 volume,
2680 direction == ToMaster ? gettext("from shadow") :
2681 gettext("to shadow"));
2683 exit(0);
2684 break;
2685 default:
2686 if (wait_action == WaitForStart) {
2687 rc = child_wait(child, CopyStart, copy_args.shadow_vol);
2688 } else { /* wait_action == WaitForEnd */
2689 wait_loc = 0;
2690 (void) wait(&wait_loc);
2691 if (WIFEXITED(wait_loc) && (WEXITSTATUS(wait_loc) == 0))
2692 rc = 0;
2693 else
2694 rc = 1;
2696 break;
2698 return (rc);
2701 void
2702 print_status(dsw_config_t *conf, int in_config)
2704 dsw_stat_t args;
2705 int stat_flags;
2706 static int need_sep = 0;
2707 time_t tmp_time;
2709 if (need_sep++ > 0)
2710 (void) printf("--------------------------------------"
2711 "----------------------------------------\n");
2712 (void) strlcpy(args.shadow_vol, conf->shadow_vol, DSW_NAMELEN);
2713 if (in_config) {
2714 (void) printf("%s: %s\n",
2715 conf->master_vol, gettext("(master volume)"));
2716 (void) printf("%s: %s\n",
2717 conf->shadow_vol, gettext("(shadow volume)"));
2718 (void) printf("%s: %s\n",
2719 conf->bitmap_vol, gettext("(bitmap volume)"));
2723 * Do special checking on the status of this volume in a Sun Cluster
2725 if (check_cluster() == II_CLUSTER) {
2726 char dgname[CFG_MAX_BUF], *other_node;
2728 if (cfg_dgname(conf->bitmap_vol, dgname, sizeof (dgname))) {
2729 if (strlen(dgname)) {
2730 int rc = cfg_dgname_islocal(dgname,
2731 &other_node);
2733 if (rc < 0) {
2734 (void) printf(gettext(
2735 "Suspended on this node, "
2736 "not active elsewhere\n"));
2737 return;
2738 } else if (rc == 0) {
2739 (void) printf(gettext(
2740 "Suspended on this node, "
2741 "active on %s\n"), other_node);
2742 return;
2748 args.status = spcs_s_ucreate();
2749 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) {
2751 /* Handle Not found or not in config */
2752 if (errno != DSW_ENOTFOUND || !in_config)
2753 dsw_error(gettext("Stat failed"), &args.status);
2755 /* Just suspend */
2756 (void) printf(gettext("Suspended.\n"));
2757 return;
2760 if (args.overflow_vol[0] != '\0')
2761 (void) printf("%s: %s\n", args.overflow_vol,
2762 gettext("(overflow volume)"));
2764 if (conf->group_name[0] != '\0')
2765 (void) printf(gettext("Group name: %s\n"),
2766 conf->group_name);
2768 if (conf->cluster_tag[0] != '\0')
2769 (void) printf(gettext("Cluster tag: %s\n"),
2770 conf->cluster_tag);
2772 stat_flags = args.stat;
2773 spcs_s_ufree(&args.status);
2774 if (stat_flags & DSW_GOLDEN)
2775 (void) printf(gettext("Independent copy"));
2776 else
2777 (void) printf(gettext("Dependent copy"));
2779 if (stat_flags & DSW_TREEMAP)
2780 (void) printf(gettext(", compacted shadow space"));
2782 if (stat_flags & DSW_COPYINGP)
2783 (void) printf(gettext(", copy in progress"));
2784 else if (stat_flags & DSW_COPYING)
2785 (void) printf(gettext(", copy not active"));
2787 if (stat_flags & DSW_COPYINGM)
2788 (void) printf(gettext(", copying master to shadow"));
2790 if (stat_flags & DSW_COPYINGS)
2791 (void) printf(gettext(", copying shadow to master"));
2793 if (stat_flags & DSW_COPYINGX)
2794 (void) printf(gettext(", abort of copy requested"));
2796 if (stat_flags & DSW_MSTOFFLINE)
2797 (void) printf(gettext(", master volume offline"));
2799 if (stat_flags & DSW_SHDOFFLINE)
2800 (void) printf(gettext(", shadow volume offline"));
2802 if (stat_flags & DSW_BMPOFFLINE)
2803 (void) printf(gettext(", bitmap volume offline"));
2805 if (stat_flags & DSW_OVROFFLINE)
2806 (void) printf(gettext(", overflow volume offline"));
2808 if (stat_flags & DSW_SHDEXPORT)
2809 (void) printf(gettext(", shadow volume exported"));
2811 if (stat_flags & DSW_SHDIMPORT)
2812 (void) printf(gettext(", shadow volume imported"));
2814 if (stat_flags & DSW_OVERFLOW)
2815 (void) printf(gettext(", out of space"));
2817 if (stat_flags & DSW_VOVERFLOW)
2818 (void) printf(gettext(", spilled into overflow volume"));
2819 (void) printf("\n");
2821 tmp_time = args.mtime;
2822 if (tmp_time != 0)
2823 (void) printf("%s %s", gettext("Latest modified time:"),
2824 ctime(&tmp_time));
2825 else
2826 (void) printf("%s\n", gettext("Latest modified time: unknown"));
2828 (void) printf("%s %8llu\n", gettext("Volume size:"), args.size);
2829 if (args.shdsize != 0) {
2830 (void) printf("%s %lld %s %lld\n",
2831 gettext("Shadow chunks total:"), args.shdsize,
2832 gettext("Shadow chunks used:"), args.shdused);
2834 bitmap_op(args.shadow_vol, 0, 1, 0, 0);
2838 abort_copy(char *volume)
2840 dsw_ioctl_t args;
2842 if (!find_shadow_config(volume, NULL, &args))
2843 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2844 "group"), NULL);
2845 args.status = spcs_s_ucreate();
2846 if (do_ioctl(dsw_fd, DSWIOC_ABORT, &args) == -1)
2847 dsw_error(gettext("Abort failed"), &args.status);
2848 spcs_log("ii", NULL, gettext("Abort %s"), args.shadow_vol);
2849 spcs_s_ufree(&args.status);
2850 return (0);
2853 void
2854 iiversion()
2856 dsw_version_t args;
2858 args.status = spcs_s_ucreate();
2859 if (do_ioctl(dsw_fd, DSWIOC_VERSION, &args) == -1)
2860 dsw_error(gettext("Version failed"), &args.status);
2861 spcs_s_ufree(&args.status);
2862 #ifdef DEBUG
2863 (void) printf(gettext("Point in Time Copy version %d.%d.%d.%d\n"),
2864 args.major, args.minor, args.micro, args.baseline);
2865 #else
2866 if (args.micro) {
2867 (void) printf(gettext("Point in Time Copy version %d.%d.%d\n"),
2868 args.major, args.minor, args.micro);
2869 } else {
2870 (void) printf(gettext("Point in Time Copy version %d.%d\n"),
2871 args.major, args.minor);
2873 #endif
2876 void
2877 list_volumes()
2879 dsw_list_t args;
2880 int i, set, found;
2881 dsw_config_t *lp;
2882 ENTRY item, *ip;
2883 dsw_config_t parms;
2885 if ((i = do_ioctl(dsw_fd, DSWIOC_LISTLEN, &args)) == -1)
2886 dsw_error("DSWIOC_LISTLEN", NULL);
2888 args.status = spcs_s_ucreate();
2889 args.list_used = 0;
2890 args.list_size = i + 4;
2891 lp = args.list = (dsw_config_t *)
2892 malloc(args.list_size * sizeof (dsw_config_t));
2894 if (args.list == NULL)
2895 dsw_error(gettext("Failed to allocate memory"), NULL);
2896 if (do_ioctl(dsw_fd, DSWIOC_LIST, &args) == -1)
2897 dsw_error(gettext("List failed"), &args.status);
2898 spcs_s_ufree(&args.status);
2900 /* make a hashtable */
2901 if (args.list_used > 0) {
2902 if (hcreate(args.list_used) == 0) {
2903 dsw_error(gettext("Failed to allocate memory"), NULL);
2904 /*NOTREACHED*/
2908 /* populate the hashtable */
2909 for (i = 0; i < args.list_used; i++, lp++) {
2910 item.key = lp->shadow_vol;
2911 item.data = (char *)lp;
2912 if (hsearch(item, ENTER) == NULL) {
2913 dsw_error(gettext("Failed to allocate memory"), NULL);
2914 /*NOTREACHED*/
2918 /* perform action for each line of the stored config file */
2919 for (set = 1; get_dsw_config(set, &parms) == 0; set++) {
2921 /* Are there any II sets configured on this node? */
2922 if (args.list_used > 0) {
2923 item.key = parms.shadow_vol;
2925 /* Is this volume configured on this node? */
2926 if (ip = hsearch(item, FIND)) {
2928 /* Handle Imported Shadows */
2929 /* LINTED alignment of cast ok */
2930 lp = (dsw_config_t *)ip->data;
2931 if (strcmp(parms.master_vol,
2932 II_IMPORTED_SHADOW))
2933 found = !(lp->flag & DSW_SHDIMPORT);
2934 else
2935 found = (lp->flag & DSW_SHDIMPORT);
2937 else
2938 found = FALSE;
2940 else
2941 found = FALSE;
2943 if ((cfg_cluster_tag) &&
2944 strcmp(cfg_cluster_tag, parms.cluster_tag))
2945 continue;
2947 if ((group_name) && strcmp(group_name, parms.group_name))
2948 continue;
2950 (void) printf("%s %.*s %.*s %.*s%s\n",
2951 (parms.flag & DSW_GOLDEN) ? "ind" : "dep",
2952 DSW_NAMELEN, parms.master_vol,
2953 DSW_NAMELEN, parms.shadow_vol,
2954 DSW_NAMELEN, parms.bitmap_vol,
2955 found ? "" : gettext(" (suspended)"));
2957 hdestroy();
2958 free(args.list);
2962 wait_for_copy(char *volume)
2964 dsw_ioctl_t parms;
2965 int rc;
2966 static int unlocked = 0;
2967 char *ppid;
2969 if (unlocked && !ii_lock(cfg, CFG_RDLOCK)) {
2970 dsw_error(gettext("Unable to set locking on the configuration"),
2971 NULL);
2973 config_locked = 1;
2974 if (!find_shadow_config(volume, NULL, &parms))
2975 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2976 "group"), NULL);
2977 cfg_unlock(cfg);
2978 config_locked = 0;
2979 unlocked = 1;
2981 parms.status = spcs_s_ucreate();
2982 if (pflg) {
2983 #ifdef DEBUG
2984 ppid = getenv("IIADM_PPID");
2985 if (ppid) {
2986 parms.pid = atoi(ppid);
2987 (void) fprintf(stderr, "(using %s for ppid)\n", ppid);
2988 } else {
2989 parms.pid = (nflg) ? -1 : getppid();
2991 #else
2992 parms.pid = (nflg) ? -1 : getppid();
2993 #endif
2994 parms.flags |= CV_LOCK_PID;
2997 rc = do_ioctl(dsw_fd, DSWIOC_WAIT, &parms);
2998 if (rc == -1)
2999 dsw_error(gettext("Wait failed"), &parms.status);
3000 spcs_s_ufree(&parms.status);
3001 return (0);
3005 export(char *volume)
3007 dsw_ioctl_t parms;
3008 dsw_config_t conf;
3009 char *old_ctag, dgname[DSW_NAMELEN];
3010 int rc;
3012 if (!find_shadow_config(volume, &conf, &parms))
3013 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3014 "group"), NULL);
3015 if (mounted(volume))
3016 dsw_error(gettext("Can't export a mounted volume"), NULL);
3018 /* If this is an exportable shadow in the cluster, change ctag */
3019 if (strlen(conf.cluster_tag) &&
3020 (cfg_dgname(volume, dgname, sizeof (dgname)))) {
3021 old_ctag = cfg_cluster_tag;
3022 cfg_resource(cfg, cfg_cluster_tag = strdup(dgname));
3023 } else old_ctag = NULL;
3025 if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) {
3026 dsw_error(gettext("Unable to parse config file"), NULL);
3028 reload_vols = LD_DSVOLS | LD_SHADOWS;
3029 conform_name(&volume);
3031 spcs_log("ii", NULL, gettext("Export %s"), volume);
3032 parms.status = spcs_s_ucreate();
3033 rc = do_ioctl(dsw_fd, DSWIOC_EXPORT, &parms);
3034 if (rc == -1)
3035 dsw_error(gettext("Export failed"), &parms.status);
3036 if (perform_autosv()) {
3037 if (cfg_vol_disable(cfg, volume, cfg_cluster_tag, "ii") < 0) {
3038 dsw_error(gettext("SV-disable failed"), NULL);
3040 (void) cfg_commit(cfg);
3043 /* restore old cluster tag, if changed */
3044 if (old_ctag != NULL)
3045 cfg_resource(cfg, cfg_cluster_tag = old_ctag);
3047 spcs_s_ufree(&parms.status);
3048 return (0);
3052 detach(char *volume)
3054 dsw_ioctl_t parms;
3055 int rc;
3057 if (!find_shadow_config(volume, NULL, &parms))
3058 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3059 "group"), NULL);
3060 parms.status = spcs_s_ucreate();
3061 rc = do_ioctl(dsw_fd, DSWIOC_ODETACH, &parms);
3062 if (rc == 0) {
3063 /* remove overflow from cfg line */
3064 (void) sprintf(key, "ii.set%d.overflow", setnumber);
3065 if (cfg_put_cstring(cfg, key, "-", 1) < 0) {
3066 perror("cfg_put_cstring");
3068 (void) cfg_commit(cfg);
3069 } else {
3070 spcs_log("ii", NULL, gettext("Detach of overflow %s failed"),
3071 parms.shadow_vol);
3072 dsw_error(gettext("Failed to detach overflow volume"),
3073 &parms.status);
3075 return (rc);
3078 static void
3079 can_disable(char *vol)
3081 dsw_stat_t args;
3083 if (mounted(vol)) {
3084 (void) strlcpy(args.shadow_vol, vol, DSW_NAMELEN);
3085 args.status = spcs_s_ucreate();
3086 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) != -1 &&
3087 (args.stat & DSW_GOLDEN) == 0) {
3088 errno = EBUSY;
3089 dsw_error(gettext("Shadow Volume is currently mounted "
3090 "and dependent on the master volume"), NULL);
3092 spcs_s_ufree(&args.status);
3096 static void
3097 clean_up_after_failed_disable(dsw_ioctl_t *parms)
3099 char **p;
3100 dsw_stat_t args;
3102 for (p = group_volumes; *p; p++) {
3103 (void) strlcpy(args.shadow_vol, *p, DSW_NAMELEN);
3104 args.status = spcs_s_ucreate();
3105 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) {
3106 /* set was successfully disabled */
3107 if (find_shadow_config(*p, NULL, NULL))
3108 remove_iiset(setnumber, *p, 0);
3110 spcs_s_ufree(&args.status);
3113 dsw_error(gettext("Some sets in the group failed to disable"),
3114 &parms->status);
3118 dsw_group_or_single_disable(int argc, char *argv[])
3120 int rc = 0;
3121 char **p;
3122 dsw_ioctl_t parms;
3123 int flags = 0;
3124 dsw_config_t conf;
3125 int shd_exported = 0;
3127 if (argc != 2)
3128 usage(gettext("Incorrect number of arguments"));
3130 if (group_name) {
3131 if (find_group_members(group_name) < 1)
3132 dsw_error(gettext("Group does not exist or "
3133 "has no members"), NULL);
3134 for (p = group_volumes; *p; p++) {
3135 can_disable(*p);
3138 (void) strncpy(parms.shadow_vol, group_name, DSW_NAMELEN);
3139 if (*group_name)
3140 flags = CV_IS_GROUP;
3141 } else {
3142 if (!find_shadow_config(argv[1], &conf, &parms)) {
3143 dsw_error(gettext("Volume is not in a Point-in-Time "
3144 "Copy group"), NULL);
3147 can_disable(argv[1]);
3148 flags = 0;
3151 if (group_name && !*group_name) {
3152 /* user typed iiadm -g "" -d */
3153 for (p = group_volumes; *p; p++) {
3154 parms.status = spcs_s_ucreate();
3155 parms.flags = flags;
3156 (void) strncpy(parms.shadow_vol, *p, DSW_NAMELEN);
3157 rc = do_ioctl(dsw_fd, DSWIOC_DISABLE, &parms);
3158 if (rc == -1 && errno != DSW_ENOTFOUND)
3159 dsw_error(gettext("Disable failed"),
3160 &parms.status);
3161 if (!find_shadow_config(*p, NULL, NULL))
3162 dsw_error(gettext("Volume is not in a Point-in"
3163 "-Time Copy group"), &parms.status);
3164 remove_iiset(setnumber, *p, 0);
3165 spcs_s_ufree(&parms.status);
3166 spcs_log("ii", NULL, gettext("Disabled %s"),
3167 parms.shadow_vol);
3169 } else {
3170 if (is_exported(conf.shadow_vol)) {
3171 shd_exported = 1;
3173 if ((strcmp(conf.master_vol, II_IMPORTED_SHADOW) == 0) &&
3174 is_exported(conf.shadow_vol)) {
3175 dsw_error(gettext(
3176 "Imported shadow not disabled"), NULL);
3179 parms.status = spcs_s_ucreate();
3180 parms.flags = flags;
3181 rc = do_ioctl(dsw_fd, DSWIOC_DISABLE, &parms);
3182 if (rc == -1 && errno != DSW_ENOTFOUND) {
3183 if (errno == DSW_EDISABLE) {
3185 * one or more sets within the group
3186 * couldn't disable
3188 clean_up_after_failed_disable(&parms);
3189 } else {
3190 dsw_error(gettext("Disable failed"),
3191 &parms.status);
3194 spcs_log("ii", NULL, gettext("Disabled %s"), parms.shadow_vol);
3198 if (group_name && *group_name) {
3199 for (p = group_volumes; *p; p++) {
3200 if (!find_shadow_config(*p, NULL, NULL)) {
3201 /* argh! */
3202 (void) fprintf(stderr,
3203 gettext("Volume '%s' is not "
3204 "in a Point-in-Time Copy group"), *p);
3205 } else {
3206 remove_iiset(setnumber, *p, 0);
3209 } else if (!group_name) {
3210 if (!find_shadow_config(argv[1], NULL, NULL)) {
3211 /* argh! */
3212 dsw_error(gettext("Volume is not in a Point-in-Time "
3213 "Copy group"), NULL);
3216 remove_iiset(setnumber, argv[1], shd_exported);
3219 return (0);
3223 dsw_group_or_single_op(int argc, char *argv[], int (*op)(char *))
3225 int rc = 0;
3227 if (argc != 2)
3228 usage(gettext("Incorrect number of arguments"));
3230 if (group_name) {
3231 if (find_group_members(group_name) < 1)
3232 dsw_error(gettext("Group does not exist or "
3233 "has no members"), NULL);
3234 for (; *group_volumes; group_volumes++)
3235 rc |= (*op)(*group_volumes);
3236 } else {
3237 rc = (*op)(argv[1]);
3239 return (rc);
3242 void
3243 dsw_list_clusters(char *cluster)
3245 dsw_aioctl_t *acopy_args;
3246 int rc, i, count;
3247 char *ptr;
3249 if ((count = do_ioctl(dsw_fd, DSWIOC_LISTLEN, NULL)) < 0)
3250 dsw_error("DSWIOC_LISTLEN", NULL);
3252 acopy_args = malloc(sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
3253 if (acopy_args == NULL)
3254 dsw_error(gettext("Can't get memory for list enquiry"), NULL);
3256 bzero(acopy_args, sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
3257 acopy_args->count = count;
3258 acopy_args->flags = 0;
3259 acopy_args->status = spcs_s_ucreate();
3260 if (cluster)
3261 (void) strncpy(acopy_args->shadow_vol, cluster, DSW_NAMELEN);
3263 rc = do_ioctl(dsw_fd, DSWIOC_CLIST, acopy_args);
3264 if (rc == -1)
3265 dsw_error(gettext("Cluster list access failure"),
3266 &acopy_args->status);
3268 acopy_args->shadow_vol[DSW_NAMELEN*acopy_args->count] = NULL;
3270 if (cluster) {
3271 (void) printf(gettext("Sets in cluster resource group %s:\n"),
3272 cluster);
3273 } else {
3274 (void) printf(
3275 gettext("Currently configured resource groups\n"));
3277 for (i = 0, ptr = acopy_args->shadow_vol; *ptr &&
3278 i < acopy_args->count; i++, ptr += DSW_NAMELEN) {
3279 (void) printf(" %-64.64s\n", ptr);
3283 void
3284 dsw_enable(int argc, char *argv[])
3286 if (argc != 5)
3287 usage(gettext("Incorrect number of arguments"));
3289 enable(argv[1], argv[2], argv[3], argv[4]);
3290 exit(0);
3294 void
3295 dsw_disable(int argc, char *argv[])
3297 (void) dsw_group_or_single_disable(argc, argv);
3298 exit(0);
3302 void
3303 dsw_copy_to_shadow(int argc, char *argv[])
3305 char **volume_list;
3307 if (argc != 2)
3308 usage(gettext("Incorrect number of arguments"));
3309 if (group_name == NULL)
3310 volume_list = ++argv;
3311 else {
3312 if (find_group_members(group_name) < 1)
3313 dsw_error(gettext("Group does not exist or "
3314 "has no members"), NULL);
3315 volume_list = group_volumes;
3318 exit(do_copy(volume_list, Copy, ToShadow, WaitForStart));
3322 void
3323 dsw_update_shadow(int argc, char *argv[])
3325 char **volume_list;
3327 if (argc != 2)
3328 usage(gettext("Incorrect number of arguments"));
3329 if (group_name == NULL)
3330 volume_list = ++argv;
3331 else {
3332 if (find_group_members(group_name) < 1)
3333 dsw_error(gettext("Group does not exist or "
3334 "has no members"), NULL);
3335 volume_list = group_volumes;
3338 exit(do_copy(volume_list, Update, ToShadow, WaitForStart));
3342 void
3343 dsw_copy_to_master(int argc, char *argv[])
3345 char **volume_list;
3347 if (argc != 2)
3348 usage(gettext("Incorrect number of arguments"));
3349 if (group_name == NULL) {
3350 volume_list = ++argv;
3351 check_action(gettext("Overwrite master with shadow volume?"));
3352 } else {
3353 check_action(gettext("Overwrite every"
3354 " master in this group with its shadow volume?"));
3355 if (find_group_members(group_name) < 1)
3356 dsw_error(gettext("Group does not exist or "
3357 "has no members"), NULL);
3358 volume_list = group_volumes;
3361 exit(do_copy(volume_list, Copy, ToMaster, WaitForStart));
3365 void
3366 dsw_update_master(int argc, char *argv[])
3368 char **volume_list;
3370 if (argc != 2)
3371 usage(gettext("Incorrect number of arguments"));
3372 if (group_name == NULL) {
3373 volume_list = ++argv;
3374 check_action(gettext("Overwrite master with shadow volume?"));
3375 } else {
3376 check_action(gettext("Overwrite every"
3377 " master in this group with its shadow volume?"));
3378 if (find_group_members(group_name) < 1)
3379 dsw_error(gettext("Group does not exist or "
3380 "has no members"), NULL);
3381 volume_list = group_volumes;
3384 exit(do_copy(volume_list, Update, ToMaster, WaitForStart));
3388 void
3389 dsw_abort_copy(int argc, char *argv[])
3391 exit(dsw_group_or_single_op(argc, argv, abort_copy));
3395 void
3396 dsw_display_status(int argc, char *argv[])
3398 dsw_config_t parms;
3399 int in_config;
3401 if (argc != 2 && argc != 1)
3402 usage(gettext("Incorrect number of arguments"));
3404 /* "iiadm -i" and "iiadm -i all" are equivalent */
3405 if (argc == 2 && strcmp("all", argv[1]) != 0) {
3406 in_config = find_shadow_config(argv[1], &parms, NULL);
3407 if (!in_config) {
3408 (void) printf(gettext(
3409 "Volume is not in configuration file\n"), NULL);
3410 (void) fflush(stdout);
3411 (void) strlcpy(parms.shadow_vol, argv[1], DSW_NAMELEN);
3413 print_status(&parms, in_config);
3414 } else if (group_name) {
3415 if (find_group_members(group_name) < 1)
3416 dsw_error(gettext("Group does not exist or "
3417 "has no members"), NULL);
3418 for (; *group_volumes; group_volumes++) {
3419 in_config = find_shadow_config(*group_volumes,
3420 &parms, NULL);
3421 if (in_config)
3422 print_status(&parms, in_config);
3424 } else {
3425 /* perform action for each line of the stored config file */
3426 for (setnumber = 1;
3427 !get_dsw_config(setnumber, &parms); setnumber++) {
3428 switch (check_cluster()) {
3429 case II_CLUSTER:
3430 if ((cfg_cluster_tag) &&
3431 (strcmp(cfg_cluster_tag,
3432 parms.cluster_tag)))
3433 continue;
3434 break;
3435 case II_CLUSTER_LCL:
3436 if (strlen(parms.cluster_tag))
3437 continue;
3438 break;
3440 print_status(&parms, 1);
3443 exit(0);
3446 void
3447 dsw_display_bitmap(int argc, char *argv[])
3449 dsw_config_t parms;
3450 int in_config;
3452 if (argc != 2)
3453 usage(gettext("Incorrect number of arguments"));
3455 in_config = find_shadow_config(argv[1], &parms, NULL);
3456 if (!in_config) {
3457 (void) printf(gettext(
3458 "Volume is not in configuration file\n"), NULL);
3459 (void) fflush(stdout);
3460 (void) strlcpy(parms.master_vol, argv[1], DSW_NAMELEN);
3463 bitmap_op(parms.shadow_vol, 1, 0, 0, 0);
3464 exit(0);
3468 /*ARGSUSED*/
3469 void
3470 dsw_version(int argc, char *argv[])
3472 iiversion();
3473 exit(0);
3476 void
3477 dsw_reset(int argc, char *argv[])
3479 exit(dsw_group_or_single_op(argc, argv, reset));
3482 void
3483 dsw_overflow(int argc, char *argv[])
3485 if (argc != 2)
3486 usage(gettext("Incorrect number of arguments"));
3488 exit(overflow(argv[1]));
3491 void
3492 dsw_wait(int argc, char *argv[])
3494 exit(dsw_group_or_single_op(argc, argv, wait_for_copy));
3497 /*ARGSUSED*/
3498 void
3499 dsw_list_volumes(int argc, char *argv[])
3501 if (argc != 1)
3502 usage(gettext("Incorrect number of arguments"));
3504 list_volumes();
3505 exit(0);
3508 void
3509 dsw_export(int argc, char *argv[])
3511 if (argc != 2)
3512 usage(gettext("Incorrect number of arguments"));
3514 exit(dsw_group_or_single_op(argc, argv, export));
3517 void
3518 dsw_detach(int argc, char *argv[])
3520 (void) dsw_group_or_single_op(argc, argv, detach);
3521 exit(0);
3524 void
3525 import(char *shadow_volume, char *bitmap_volume)
3527 dsw_config_t parms = {0};
3528 int rc = 0;
3529 char shd_dg[DSW_NAMELEN];
3530 char bmp_dg[DSW_NAMELEN];
3533 * If importing a shadow volume and the shadow volume is already
3534 * configured, we only support this if we are in a Sun Cluster
3535 * and the current user specified a cluster tag of -C local
3537 if (find_shadow_config(shadow_volume, &parms, NULL)) {
3538 dsw_error(gettext("Can't import volume on same node"), NULL);
3541 switch (check_cluster()) {
3542 case II_CLUSTER:
3543 case II_CLUSTER_LCL:
3544 (void) check_resource_group(shadow_volume);
3545 if (cfg_cluster_tag) { /* check all volumes are in same dg */
3546 if (cfg_dgname(shadow_volume, shd_dg, DSW_NAMELEN)
3547 == NULL)
3548 dsw_error(gettext("Shadow volume not in a"
3549 " disk group"), NULL);
3550 if (cfg_dgname(bitmap_volume, bmp_dg, DSW_NAMELEN)
3551 == NULL)
3552 dsw_error(gettext("Bitmap volume not in a"
3553 " disk group"), NULL);
3554 if (strcmp(bmp_dg, shd_dg) != 0)
3555 dsw_error(gettext("Bitmap volume not in"
3556 " same disk group as shadow set members"),
3557 NULL);
3559 break;
3560 case II_NOT_CLUSTER:
3561 /* do nothing */
3562 break;
3563 default:
3564 dsw_error(gettext(
3565 "Unexpected return from check_cluster()"), NULL);
3568 /* Local configuration volumes */
3569 if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) {
3570 dsw_error(gettext("Unable to parse config file"), NULL);
3573 reload_vols = LD_DSVOLS | LD_SHADOWS;
3574 conform_name(&shadow_volume);
3575 (void) strcpy(parms.master_vol, II_IMPORTED_SHADOW);
3576 (void) strlcpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
3577 (void) strlcpy(parms.bitmap_vol, bitmap_volume, DSW_NAMELEN);
3578 parms.flag = DSW_GOLDEN;
3580 spcs_log("ii", NULL, gettext("Import %s %s"),
3581 parms.shadow_vol, parms.bitmap_vol);
3582 parms.status = spcs_s_ucreate();
3583 rc = do_ioctl(dsw_fd, DSWIOC_IMPORT, &parms);
3584 if (rc == -1) {
3585 spcs_log("ii", NULL, gettext("Import failed %s %s"),
3586 parms.shadow_vol, parms.bitmap_vol);
3587 dsw_error(gettext("Import failed"), &parms.status);
3589 if (perform_autosv()) {
3590 if (cfg_vol_enable(cfg, shadow_volume, cfg_cluster_tag, "ii")
3591 < 0) {
3592 dsw_error(gettext("SV-enable failed"), NULL);
3594 /* cfg_commit is called by add_cfg_entry below */
3596 spcs_s_ufree(&parms.status);
3597 add_cfg_entry(&parms);
3600 void
3601 dsw_import(int argc, char *argv[])
3603 if (argc != 3)
3604 usage(gettext("Incorrect number of arguments"));
3605 import(argv[1], argv[2]);
3607 exit(0);
3610 void
3611 join(char *shadow_volume, char *bitmap_file)
3613 dsw_ioctl_t shd;
3614 dsw_config_t conf;
3615 dsw_bitmap_t parms;
3616 int rc = 0;
3617 int size;
3618 FILE *bmpfp;
3619 uchar_t *shd_bitmap = 0;
3620 ii_header_t header;
3621 char dgname[DSW_NAMELEN];
3623 if (!find_shadow_config(shadow_volume, &conf, &shd))
3624 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3625 "group"), NULL);
3627 /* If this is an exportable shadow in the cluster, change ctag */
3628 if (strlen(conf.cluster_tag) &&
3629 (cfg_dgname(shadow_volume, dgname, sizeof (dgname))))
3630 cfg_resource(cfg, cfg_cluster_tag = strdup(dgname));
3632 if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) {
3633 dsw_error(gettext("Unable to parse config file"), NULL);
3635 reload_vols = LD_DSVOLS | LD_SHADOWS;
3636 conform_name(&shadow_volume);
3638 if ((bmpfp = fopen(bitmap_file, "r")) == NULL) {
3639 perror(bitmap_file);
3640 (void) fprintf(stderr,
3641 gettext("Can't open imported bitmap volume\n"));
3642 exit(1);
3645 if (fread(&header, sizeof (header), 1, bmpfp) != 1) {
3646 (void) fprintf(stderr,
3647 gettext("Can't read imported bitmap volume\n"));
3648 exit(1);
3651 /* See if this is a bitmap header */
3652 switch (header.ii_magic) {
3653 case DSW_DIRTY: /* A copy of a enable bitmap volume */
3654 case DSW_CLEAN:
3655 check_action(gettext("Use the never imported bitmap?"));
3656 break;
3657 case DSW_INVALID: /* A valid diskable secondary bitmap */
3658 break;
3659 default:
3660 (void) fprintf(stderr,
3661 gettext("Secondary bitmap is not a valid bitmap volume\n"));
3662 exit(1);
3665 size = FBA_SIZE(header.ii_copyfba - header.ii_shdfba);
3666 if ((shd_bitmap = malloc(size)) == NULL) {
3667 perror("malloc");
3668 exit(1);
3671 if (fseek(bmpfp, FBA_SIZE(header.ii_shdfba), SEEK_SET)) {
3672 perror("fseek");
3673 exit(1);
3676 if (fread(shd_bitmap, 1, size, bmpfp) != size) {
3677 (void) fprintf(stderr,
3678 gettext("Can't read imported bitmap volume\n"));
3679 exit(1);
3682 (void) fclose(bmpfp);
3684 (void) strlcpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
3685 parms.shd_bitmap = shd_bitmap;
3686 parms.shd_size = size;
3687 parms.copy_bitmap = NULL;
3688 parms.copy_size = 0;
3690 spcs_log("ii", NULL, gettext("Join %s %s"),
3691 parms.shadow_vol, bitmap_file);
3692 parms.status = spcs_s_ucreate();
3693 rc = do_ioctl(dsw_fd, DSWIOC_JOIN, &parms);
3694 if (rc == -1) {
3695 spcs_log("ii", NULL, gettext("Join failed %s %s"),
3696 parms.shadow_vol, bitmap_file);
3697 dsw_error(gettext("Join failed"), &parms.status);
3699 if (perform_autosv()) {
3700 rc = cfg_vol_enable(cfg, shadow_volume, cfg_cluster_tag, "ii");
3701 if (rc < 0) {
3702 dsw_error(gettext("SV-enable failed"), NULL);
3704 (void) cfg_commit(cfg);
3706 spcs_s_ufree(&parms.status);
3710 params(char *shadow_volume)
3712 char *delay = param_delay;
3713 char *unit = param_unit;
3714 dsw_copyp_t parms;
3715 int rc = 0;
3716 int get = 0;
3717 int new_delay;
3718 int new_unit;
3720 (void) strlcpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
3721 if (delay == NULL || unit == NULL) {
3722 get = 1;
3723 parms.copy_delay = -1;
3724 parms.copy_unit = -1;
3725 } else {
3726 new_delay = parms.copy_delay = convert_int(delay);
3727 new_unit = parms.copy_unit = convert_int(unit);
3730 parms.status = spcs_s_ucreate();
3731 rc = do_ioctl(dsw_fd, DSWIOC_COPYP, &parms);
3732 if (rc == -1) {
3733 (void) fprintf(stderr,
3734 gettext("Parameter ranges are delay(%d - %d), "
3735 "units(%d - %d)\n"), MIN_THROTTLE_DELAY, MAX_THROTTLE_DELAY,
3736 MIN_THROTTLE_UNIT, MAX_THROTTLE_UNIT);
3737 dsw_error(gettext("Set Copy Parameters failed"), &parms.status);
3739 if (!get)
3740 spcs_log("ii", NULL, gettext("Changed copy parameters %s from "
3741 "%d %d to %d %d"), parms.shadow_vol, parms.copy_delay,
3742 parms.copy_unit, new_delay, new_unit);
3743 else
3744 (void) printf(gettext("volume: %s\ncopy delay: %d\ncopy unit:"
3745 " %d\n"), parms.shadow_vol, parms.copy_delay,
3746 parms.copy_unit);
3747 spcs_s_ufree(&parms.status);
3748 return (0);
3751 static void
3752 do_attach(dsw_config_t *parms)
3754 dsw_config_t io;
3755 int rc;
3756 int check = 0;
3758 spcs_log("ii", NULL, gettext("Attach %s %s"),
3759 parms->shadow_vol, parms->bitmap_vol);
3760 parms->status = spcs_s_ucreate();
3761 rc = do_ioctl(dsw_fd, DSWIOC_OATTACH, parms);
3762 if (rc == -1) {
3763 check = 1;
3764 /* if overflow() fails, it calls dsw_error to exit */
3765 (void) overflow(parms->bitmap_vol);
3767 spcs_s_ufree(&parms->status);
3768 if (check == 1) {
3769 if (!find_shadow_config(parms->shadow_vol, &io, NULL))
3770 dsw_error(
3771 gettext("Volume is not in a Point-in-Time Copy "
3772 "group"), NULL);
3773 (void) strlcpy(io.bitmap_vol, parms->bitmap_vol, DSW_NAMELEN);
3774 io.status = spcs_s_ucreate();
3775 if (do_ioctl(dsw_fd, DSWIOC_OATTACH, &io) == -1) {
3776 spcs_log("ii", NULL, gettext("Attach failed %s %s"),
3777 io.shadow_vol, parms->bitmap_vol);
3778 dsw_error(gettext("Attach failed"), &io.status);
3780 spcs_s_ufree(&io.status);
3785 attach(char *shadow_volume)
3787 dsw_config_t parms;
3788 dsw_stat_t args;
3789 char shd_dg[DSW_NAMELEN];
3790 char ovr_dg[DSW_NAMELEN];
3792 switch (check_cluster()) {
3793 case II_CLUSTER:
3794 case II_CLUSTER_LCL:
3795 (void) check_resource_group(shadow_volume);
3796 if (cfg_cluster_tag) { /* check all volumes are in same dg */
3797 if (cfg_dgname(shadow_volume, shd_dg, DSW_NAMELEN)
3798 == NULL)
3799 dsw_error(gettext("Shadow volume not in a"
3800 " disk group"), NULL);
3801 if (cfg_dgname(overflow_file, ovr_dg, DSW_NAMELEN)
3802 == NULL)
3803 dsw_error(gettext("Overflow volume not in a"
3804 " disk group"), NULL);
3805 if (strcmp(ovr_dg, shd_dg) != 0)
3806 dsw_error(gettext("Overflow volume not in"
3807 " same disk group as shadow set members"),
3808 NULL);
3810 break;
3811 case II_NOT_CLUSTER:
3812 /* do nothing */
3813 break;
3814 default:
3815 dsw_error(gettext(
3816 "Unexpected return from check_cluster()"), NULL);
3819 /* assure that the overflow_file is not an II volume */
3820 if (find_any_cf_line(overflow_file))
3821 dsw_error(gettext(
3822 "Overflow volume is already in a Point-in-Time Copy "
3823 "group"), NULL);
3825 /* use find_shadow_config() to find setnumber */
3826 if (!find_shadow_config(shadow_volume, &parms, NULL))
3827 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3828 "group"), NULL);
3830 /* can only attach an overflow volume to dependent, compact shadow */
3831 (void) strlcpy(args.shadow_vol, shadow_volume, DSW_NAMELEN);
3833 args.status = spcs_s_ucreate();
3834 if ((do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) ||
3835 !(args.stat & DSW_TREEMAP))
3836 dsw_error(gettext("Not a compact dependent shadow"), NULL);
3838 /* bitmap_vol is overloaded */
3839 (void) strlcpy(parms.bitmap_vol, overflow_file, DSW_NAMELEN);
3841 do_attach(&parms);
3843 /* add overflow to cfg line */
3844 (void) sprintf(key, "ii.set%d.overflow", setnumber);
3845 if (cfg_put_cstring(cfg, key, overflow_file,
3846 strlen(overflow_file)) < 0) {
3847 perror("cfg_put_cstring");
3849 (void) cfg_commit(cfg);
3850 return (0);
3853 void
3854 dsw_join(int argc, char *argv[])
3856 if (argc != 3)
3857 usage(gettext("Incorrect number of arguments"));
3859 join(argv[1], argv[2]);
3860 exit(0);
3863 void
3864 dsw_params(int argc, char *argv[])
3866 if (argc != 4 && argc != 2 && argc != 0)
3867 usage(gettext("Incorrect number of arguments"));
3869 if ((argc == 4) || (argc == 2)) {
3870 param_delay = argv[1];
3871 param_unit = argv[2];
3872 if (argc == 4) {
3873 argv[1] = argv[3];
3874 argv[2] = NULL;
3877 exit(dsw_group_or_single_op(2, argv, params));
3880 /*ARGSUSED*/
3881 void
3882 dsw_attach(int argc, char *argv[])
3884 overflow_file = argv[1];
3885 argv[1] = argv[2];
3886 (void) dsw_group_or_single_op(2, argv, attach);
3887 exit(0);
3890 /*ARGSUSED*/
3891 void
3892 dsw_olist(int argc, char *argv[])
3894 char *sp, *overflow_list, **vol;
3895 int count, i;
3896 ENTRY item, *found;
3897 char key[ CFG_MAX_KEY ], buf[ CFG_MAX_BUF ];
3899 overflow_list = get_overflow_list();
3901 /* count entries */
3902 count = 0;
3903 for (sp = overflow_list; *sp; sp += DSW_NAMELEN) {
3904 ++count;
3907 /* create hash (adding room for suspended overflow volumes) */
3908 if (hcreate(count + 1024) == 0) {
3909 dsw_error(gettext("Out of memory creating lookup table"), NULL);
3910 /*NOTREACHED*/
3913 if (count > 0) {
3914 /* create memory to store copy of list */
3915 vol = (char **)calloc(count, sizeof (char *));
3916 if (!vol) {
3917 dsw_error(
3918 gettext("Out of memory creating lookup table"),
3919 NULL);
3920 /*NOTREACHED*/
3923 /* fill hash */
3924 for (i = 0, sp = overflow_list; *sp; sp += DSW_NAMELEN, i++) {
3926 /* make copy of string */
3927 vol[ i ] = (char *)malloc(DSW_NAMELEN + 1);
3928 (void) strlcpy(vol[ i ], sp, DSW_NAMELEN);
3930 item.key = vol[ i ];
3931 item.data = (char *)0;
3932 (void) hsearch(item, ENTER);
3936 /* loop through config file entries */
3937 i = 0;
3938 cfg_rewind(cfg, CFG_SEC_CONF);
3940 /*CONSTCOND*/
3941 while (1) {
3942 ++i;
3943 (void) snprintf(key, CFG_MAX_KEY, "ii.set%d.overflow", i);
3944 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
3945 break;
3948 /* has this set got an overflow volume? */
3949 if (!*buf) {
3950 continue;
3953 /* look up overflow in hash */
3954 item.key = buf;
3955 if (count > 0 && (found = hsearch(item, FIND)) != NULL) {
3956 if (0 == (int)found->data) {
3957 (void) printf("%s\n", buf);
3958 found->data = (char *)1;
3959 (void) hsearch(*found, ENTER);
3961 } else {
3962 /* must be part of a suspended set */
3963 (void) printf("%s (attached to suspended set)\n", buf);
3964 item.key = buf;
3965 item.data = (char *)1;
3966 (void) hsearch(item, ENTER);
3970 exit(0);
3973 void
3974 dsw_ostat(int argc, char *argv[])
3976 dsw_ostat_t args;
3977 int stat_flags;
3979 if (argc != 2)
3980 usage(gettext("Incorrect number of arguments"));
3982 (void) strlcpy(args.overflow_vol, argv[1], DSW_NAMELEN);
3984 args.status = spcs_s_ucreate();
3985 if (do_ioctl(dsw_fd, DSWIOC_OSTAT2, &args) == -1)
3986 dsw_error(gettext("Stat failed"), &args.status);
3987 spcs_s_ufree(&args.status);
3989 if ((args.hversion >= 1) && (args.hmagic == II_OMAGIC)) {
3990 stat_flags = args.flags;
3991 if (stat_flags & IIO_CNTR_INVLD)
3992 (void) printf(gettext("Clean shutdown of volume "
3993 "sets associated with overflow volume "
3994 "did not occur.\n"
3995 "Overflow counters will be inconsistent "
3996 "until new point-in-time(s) are taken.\n"));
3998 (void) printf(gettext("Total number of attached shadows: %d\n"),
3999 args.drefcnt);
4000 (void) printf(gettext("Number of currently attached shadows: %d\n"),
4001 args.crefcnt);
4002 (void) printf(gettext("Total number of chunks: %lld\n"), args.nchunks);
4003 (void) printf(gettext("Number of chunks ever allocated: %lld\n"),
4004 args.used);
4005 (void) printf(gettext("Number of used chunks: %lld\n"),
4006 (args.nchunks - args.unused));
4007 (void) printf(gettext("Number of unused chunks: %lld\n"), args.unused);
4008 exit(0);
4011 /*ARGSUSED*/
4012 void
4013 dsw_move_2_group(int argc, char *argv[])
4015 dsw_config_t parms;
4016 dsw_movegrp_t movegrp;
4017 grptag_t *gdata;
4018 int waserr = 0;
4020 /* handle move to NULL group, or group of all spaces or tabs */
4021 (void) strncpy(movegrp.new_group, group_name, DSW_NAMELEN);
4022 if ((strlen(group_name) == 0) || (strcspn(group_name, " \t") == 0)) {
4023 group_name = "-";
4024 bzero(movegrp.new_group, DSW_NAMELEN);
4025 gdata = NULL;
4026 } else {
4027 /* get the ctag for this group (if any) */
4028 gdata = (grptag_t *)nsc_lookup(volhash, group_name);
4031 movegrp.status = spcs_s_ucreate();
4033 for (++argv; *argv; argv++) {
4034 if (!find_shadow_config(*argv, &parms, NULL))
4035 dsw_error(gettext("Volume is not in a Point-in-Time "
4036 "Copy group"), NULL);
4038 /* ensure the ctag matches the group */
4039 if (gdata && *gdata->ctag) {
4040 if (strncmp(parms.cluster_tag, gdata->ctag,
4041 DSW_NAMELEN) != 0) {
4042 (void) fprintf(stderr, "%s: %s %s %s\n", cmdnam,
4043 gettext("unable to move set"), *argv,
4044 gettext("into new group - cluster "
4045 "resource mismatch"));
4046 waserr = 1;
4047 continue;
4051 /* move the set in the kernel */
4052 (void) strncpy(movegrp.shadow_vol, parms.shadow_vol,
4053 DSW_NAMELEN);
4054 if (do_ioctl(dsw_fd, DSWIOC_MOVEGRP, &movegrp) < 0)
4055 dsw_error(gettext("Failed to move group in kernel"),
4056 NULL);
4058 /* now update the config */
4059 (void) sprintf(key, "ii.set%d.group", setnumber);
4060 if (cfg_put_cstring(cfg, key, group_name,
4061 strlen(group_name)) < 0) {
4062 perror("cfg_put_cstring");
4064 (void) cfg_commit(cfg);
4066 spcs_s_ufree(&movegrp.status);
4067 cfg_close(cfg);
4068 exit(waserr);
4071 void
4072 dsw_list_groups()
4074 FILE *pfp;
4076 if ((pfp = popen("/usr/bin/sort -u", "w")) == NULL) {
4077 dsw_error(gettext("Can't open sort program"), NULL);
4080 (void) fflush(stdout);
4081 for (setnumber = 1; /*CSTYLED*/; setnumber++) {
4082 (void) snprintf(key, sizeof (key), "ii.set%d.group", setnumber);
4083 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0)
4084 break;
4086 /* skip if shadow set is not in any group */
4087 if (strcmp(buf, "") == 0)
4088 continue;
4089 (void) fprintf(pfp, "%s\n", buf);
4091 (void) pclose(pfp);
4094 void
4095 dsw_list_group_volumes()
4097 FILE *pfp;
4099 if (find_group_members(group_name) < 1)
4100 dsw_error(gettext("Group does not exist or has no members"),
4101 NULL);
4103 if ((pfp = popen("/usr/bin/sort -u", "w")) == NULL) {
4104 dsw_error(gettext("Can't open sort program"), NULL);
4107 (void) fflush(stdout);
4108 for (; *group_volumes; group_volumes++)
4109 (void) fprintf(pfp, "%s\n", *group_volumes);
4110 (void) pclose(pfp);
4113 static void
4114 load_ii_vols(CFGFILE *cfg)
4116 int set, entries;
4117 char *mst, *shd, *buf, **entry;
4118 char *ctag, *group;
4119 mstcount_t *mdata;
4120 shdvol_t *sdata;
4121 grptag_t *gdata;
4122 static int whinged = 0;
4124 if (volhash) {
4125 return;
4128 volhash = nsc_create_hash();
4129 cfg_rewind(cfg, CFG_SEC_CONF);
4130 entries = cfg_get_section(cfg, &entry, "ii");
4131 for (set = 1; set <= entries; set++) {
4132 buf = entry[set - 1];
4134 /* grab master volume name */
4135 mst = strtok(buf, " ");
4136 if (!mst) {
4137 free(buf);
4138 break;
4141 /* grab shadow, group & cnode fields */
4142 shd = strtok(NULL, " ");
4143 (void) strtok(NULL, " "); /* bitmap */
4144 (void) strtok(NULL, " "); /* mode */
4145 (void) strtok(NULL, " "); /* overflow */
4146 ctag = strtok(NULL, " "); /* cnode */
4147 (void) strtok(NULL, " "); /* options */
4148 group = strtok(NULL, " "); /* group */
4150 /* Fix optional tags */
4151 if (ctag)
4152 ctag += strspn(ctag, "-");
4153 if (group)
4154 group += strspn(group, "-");
4156 /* If cluster tags don't match, skip record */
4157 if ((cfg_cluster_tag && strcmp(ctag, cfg_cluster_tag)) ||
4158 (!cfg_cluster_tag && strlen(ctag))) {
4159 free(buf);
4160 continue;
4163 /* master volume, may be duplicates */
4164 mdata = (mstcount_t *)nsc_lookup(volhash, mst);
4165 if (mdata) {
4166 ++mdata->count;
4167 } else {
4168 mdata = (mstcount_t *)malloc(sizeof (mstcount_t));
4169 mdata->count = 1;
4170 (void) nsc_insert_node(volhash, mdata, mst);
4173 /* grab shadow volume name */
4174 sdata = (shdvol_t *)malloc(sizeof (shdvol_t));
4175 (void) strncpy(sdata->master, mst, DSW_NAMELEN);
4176 (void) nsc_insert_node(volhash, sdata, shd);
4178 /* No need to continue if no groups or ctags */
4179 if (!group || !*group || !ctag || !*ctag) {
4180 free(buf);
4181 continue;
4184 gdata = (grptag_t *)nsc_lookup(volhash, group);
4185 if (gdata) {
4186 /* group already exists - check ctag */
4187 if (*ctag &&
4188 (strncmp(ctag, gdata->ctag, DSW_NAMELEN) != 0)) {
4189 if (!whinged) {
4190 (void) printf(gettext(
4191 "Warning: multiple "
4192 "cluster resource groups "
4193 "defined within a single "
4194 "I/O group\n"));
4195 whinged = 1;
4198 } else {
4199 gdata = (grptag_t *)malloc(sizeof (grptag_t));
4200 (void) strncpy(gdata->ctag, ctag, DSW_NAMELEN);
4201 (void) nsc_insert_node(volhash, gdata, group);
4204 free(buf);
4207 /* free up any leftovers */
4208 while (set < entries)
4209 free(entry[set++]);
4210 if (entries)
4211 free(entry);
4214 static void
4215 unload_ii_vols()
4217 nsc_remove_all(volhash, free);
4218 volhash = 0;
4221 static int
4222 perform_autosv()
4224 static int result;
4225 static int calculated = 0;
4226 int rc;
4228 #ifdef DEBUG
4229 if (getenv("II_SET_CLUSTER"))
4230 return (1);
4231 #endif
4233 if (calculated) {
4234 return (result);
4238 * we only perform auto-sv if we're in a sun cluster or if
4239 * we're on a standalone system. I.e. we don't do auto-sv on Harry
4241 rc = check_cluster();
4243 if (II_NOT_CLUSTER == rc) {
4244 result = 1;
4245 } else {
4246 result = cfg_issuncluster();
4249 calculated = 1;
4250 return (result);
4254 * Returns true if set has had the shadow volume exported.
4255 * Returns false if shadow volume is not exported, or set is suspended.
4257 static int
4258 is_exported(char *set)
4260 dsw_stat_t args;
4261 int rc;
4263 (void) strlcpy(args.shadow_vol, set, DSW_NAMELEN);
4264 args.status = spcs_s_ucreate();
4266 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &args);
4267 spcs_s_ufree(&args.status);
4269 if (-1 == rc) {
4270 /* set must be suspended, or being disabled */
4271 return (0);
4274 return ((args.stat & DSW_SHDEXPORT) == DSW_SHDEXPORT);
4277 static void
4278 conform_name(char **path)
4280 char *cfgname;
4281 int rc = cfg_get_canonical_name(cfg, *path, &cfgname);
4283 if (rc < 0) {
4284 dsw_error(gettext("Unable to parse config file"), NULL);
4286 if (rc) {
4287 (void) printf(" '%s'\n%s\n '%s'\n", *path,
4288 gettext("is currently configured as"), cfgname);
4289 check_action(gettext("Perform operation with indicated volume"
4290 " name?"));
4291 *path = cfgname;
4293 * NOTE: *path ought to be deallocated ('free(*path)') after
4294 * we're done with it, but since this routine is called just
4295 * before we exit, it doesn't really matter
4301 * verify_groupname(char *, int);
4303 * Check the group name for the following rules:
4304 * 1. The name does not start with a '-'
4305 * 2. The name does not contain any space characters as defined by
4306 * isspace(3C).
4307 * If either of these rules are broken, error immediately. The check for a
4308 * leading dash can be skipped if the 'testDash' argument is false. This is to
4309 * allow for the '-g -L' functionality.
4312 static void
4313 verify_groupname(char *grp, int testDash)
4315 int i;
4317 if (testDash && grp[0] == '-') {
4318 errno = EINVAL;
4319 dsw_error(gettext("group name cannot start with a '-'"), NULL);
4322 for (i = 0; grp[i] != '\0'; i++) {
4323 if (isspace(grp[i])) {
4324 errno = EINVAL;
4325 dsw_error(gettext("group name cannot contain a space"),
4326 NULL);
4331 void
4332 check_iishadow(char *shadow_vol) {
4333 int i;
4334 int entries;
4335 char **entry;
4336 char *shost;
4337 char *svol;
4338 char *buf;
4339 void *librdc;
4342 * See if librdc is around
4343 * If not, we can just return
4345 if (librdc = dlopen(RDC_LIB, RTLD_LAZY | RTLD_GLOBAL))
4346 self_check = (int (*)(char *)) dlsym(librdc, "self_check");
4347 else {
4348 return;
4351 entry = NULL;
4352 entries = cfg_get_section(cfg, &entry, "sndr");
4353 for (i = 0; i < entries; i++) {
4354 buf = entry[i];
4356 (void) strtok(buf, " "); /* phost */
4357 (void) strtok(NULL, " "); /* primary */
4358 (void) strtok(NULL, " "); /* pbitmap */
4359 shost = strtok(NULL, " "); /* shost */
4360 svol = strtok(NULL, " "); /* secondary */
4362 if (self_check(shost) && (strcmp(shadow_vol, svol) == 0)) {
4363 free(buf);
4364 if (entries)
4365 free(entry);
4366 errno = EINVAL;
4367 dsw_error(gettext(
4368 "shadow volume is in use as SNDR secondary volume"),
4369 NULL);
4371 free(buf);
4374 (void) dlclose(librdc);
4375 if (entries)
4376 free(entry);