1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
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>
50
51 #include <sys/nsctl/cfg.h>
52 #include <sys/nsctl/nsc_hash.h>
53
54 #include <sys/unistat/spcs_s.h>
55 #include <sys/unistat/spcs_s_u.h>
56 #include <sys/unistat/spcs_errors.h>
57 #include <sys/nsctl/dsw.h>
58 #include <sys/nsctl/dsw_dev.h> /* for bit map header format */
59
60 #include <sys/nskernd.h>
61
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;
72
73 #define DSW_TEXT_DOMAIN "II"
74
75 #include <dlfcn.h>
76 #define RDC_LIB "/usr/lib/librdc.so.1"
77 static int (*self_check)(char *);
78
79 /*
80 * Support for the special cluster tag "local" to be used with -C in a
81 * cluster for local volumes.
82 */
83 #define II_LOCAL_TAG "local"
84
85 #define II_NOT_CLUSTER 1
86 #define II_CLUSTER 2
87 #define II_CLUSTER_LCL 3
88
89 static char *cfg_cluster_tag = NULL;
90 static CFGFILE *cfg = NULL;
91
92 void sigterm(int sig);
93
94 #define SD_BIT_CLR(bmap, bit) (bmap &= ~(1 << bit))
95 #define SD_BIT_ISSET(bmap, bit) ((bmap & (1 << bit)) != 0)
96
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 */
100
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;
104
105 int dsw_fd;
106
107 #define LD_II 0x00000001
108 #define LD_DSVOLS 0x00000002
109 #define LD_SVOLS 0x00000004
110 #define LD_SHADOWS 0x00000008
111
112 static int reload_vols = 0;
113 static int config_locked = 0;
114 static int last_lock;
115
116 /*
117 * names for do_copy() flags.
118 */
119
120 enum copy_update {Copy = 0, Update};
121 enum copy_direction {ToShadow = 0, ToMaster};
122 enum copy_wait {WaitForStart = 0, WaitForEnd};
123
124 char *cmdnam;
125
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);
153
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 *);
181
182 extern char *optarg;
183 extern int optind, opterr, optopt;
184
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;
214
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;
225
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;
235
236 #ifdef lint
237 int
iiadm_lintmain(int argc,char * argv[])238 iiadm_lintmain(int argc, char *argv[])
239 #else
240 int
241 main(int argc, char *argv[])
242 #endif
243 {
244 int c;
245 int actions = 0;
246 int ac;
247 char *av[1024];
248
249 InitEnv();
250
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"));
268 }
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"));
290 }
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++;
301 }
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"));
321 }
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++;
388 }
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;
456 }
457 if (hflg) {
458 usage(NULL);
459 exit(0);
460 }
461
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"));
468
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;
477 }
478
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"));
483
484 /*
485 * Open configuration file.
486 */
487 if ((cfg = cfg_open(NULL)) == NULL) {
488 perror("unable to access configuration");
489 exit(2);
490 }
491
492 /*
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
503 */
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);
509 }
510 config_locked = 1;
511
512 /*
513 * If we are in a cluster, set or derive a valid disk group
514 */
515 switch (check_cluster()) {
516 case II_CLUSTER:
517 /*
518 * If in a Sun Cluster, can't Import an II shadow
519 * Must be done as -C local
520 */
521 if (Iflg)
522 dsw_error(gettext(
523 "-I (import) only allowed as -C local"), NULL);
524 /*FALLTHRU*/
525 case II_CLUSTER_LCL:
526 /*
527 * If a cluster tag was specified or derived, set it
528 */
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);
535 }
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);
545 }
546
547 /* preload the ii config */
548 load_ii_vols(cfg);
549 reload_vols |= LD_II;
550
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;
567
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;
587
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++];
613 }
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);
662 }
663 if (cfg)
664 cfg_close(cfg);
665
666 exit(0);
667 return (0);
668 }
669
670 static int
ii_lock(CFGFILE * cfg,int locktype)671 ii_lock(CFGFILE *cfg, int locktype)
672 {
673 last_lock = locktype;
674 return (cfg_lock(cfg, locktype));
675 }
676
677 static int
do_ioctl(int fd,int cmd,void * arg)678 do_ioctl(int fd, int cmd, void *arg)
679 {
680 int unlocked = 0;
681 int rc;
682 int save_errno;
683
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;
712
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;
725
726 default:
727 (void) fprintf(stderr,
728 "cfg locking needs to be set for %08x\n", cmd);
729 exit(1);
730 break;
731 }
732 }
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();
743 }
744 rc = ioctl(fd, cmd, arg);
745 save_errno = errno;
746 if (config_locked && unlocked) {
747 (void) cfg_lock(cfg, last_lock);
748 }
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);
759 }
760
761 errno = save_errno;
762 return (rc);
763 }
764
765 static int
get_dsw_config(int setno,dsw_config_t * parms)766 get_dsw_config(int setno, dsw_config_t *parms)
767 {
768 char buf[CFG_MAX_BUF];
769 char key[CFG_MAX_KEY];
770
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);
775
776 (void) snprintf(key, sizeof (key), "ii.set%d.shadow", setno);
777 (void) cfg_get_cstring(cfg, key, parms->shadow_vol, DSW_NAMELEN);
778
779 (void) snprintf(key, sizeof (key), "ii.set%d.bitmap", setno);
780 (void) cfg_get_cstring(cfg, key, parms->bitmap_vol, DSW_NAMELEN);
781
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;
786
787 (void) snprintf(key, sizeof (key), "ii.set%d.overflow", setno);
788 (void) cfg_get_cstring(cfg, key, last_overflow, DSW_NAMELEN);
789
790 (void) snprintf(key, sizeof (key), "ii.set%d.group", setno);
791 (void) cfg_get_cstring(cfg, key, parms->group_name, DSW_NAMELEN);
792
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);
796 }
797
798 static int
find_next_cf_line(char * volume,int next)799 find_next_cf_line(char *volume, int next)
800 {
801 dsw_config_t cf_line;
802
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);
809 }
810 return (0);
811 }
812 int
find_any_cf_line(char * volume)813 find_any_cf_line(char *volume)
814 {
815 return (find_next_cf_line(volume, 1));
816 }
817
818 static int
find_next_shadow_line(char * volume,int next)819 find_next_shadow_line(char *volume, int next)
820 {
821 dsw_config_t cf_line;
822
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);
827 }
828 return (0);
829 }
830 int
find_shadow_line(char * volume)831 find_shadow_line(char *volume)
832 {
833 return (find_next_shadow_line(volume, 1));
834 }
835
836 /*
837 * this function is designed to be called once, subsequent calls won't
838 * free memory allocated by earlier invocations.
839 */
840 char *
get_overflow_list()841 get_overflow_list()
842 {
843 dsw_aioctl_t *acopy_args;
844 int rc, num;
845
846 num = do_ioctl(dsw_fd, DSWIOC_OLISTLEN, NULL);
847 if (num < 0)
848 dsw_error(gettext("Can't get overflow list length"), NULL);
849
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);
853
854 acopy_args->count = num;
855 acopy_args->flags = 0;
856 acopy_args->status = spcs_s_ucreate();
857
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;
864
865 return (acopy_args->shadow_vol);
866 }
867
868 /*
869 * this function is designed to be called once, subsequent calls won't
870 * free memory allocated by earlier invocations.
871 */
872
873 int
find_group_members(char * group)874 find_group_members(char *group)
875 {
876 int nmembers = 0;
877 int vector_len = 0;
878
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,
883 sizeof (buf)) < 0)
884 break;
885
886 if (strcmp(group, buf))
887 continue;
888
889 (void) snprintf(key, sizeof (key), "ii.set%d.shadow",
890 setnumber);
891 if (cfg_get_cstring(cfg, key, buf,
892 sizeof (buf)) < 0)
893 break;
894
895 if (nmembers >= vector_len) {
896 vector_len += 10;
897 group_volumes = realloc(group_volumes, (1+vector_len) *
898 sizeof (char *));
899 }
900 group_volumes[nmembers] = strdup(buf);
901 nmembers++;
902 }
903 if (group_volumes)
904 group_volumes[nmembers] = NULL; /* terminate list */
905 return (nmembers);
906 }
907
908 static int
find_next_matching_cf_line(char * volume,dsw_config_t * conf,dsw_ioctl_t * io,int next)909 find_next_matching_cf_line(
910 char *volume, dsw_config_t *conf, dsw_ioctl_t *io, int next)
911 {
912 dsw_config_t config;
913
914 if (!find_next_cf_line(volume, next)) {
915 return (0);
916 }
917
918 if (conf == NULL)
919 conf = &config;
920 (void) get_dsw_config(setnumber, conf);
921 if (io) {
922 (void) strncpy(io->shadow_vol, conf->shadow_vol, DSW_NAMELEN);
923 io->shadow_vol[DSW_NAMELEN] = '\0';
924 }
925 return (1);
926 }
927
928 int
find_matching_cf_line(char * volume,dsw_config_t * conf,dsw_ioctl_t * io)929 find_matching_cf_line(char *volume, dsw_config_t *conf, dsw_ioctl_t *io)
930 {
931 return (find_next_matching_cf_line(volume, conf, io, 1));
932 }
933
934 int
find_shadow_config(char * volume,dsw_config_t * conf,dsw_ioctl_t * io)935 find_shadow_config(char *volume, dsw_config_t *conf, dsw_ioctl_t *io)
936 {
937 dsw_config_t *c, cf;
938
939 if (io) {
940 bzero(io, sizeof (dsw_ioctl_t));
941 }
942 c = conf ? conf : &cf;
943 setnumber = 1;
944 /* perform action for each line of the stored config file */
945 for ((void) snprintf(key, sizeof (key), "ii.set%d.shadow", setnumber);
946 cfg_get_cstring(cfg, key, c->shadow_vol, DSW_NAMELEN) >= 0;
947 (void) snprintf(key, sizeof (key), "ii.set%d.shadow",
948 ++setnumber)) {
949 if (strncmp(volume, c->shadow_vol, DSW_NAMELEN) == 0) {
950 (void) get_dsw_config(setnumber, c);
951
952 if (check_resource_group(c->bitmap_vol)) {
953 setnumber = 0;
954 continue;
955 }
956
957 switch (check_cluster()) {
958 case II_CLUSTER:
959 if ((cfg_cluster_tag) &&
960 (strcmp(cfg_cluster_tag, c->cluster_tag)))
961 continue;
962 break;
963 case II_CLUSTER_LCL:
964 if (strlen(c->cluster_tag))
965 continue;
966 break;
967 }
968
969 if (io) {
970 (void) strncpy(io->shadow_vol, c->shadow_vol,
971 DSW_NAMELEN);
972 io->shadow_vol[DSW_NAMELEN] = '\0';
973 }
974 return (1);
975 }
976 }
977 return (0);
978 }
979
980 void
add_cfg_entry(dsw_config_t * parms)981 add_cfg_entry(dsw_config_t *parms)
982 {
983 /* insert the well-known fields first */
984 (void) snprintf(buf, sizeof (buf), "%s %s %s %s",
985 parms->master_vol, parms->shadow_vol, parms->bitmap_vol,
986 (parms->flag & DSW_GOLDEN) ? "I" : "D");
987
988 if (cfg_put_cstring(cfg, "ii", buf, strlen(buf)) >= 0) {
989 /* if we have a group name, add it */
990 if (group_name) {
991 if (find_any_cf_line(parms->shadow_vol)) {
992 (void) sprintf(buf, "ii.set%d.group",
993 setnumber);
994 if (cfg_put_cstring(cfg, buf,
995 group_name, strlen(group_name)) < 0)
996 perror("cfg_put_cstring");
997 }
998 else
999 perror("cfg_location");
1000 }
1001
1002 /* commit the record */
1003 (void) cfg_commit(cfg);
1004 }
1005 else
1006 perror("cfg_put_string");
1007 }
1008
1009 void
remove_iiset(int setno,char * shadow,int shd_exp)1010 remove_iiset(int setno, char *shadow, int shd_exp)
1011 {
1012 mstcount_t *mdata;
1013 shdvol_t *sdata;
1014 char sn[CFG_MAX_BUF];
1015
1016 if (perform_autosv()) {
1017 if (volhash) {
1018 unload_ii_vols();
1019 }
1020 load_ii_vols(cfg);
1021 if (cfg_load_dsvols(cfg) < 0 || cfg_load_svols(cfg) < 0) {
1022 dsw_error(gettext("Unable to parse config file"), NULL);
1023 }
1024
1025 sdata = (shdvol_t *)nsc_lookup(volhash, shadow);
1026 if (sdata) {
1027 /*
1028 * Handle the normal cases of disabling a set that is
1029 * not an imported shadow volume
1030 */
1031 if (strcmp(sdata->master, II_IMPORTED_SHADOW)) {
1032 /*
1033 * Handle multiple-shadows of single master
1034 */
1035 mdata = (mstcount_t *)
1036 nsc_lookup(volhash, sdata->master);
1037 if ((mdata) && (mdata->count == 1)) {
1038 if (cfg_vol_disable(cfg, sdata->master,
1039 cfg_cluster_tag, "ii") < 0)
1040 dsw_error(gettext(
1041 "SV disable of master failed"),
1042 NULL);
1043 }
1044 }
1045
1046 /*
1047 * Handle disk group name of different shadow
1048 */
1049 if (shd_exp) {
1050 /*
1051 * If shadow is exported, then do nothing
1052 */
1053 /*EMPTY*/;
1054 } else if (cfg_cluster_tag &&
1055 strcmp(cfg_cluster_tag, "") &&
1056 cfg_dgname(shadow, sn, sizeof (sn)) &&
1057 strlen(sn) &&
1058 strcmp(sn, cfg_cluster_tag)) {
1059 /* reload disk group volumes */
1060 cfg_resource(cfg, sn);
1061 cfg_unload_dsvols();
1062 cfg_unload_svols();
1063 (void) cfg_load_dsvols(cfg);
1064 (void) cfg_load_svols(cfg);
1065 if (cfg_vol_disable(cfg, shadow, sn,
1066 "ii") < 0)
1067 dsw_error(gettext(
1068 "SV disable of shadow failed"),
1069 NULL);
1070 cfg_resource(cfg, cfg_cluster_tag);
1071 } else {
1072 if (cfg_vol_disable(cfg, shadow,
1073 cfg_cluster_tag, "ii") < 0)
1074 dsw_error(gettext(
1075 "SV disable of shadow failed"),
1076 NULL);
1077 }
1078 }
1079 cfg_unload_svols();
1080 cfg_unload_dsvols();
1081 unload_ii_vols();
1082 reload_vols &= ~(LD_SVOLS | LD_DSVOLS | LD_II);
1083 }
1084
1085 (void) sprintf(key, "ii.set%d", setno);
1086 if (cfg_put_cstring(cfg, key, NULL, 0) < 0) {
1087 perror("cfg_put_cstring");
1088 }
1089 (void) cfg_commit(cfg);
1090 }
1091
1092 /*
1093 * determine if we are running in a Sun Cluster Environment
1094 */
1095 int
check_cluster()1096 check_cluster()
1097 {
1098 static int is_cluster = -1;
1099 int rc;
1100 #ifdef DEBUG
1101 char *cdebug = getenv("II_SET_CLUSTER");
1102 #endif
1103
1104 /*
1105 * If this routine was previously called, just return results
1106 */
1107 if (is_cluster != -1)
1108 return (is_cluster);
1109
1110 /*
1111 * See if Sun Cluster was installed on this node
1112 */
1113 #ifdef DEBUG
1114 if (cdebug) rc = atoi(cdebug);
1115 else
1116 #endif
1117 rc = cfg_iscluster();
1118 if (rc > 0) {
1119 /*
1120 * Determine if user specified -C local
1121 */
1122 if ((cfg_cluster_tag == NULL) ||
1123 (strcmp(cfg_cluster_tag, II_LOCAL_TAG))) {
1124 /*
1125 * We're in a Sun Cluster, and no "-C local"
1126 */
1127 is_cluster = II_CLUSTER;
1128 } else {
1129 /*
1130 * We're in a Sun Cluster, but "-C local" was specified
1131 */
1132 is_cluster = II_CLUSTER_LCL;
1133 cfg_cluster_tag = "";
1134 }
1135 return (is_cluster);
1136 } else if (rc == 0) {
1137 /*
1138 * Not in a Sun Cluster
1139 */
1140 is_cluster = II_NOT_CLUSTER;
1141 return (is_cluster);
1142 } else {
1143 dsw_error(gettext("unable to ascertain environment"), NULL);
1144 /*NOTREACHED*/
1145 }
1146
1147 /* gcc */
1148 return (is_cluster);
1149 }
1150
1151 /*
1152 * Determine if we need to set a cfg_resource based on this volume
1153 */
1154 static int
check_resource_group(char * volume)1155 check_resource_group(char *volume)
1156 {
1157 char diskgroup[CFG_MAX_BUF];
1158
1159 /*
1160 * If we are in a cluster, attempt to derive a new resource group
1161 */
1162
1163 #ifdef DEBUG
1164 if (getenv("II_SET_CLUSTER") || (check_cluster() == II_CLUSTER)) {
1165 #else
1166 if (check_cluster() == II_CLUSTER) {
1167 #endif
1168 if (check_diskgroup(volume, diskgroup)) {
1169 if (cfg_cluster_tag == NULL) {
1170 cfg_cluster_tag = strdup(diskgroup);
1171 if (cfg_cluster_tag == NULL)
1172 dsw_error(gettext(
1173 "Memory allocation failure"), NULL);
1174 cfg_resource(cfg, cfg_cluster_tag);
1175 return (1);
1176 } else {
1177 /*
1178 * Check dgname and cluster tag from -C are the same.
1179 */
1180 if (strcmp(diskgroup, cfg_cluster_tag) != 0) {
1181 char error_buffer[128];
1182 (void) snprintf(error_buffer, sizeof (error_buffer),
1183 gettext(
1184 "-C (%s) does not match disk group "
1185 "name (%s) for %s"), cfg_cluster_tag,
1186 diskgroup, volume);
1187 spcs_log("ii", NULL, error_buffer);
1188 dsw_error(error_buffer, NULL);
1189 }
1190 }
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);
1197 }
1198 return (0);
1199 }
1200
1201 static void
1202 check_dg_is_local(char *dgname)
1203 {
1204 char error_buffer[128];
1205 char *othernode;
1206 int rc;
1207
1208 /*
1209 * check where this disk service is mastered
1210 */
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);
1222 }
1223 }
1224
1225 /*
1226 * Carry out cluster based checks for a specified volume, or just
1227 * global options.
1228 */
1229 static int
1230 check_diskgroup(char *path, char *result)
1231 {
1232 char dgname[CFG_MAX_BUF];
1233 char error_buffer[128];
1234
1235 #ifdef DEBUG
1236 char *override = getenv("II_CLUSTER_TAG");
1237 if (override) {
1238 (void) strcpy(result, override);
1239 return (1);
1240 }
1241 #endif
1242 /*
1243 * Check on path name, a returned NULL dgname is valid
1244 */
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);
1249 }
1250 if (strcmp(dgname, "") == 0)
1251 return (0);
1252
1253 /*
1254 * See if disk group is local to this node
1255 */
1256 check_dg_is_local(dgname);
1257
1258 /*
1259 * Copy dgname into result
1260 */
1261 (void) strcpy(result, dgname);
1262 return (1);
1263 }
1264
1265 /*
1266 * sigterm (): traps specified signal , usually termination one
1267 */
1268 void
1269 sigterm(int sig)
1270 {
1271 spcs_log("ii", NULL, gettext("%s received signal %d"), cmdnam, sig);
1272 exit(1);
1273 }
1274
1275 /*
1276 * sigchild; reap child and collect status.
1277 */
1278
1279 volatile pid_t dead_child;
1280 int dead_stat;
1281
1282 /*ARGSUSED*/
1283 void
1284 sigchild(int sig)
1285 {
1286 dead_child = wait(&dead_stat);
1287 }
1288
1289 /*
1290 * InitEnv(): initializes environment
1291 */
1292 void
1293 InitEnv()
1294 {
1295 (void) setlocale(LC_ALL, "");
1296 (void) textdomain(DSW_TEXT_DOMAIN);
1297
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
1313
1314 dsw_fd = open(DSWDEV, O_RDONLY);
1315 if (dsw_fd < 0) {
1316 perror(DSWDEV);
1317 exit(1);
1318 }
1319
1320 (void) setsid();
1321 }
1322
1323 /*
1324 * print an error message, followed by decoded errno then exit.
1325 */
1326 void
1327 dsw_error(char *str, spcs_s_info_t *status)
1328 {
1329 char *sp;
1330
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);
1338 }
1339 (void) fprintf(stderr, "%s\n", sp ? sp : "");
1340 } else {
1341 spcs_s_report(*status, stderr);
1342 spcs_s_ufree(status);
1343 }
1344 if (cfg)
1345 cfg_close(cfg);
1346 exit(2);
1347 }
1348
1349
1350 #undef size
1351
1352 void
1353 free_bitmap(unsigned char *bitmap)
1354 {
1355 free(bitmap);
1356 }
1357
1358
1359 int
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;
1365 {
1366 dsw_bitmap_t parms;
1367
1368 (void) strncpy(parms.shadow_vol, master_volume, DSW_NAMELEN);
1369 parms.shadow_vol[DSW_NAMELEN-1] = '\0';
1370 parms.shd_bitmap = shd_bitmap;
1371 parms.shd_size = size;
1372 parms.copy_bitmap = copy_bitmap;
1373 parms.copy_size = size;
1374
1375 return (do_ioctl(dsw_fd, DSWIOC_BITMAP, &parms));
1376 }
1377
1378 unsigned char *
1379 allocate_bitmap(char *shadow_volume)
1380 {
1381 unsigned char *shd_bitmap;
1382 unsigned char *copy_bitmap;
1383 unsigned char *p;
1384 unsigned char *q;
1385 int i;
1386 dsw_stat_t args;
1387 int stat_flags;
1388
1389 (void) strncpy(args.shadow_vol, shadow_volume, DSW_NAMELEN);
1390 args.shadow_vol[DSW_NAMELEN-1] = '\0';
1391
1392 args.status = spcs_s_ucreate();
1393 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1)
1394 dsw_error(gettext("Stat failed"), &args.status);
1395
1396 stat_flags = args.stat;
1397 if (stat_flags & DSW_BMPOFFLINE)
1398 return (NULL);
1399
1400 bm_size = args.size;
1401 bm_size = (bm_size + DSW_SIZE-1) / DSW_SIZE;
1402 bm_actual = bm_size;
1403 bm_size = (bm_size + DSW_BITS-1) / DSW_BITS;
1404 spcs_s_ufree(&args.status);
1405
1406 p = shd_bitmap = (unsigned char *) malloc(bm_size);
1407 if (!shd_bitmap) {
1408 perror(gettext("malloc bitmap"));
1409 return (NULL);
1410 }
1411
1412 q = copy_bitmap = (unsigned char *) malloc(bm_size);
1413 if (!copy_bitmap) {
1414 perror(gettext("malloc bitmap"));
1415 free(shd_bitmap);
1416 return (NULL);
1417 }
1418
1419 (void) memset(shd_bitmap, 0, bm_size);
1420 (void) memset(copy_bitmap, 0, bm_size);
1421
1422 if (get_bitmap(shadow_volume, shd_bitmap, copy_bitmap, bm_size) < 0) {
1423 free(copy_bitmap);
1424 free(shd_bitmap);
1425 return (NULL);
1426 }
1427
1428 /*
1429 * "or" the copy and shadow bitmaps together to return a composite
1430 * bitmap that contains the total set of differences between the
1431 * volumes.
1432 */
1433 for (i = bm_size; i-- > 0; /*CSTYLED*/)
1434 *p++ |= *q++;
1435
1436 free(copy_bitmap);
1437
1438 return (shd_bitmap);
1439 }
1440
1441 /*
1442 * print usage message and exit.
1443 */
1444 void
1445 usage(char *why)
1446 {
1447 if (why) {
1448 (void) fprintf(stderr, "%s: %s\n", cmdnam, why);
1449
1450 (void) fprintf(stderr, "%s\n",
1451 gettext("\nBrief summary:"));
1452 (void) fprintf(stderr, "%s\n",
1453 gettext("\t-e {ind|dep} master_vol shadow_vol "
1454 "bitmap_vol"));
1455 (void) fprintf(stderr, "%s\n",
1456 gettext("\t-[cu {s|m}] volume_set"));
1457 (void) fprintf(stderr, "%s\n",
1458 gettext("\t-i all"));
1459 (void) fprintf(stderr, "%s\n",
1460 gettext("\t-[adDEilPRw] volume_set"));
1461 (void) fprintf(stderr, "%s\n",
1462 gettext("\t-g group_name [options]"));
1463 (void) fprintf(stderr, "%s\n",
1464 gettext("\t-C cluster_tag [options]"));
1465 (void) fprintf(stderr, "%s\n",
1466 gettext("\t-[hilLv]"));
1467 (void) fprintf(stderr, "%s\n",
1468 gettext("\t-[IJ] volume_set bitmap"));
1469 (void) fprintf(stderr, "%s\n",
1470 gettext("\t-A overflow_vol volume_set"));
1471 (void) fprintf(stderr, "%s\n",
1472 gettext("\t-[OQ] overflow_vol"));
1473 (void) fprintf(stderr, "%s\n",
1474 gettext("\t-P {delay} {units} volume_set"));
1475
1476 /* assume we came here due to a user mistake */
1477 exit(1);
1478 /* NOTREACHED */
1479 } else {
1480
1481 (void) fprintf(stdout, "%s\n",
1482 gettext("Point-in-Time Copy Administrator CLI options"));
1483 (void) fprintf(stdout, "%s\n",
1484 gettext("Usage summary:"));
1485 (void) fprintf(stdout, "%s\n",
1486 gettext("\t-e ind m s b\tenable independent master shadow "
1487 "bitmap"));
1488 (void) fprintf(stdout, "%s\n",
1489 gettext("\t-e dep m s b\tenable dependent master shadow "
1490 "bitmap"));
1491 if (check_cluster() == II_CLUSTER)
1492 (void) fprintf(stdout, "%s\n",
1493 gettext("\t-ne ind m s b\tenable exportable master "
1494 "shadow bitmap"));
1495 (void) fprintf(stdout, "%s\n",
1496 gettext("\t-d v\t\tdisable volume"));
1497 (void) fprintf(stdout, "%s\n",
1498 gettext("\t-u s v\t\tupdate shadow volume"));
1499 (void) fprintf(stdout, "%s\n",
1500 gettext("\t-u m v\t\tupdate master volume"));
1501 (void) fprintf(stdout, "%s\n",
1502 gettext("\t-c s v\t\tcopy to shadow volume"));
1503 (void) fprintf(stdout, "%s\n",
1504 gettext("\t-c m v\t\tcopy to master volume"));
1505 (void) fprintf(stdout, "%s\n",
1506 gettext("\t-a v\t\tabort copy volume"));
1507 (void) fprintf(stdout, "%s\n",
1508 gettext("\t-w v\t\twait volume"));
1509 (void) fprintf(stdout, "%s\n",
1510 gettext("\t-i v\t\tdisplay volume status"));
1511 (void) fprintf(stdout, "%s\n",
1512 gettext("\t-i all\t\tdisplay all volume status"));
1513 (void) fprintf(stdout, "%s\n",
1514 gettext("\t-l\t\tlist all volumes"));
1515 (void) fprintf(stdout, "%s\n",
1516 gettext("\t-R v\t\treset volume"));
1517 (void) fprintf(stdout, "%s\n",
1518 gettext("\t-A o v\t\tattach overflow to volume"));
1519 (void) fprintf(stdout, "%s\n",
1520 gettext("\t-D v\t\tdetach overflow from volume"));
1521 (void) fprintf(stdout, "%s\n",
1522 gettext("\t-L\t\tlist all overflow volumes"));
1523 (void) fprintf(stdout, "%s\n",
1524 gettext("\t-O o\t\tinitialize overflow"));
1525 (void) fprintf(stdout, "%s\n",
1526 gettext("\t-Q o\t\tquery status of overflow"));
1527 (void) fprintf(stdout, "%s\n",
1528 gettext("\t-E v\t\texport shadow volume"));
1529 (void) fprintf(stdout, "%s\n",
1530 gettext("\t-I v b\t\timport volume bitmap"));
1531 (void) fprintf(stdout, "%s\n",
1532 gettext("\t-J v b\t\tjoin volume bitmap"));
1533 (void) fprintf(stdout, "%s\n",
1534 gettext("\t-P d u v\tset copy delay/units for volume"));
1535 (void) fprintf(stdout, "%s\n",
1536 gettext("\t-P v\t\tget copy delay/units for volume"));
1537 (void) fprintf(stdout, "%s\n",
1538 gettext("\t-C tag\t\tcluster resource tag"));
1539 #ifdef DEBUG
1540 (void) fprintf(stdout, "%s\n",
1541 gettext("\t-b v\t\tdisplay bitmap volume"));
1542 (void) fprintf(stdout, "%s\n",
1543 gettext("\t-f f\t\tuse private configuration file"));
1544 #endif
1545 (void) fprintf(stdout, "%s\n",
1546 gettext("\t-v\t\tprint software versions"));
1547 (void) fprintf(stdout, "%s\n",
1548 gettext("\t-n\t\tperform action without question"));
1549 (void) fprintf(stdout, "%s\n",
1550 gettext("\t-p [-c|-u] {m|s}"
1551 "enable PID locking on copy or update"));
1552 (void) fprintf(stdout, "%s\n",
1553 gettext("\t-p -w v\t\tdisable PID locking"));
1554 (void) fprintf(stdout, "%s\n",
1555 gettext("\t-h\t\tiiadm usage summary"));
1556 (void) fprintf(stdout, "%s\n",
1557 gettext("\nUsage summary for options that support "
1558 "grouping (-g g):"));
1559 (void) fprintf(stdout, "%s\n",
1560 gettext("\t-g g -e ind m s b group enable independent "
1561 "master shadow bitmap"));
1562 (void) fprintf(stdout, "%s\n",
1563 gettext("\t-g g -e dep m s b group enable dependent "
1564 "master shadow bitmap"));
1565 (void) fprintf(stdout, "%s\n",
1566 gettext("\t-g g -d\t\tdisable group"));
1567 (void) fprintf(stdout, "%s\n",
1568 gettext("\t-g g -u s\tupdate shadow for all volumes in "
1569 "group"));
1570 (void) fprintf(stdout, "%s\n",
1571 gettext("\t-g g -u m\tupdate master for all volumes in "
1572 "group"));
1573 (void) fprintf(stdout, "%s\n",
1574 gettext("\t-g g -c s\tcopy to shadow for all volumes in "
1575 "group"));
1576 (void) fprintf(stdout, "%s\n",
1577 gettext("\t-g g -c m\tcopy to master for all volumes in "
1578 "group"));
1579 (void) fprintf(stdout, "%s\n",
1580 gettext("\t-g g -a\t\tabort copy for all volumes in "
1581 "group"));
1582 (void) fprintf(stdout, "%s\n",
1583 gettext("\t-g g -w\t\twait for all volumes in group"));
1584 (void) fprintf(stdout, "%s\n",
1585 gettext("\t-g g -i\t\tdisplay status of all volumes in "
1586 "group"));
1587 (void) fprintf(stdout, "%s\n",
1588 gettext("\t-g g -l\t\tlist all volumes in group"));
1589 (void) fprintf(stdout, "%s\n",
1590 gettext("\t-g -L\t\tlist all groups"));
1591 (void) fprintf(stdout, "%s\n",
1592 gettext("\t-g g -m v v\tmove one or more volumes into "
1593 "group"));
1594 (void) fprintf(stdout, "%s\n",
1595 gettext("\t-g \"\" -m v\tremove volume from group"));
1596 (void) fprintf(stdout, "%s\n",
1597 gettext("\t-g g -R\t\treset all volumes in group"));
1598 (void) fprintf(stdout, "%s\n",
1599 gettext("\t-g g -A o\tattach overflow to all volumes in "
1600 "group"));
1601 (void) fprintf(stdout, "%s\n",
1602 gettext("\t-g g -D\t\tdetach overflow from all volumes in "
1603 "group"));
1604 (void) fprintf(stdout, "%s\n",
1605 gettext("\t-g g -E\t\texport shadow volume for all "
1606 "volumes in group"));
1607 (void) fprintf(stdout, "%s\n",
1608 gettext("\t-g g -P d u\tset copy delay/units for all "
1609 "volumes in group"));
1610 (void) fprintf(stdout, "%s\n",
1611 gettext("\t-g g -P\t\tget copy delay/units for all "
1612 "volumes in group"));
1613 (void) fprintf(stdout, "%s\n",
1614 gettext("\nLegend summary:"));
1615 (void) fprintf(stdout, "%s\n",
1616 gettext("\tind\t\tindependent volume set"));
1617 (void) fprintf(stdout, "%s\n",
1618 gettext("\tdep\t\tdependent volume set"));
1619 (void) fprintf(stdout, "%s\n",
1620 gettext("\tall\t\tall configured volumes"));
1621 (void) fprintf(stdout, "%s\n",
1622 gettext("\tm\t\tmaster volume"));
1623 (void) fprintf(stdout, "%s\n",
1624 gettext("\ts\t\tshadow volume"));
1625 (void) fprintf(stdout, "%s\n",
1626 gettext("\tv\t\tshadow volume (reference name)"));
1627 (void) fprintf(stdout, "%s\n",
1628 gettext("\to\t\toverflow volume"));
1629 (void) fprintf(stdout, "%s\n",
1630 gettext("\tb\t\tbitmap volume"));
1631 #ifdef DEBUG
1632 (void) fprintf(stdout, "%s\n",
1633 gettext("\tf\t\tconfiguration file name"));
1634 #endif
1635 (void) fprintf(stdout, "%s\n",
1636 gettext("\td\t\tdelay tick interval"));
1637 (void) fprintf(stdout, "%s\n",
1638 gettext("\tu\t\tunit size"));
1639 (void) fprintf(stdout, "%s\n",
1640 gettext("\tg\t\tgroup name"));
1641
1642 /* assume we came here because user request help text */
1643 exit(0);
1644 /* NOTREACHED */
1645 }
1646
1647 }
1648
1649 static char yeschr[MAX_LINE_SIZE + 2];
1650 static char nochr[MAX_LINE_SIZE + 2];
1651
1652 static int
1653 yes(void)
1654 {
1655 int i, b;
1656 char ans[MAX_LINE_SIZE + 1];
1657
1658 for (i = 0; /*CSTYLED*/; i++) {
1659 b = getchar();
1660 if (b == '\n' || b == '\0' || b == EOF) {
1661 if (i < MAX_LINE_SIZE)
1662 ans[i] = 0;
1663 break;
1664 }
1665 if (i < MAX_LINE_SIZE)
1666 ans[i] = b;
1667 }
1668 if (i >= MAX_LINE_SIZE) {
1669 i = MAX_LINE_SIZE;
1670 ans[MAX_LINE_SIZE] = 0;
1671 }
1672 if ((i == 0) || (strncmp(yeschr, ans, i))) {
1673 if (strncmp(nochr, ans, i) == 0)
1674 return (0);
1675 else if (strncmp(yeschr, ans, i) == 0)
1676 return (1);
1677 else {
1678 (void) fprintf(stderr, "%s %s/%s\n",
1679 gettext("You have to respond with"),
1680 yeschr, nochr);
1681 return (2);
1682 }
1683 }
1684 return (1);
1685 }
1686
1687 static int
1688 convert_int(char *str)
1689 {
1690 int result, rc;
1691 char *buf;
1692
1693 buf = (char *)calloc(strlen(str) + 256, sizeof (char));
1694 rc = sscanf(str, "%d%s", &result, buf);
1695
1696 if (rc != 1) {
1697 (void) sprintf(buf, gettext("'%s' is not a valid number"), str);
1698 /* dsw_error calls exit which frees 'buf' */
1699 errno = EINVAL;
1700 dsw_error(buf, NULL);
1701 }
1702 free(buf);
1703
1704 return (result);
1705 }
1706
1707 void
1708 check_action(char *will_happen)
1709 {
1710 int answer;
1711
1712 if (nflg || !isatty(fileno(stdin)))
1713 return;
1714 (void) strncpy(yeschr, nl_langinfo(YESSTR), MAX_LINE_SIZE + 1);
1715 (void) strncpy(nochr, nl_langinfo(NOSTR), MAX_LINE_SIZE + 1);
1716
1717 /*CONSTCOND*/
1718 while (1) {
1719 (void) printf("%s %s/%s ", will_happen, yeschr, nochr);
1720 answer = yes();
1721 if (answer == 1 || answer == 0)
1722 break;
1723 }
1724 if (answer == 1)
1725 return;
1726 exit(1);
1727 }
1728
1729 enum child_event {Status, CopyStart};
1730
1731 /*
1732 * Wait for child process to get to some state, where some state may be:
1733 *
1734 * Status Set up the shadow enough so that it responds
1735 * to status requests.
1736 * CopyStart Start copy/update operations.
1737 */
1738
1739 int
1740 child_wait(pid_t child, enum child_event event, char *volume)
1741 {
1742 dsw_stat_t args;
1743 int rc;
1744
1745 (void) strncpy(args.shadow_vol, volume, DSW_NAMELEN);
1746 args.shadow_vol[DSW_NAMELEN-1] = '\0';
1747
1748 for (; dead_child != child; (void) sleep(1)) {
1749
1750 /* poll shadow group with a status ioctl() */
1751 args.status = spcs_s_ucreate();
1752 errno = 0;
1753 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &args);
1754
1755 spcs_s_ufree(&args.status);
1756
1757 if (event == Status) {
1758 /* keep polling while we fail with DSW_ENOTFOUND */
1759 if (rc != -1 || errno != DSW_ENOTFOUND)
1760 return (0);
1761 } else {
1762 /* event == CopyStart */
1763 if (rc == -1) {
1764 return (1); /* something wrong */
1765 }
1766 if (args.stat & DSW_COPYINGP)
1767 return (0); /* copying underway */
1768 }
1769 }
1770 /* child died */
1771 if (WIFEXITED(dead_stat))
1772 return (WEXITSTATUS(dead_stat));
1773 else
1774 return (1);
1775 }
1776
1777 int
1778 mounted(char *t)
1779 {
1780 int rdsk;
1781 int i;
1782 FILE *mntfp;
1783 struct mnttab mntref;
1784 struct mnttab mntent;
1785 char target[DSW_NAMELEN];
1786 char *s;
1787
1788 rdsk = i = 0;
1789 for (s = target; i < DSW_NAMELEN && (*s = *t++); i++) {
1790 if (*s == 'r' && rdsk == 0)
1791 rdsk = 1;
1792 else
1793 s++;
1794 }
1795 *s = '\0';
1796
1797 mntref.mnt_special = target;
1798 mntref.mnt_mountp = NULL;
1799 mntref.mnt_fstype = NULL;
1800 mntref.mnt_mntopts = NULL;
1801 mntref.mnt_time = NULL;
1802
1803 if ((mntfp = fopen("/etc/mnttab", "r")) == NULL) {
1804 dsw_error(gettext("Can not check volume against mount table"),
1805 NULL);
1806 }
1807 if (getmntany(mntfp, &mntent, &mntref) != -1) {
1808 /* found something before EOF */
1809 (void) fclose(mntfp);
1810 return (1);
1811 }
1812 (void) fclose(mntfp);
1813 return (0);
1814 }
1815
1816 void
1817 enable(char *master_volume, char *shadow_volume,
1818 char *bitmap_volume, char *copy_type)
1819 {
1820 dsw_config_t parms;
1821 dsw_ioctl_t temp;
1822 char *p;
1823 int rc;
1824 pid_t child;
1825 spcs_s_info_t *sp_info;
1826 struct stat mstat, sstat, bstat;
1827 char mst_dg[DSW_NAMELEN] = {0};
1828 char shd_dg[DSW_NAMELEN] = {0};
1829 char bmp_dg[DSW_NAMELEN] = {0};
1830 int mvol_enabled;
1831 char *altname;
1832 grptag_t *gdata;
1833
1834 bzero(&parms, sizeof (dsw_config_t));
1835
1836 if (strcmp(copy_type, "independent") == 0 ||
1837 strcmp(copy_type, gettext("independent")) == 0)
1838 parms.flag = DSW_GOLDEN;
1839 else if (strcmp(copy_type, "dependent") == 0 ||
1840 strcmp(copy_type, gettext("dependent")) == 0)
1841 parms.flag = 0;
1842 else
1843 dsw_error(gettext("don't understand shadow type"), NULL);
1844
1845 /* validate volume names */
1846 if (perform_autosv()) {
1847 if (cfg_load_svols(cfg) < 0 || cfg_load_dsvols(cfg) < 0 ||
1848 cfg_load_shadows(cfg) < 0) {
1849 dsw_error(gettext("Unable to parse config file"), NULL);
1850 }
1851 load_ii_vols(cfg);
1852 reload_vols = LD_SVOLS | LD_DSVOLS | LD_SHADOWS | LD_II;
1853
1854 /* see if it's been used before under a different name */
1855 conform_name(&master_volume);
1856 conform_name(&shadow_volume);
1857 rc = cfg_get_canonical_name(cfg, bitmap_volume, &altname);
1858 if (rc < 0) {
1859 dsw_error(gettext("Unable to parse config file"), NULL);
1860 }
1861 if (rc) {
1862 errno = EBUSY;
1863 dsw_error(gettext("Bitmap in use"), NULL);
1864 }
1865 }
1866
1867 /*
1868 * If not local, determine disk group names for volumes in II set
1869 */
1870 switch (check_cluster()) {
1871 case II_CLUSTER:
1872 /*
1873 * Check if none or all volumes are in a disk group
1874 */
1875 rc = 0;
1876 if (check_diskgroup(master_volume, mst_dg)) rc++;
1877 if (check_diskgroup(shadow_volume, shd_dg)) rc++;
1878 if (check_diskgroup(bitmap_volume, bmp_dg)) rc++;
1879 if ((rc != 0) && (rc != 3))
1880 dsw_error(gettext(
1881 "Not all Point-in-Time Copy volumes are "
1882 "in a disk group"), NULL);
1883
1884 /*
1885 * If volumes are not in a disk group, but are in a
1886 * cluster, then "-C <tag>", must be set
1887 */
1888 if (rc == 0 && cfg_cluster_tag == NULL)
1889 dsw_error(gettext(
1890 "Point-in-Time Copy volumes, that are not "
1891 "in a device group which has been "
1892 "registered with SunCluster, "
1893 "require usage of \"-C\""), NULL);
1894
1895 /*
1896 * the same disk group
1897 * If -n, plus mst_dg==bmp_dg, then allow E/I/J in SunCluster
1898 */
1899 if ((strcmp(mst_dg, bmp_dg)) ||
1900 (strcmp(mst_dg, shd_dg) && (!nflg)))
1901 dsw_error(gettext(
1902 "Volumes are not in same disk group"), NULL);
1903
1904 /*
1905 * Can never enable the same shadow twice, regardless of
1906 * exportable shadow device group movement
1907 */
1908 if (find_shadow_line(shadow_volume))
1909 dsw_error(gettext(
1910 "Shadow volume is already configured"), NULL);
1911
1912 /*
1913 * Groups cannot span multiple clusters
1914 */
1915 if (group_name && perform_autosv()) {
1916 gdata = (grptag_t *)nsc_lookup(volhash, group_name);
1917 if (gdata &&
1918 strncmp(gdata->ctag, mst_dg, DSW_NAMELEN) != 0) {
1919 errno = EINVAL;
1920 dsw_error(gettext("Group contains sets not "
1921 "in the same cluster resource"), NULL);
1922 }
1923 }
1924
1925 /*
1926 * Check cluster tag and bitmap disk group
1927 * set latter if different
1928 */
1929 if (check_resource_group(bitmap_volume)) {
1930 /*
1931 * Unload and reload in the event cluster tag has
1932 * changed
1933 */
1934 if (perform_autosv()) {
1935 unload_ii_vols();
1936 cfg_unload_shadows();
1937 cfg_unload_dsvols();
1938 cfg_unload_svols();
1939 if (cfg_load_svols(cfg) < 0 ||
1940 cfg_load_dsvols(cfg) < 0 ||
1941 cfg_load_shadows(cfg) < 0) {
1942 dsw_error(gettext(
1943 "Unable to parse config "
1944 "file"), NULL);
1945 }
1946 load_ii_vols(cfg);
1947 }
1948 }
1949 /*
1950 * Copy cluster name into config
1951 */
1952 (void) strncpy(parms.cluster_tag, cfg_cluster_tag, DSW_NAMELEN);
1953 break;
1954
1955 case II_CLUSTER_LCL:
1956 /* ensure that the -C local won't interfere with the set */
1957 if (group_name && perform_autosv()) {
1958 gdata = (grptag_t *)nsc_lookup(volhash, group_name);
1959 if (gdata) {
1960 if (strlen(gdata->ctag) != 0) {
1961 errno = EINVAL;
1962 dsw_error(gettext("Unable to put set "
1963 "into -C local and specified "
1964 "group"), NULL);
1965 }
1966 }
1967 }
1968 break;
1969 }
1970
1971 /*
1972 * If we've got a group name, add it into the config
1973 */
1974 if (group_name) {
1975 (void) strncpy(parms.group_name, group_name, DSW_NAMELEN);
1976 }
1977
1978 /*
1979 * Determine accessability of volumes
1980 */
1981 if (stat(master_volume, &mstat) != 0)
1982 dsw_error(gettext(
1983 "Unable to access master volume"), NULL);
1984 if (!S_ISCHR(mstat.st_mode))
1985 dsw_error(gettext(
1986 "Master volume is not a character device"), NULL);
1987 /* check the shadow_vol hasn't be used as SNDR secondary vol */
1988 check_iishadow(shadow_volume);
1989 if (stat(shadow_volume, &sstat) != 0)
1990 dsw_error(gettext(
1991 "Unable to access shadow volume"), NULL);
1992 if (!S_ISCHR(sstat.st_mode))
1993 dsw_error(gettext(
1994 "Shadow volume is not a character device"), NULL);
1995 if (mounted(shadow_volume)) {
1996 errno = EBUSY;
1997 dsw_error(gettext(
1998 "Shadow volume is mounted, unmount it first"), NULL);
1999 }
2000 if (mstat.st_rdev == sstat.st_rdev) {
2001 errno = EINVAL;
2002 dsw_error(gettext(
2003 "Master and shadow are the same device"), NULL);
2004 }
2005 if (stat(bitmap_volume, &bstat) != 0) {
2006 dsw_error(gettext("Unable to access bitmap"), NULL);
2007 }
2008 if (!S_ISCHR(bstat.st_mode))
2009 dsw_error(gettext(
2010 "Bitmap volume is not a character device"), NULL);
2011 if (S_ISCHR(bstat.st_mode)) {
2012 if (mstat.st_rdev == bstat.st_rdev) {
2013 errno = EINVAL;
2014 dsw_error(gettext(
2015 "Master and bitmap are the same device"), NULL);
2016 } else if (sstat.st_rdev == bstat.st_rdev) {
2017 errno = EINVAL;
2018 dsw_error(gettext(
2019 "Shadow and bitmap are the same device"), NULL);
2020 }
2021 }
2022
2023 (void) strncpy(parms.master_vol, master_volume, DSW_NAMELEN);
2024 (void) strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
2025 (void) strncpy(parms.bitmap_vol, bitmap_volume, DSW_NAMELEN);
2026 errno = 0;
2027 parms.status = spcs_s_ucreate();
2028
2029 /*
2030 * Check that none of the member volumes forms part of another
2031 * InstantImage group.
2032 *
2033 * -- this check has been removed; it is done in the kernel instead
2034 * -- PJW
2035 */
2036
2037 /*
2038 * Check against overflow volumes
2039 */
2040 for (p = get_overflow_list(); *p != NULL; p += DSW_NAMELEN) {
2041 if (strncmp(master_volume, p, DSW_NAMELEN) == 0)
2042 dsw_error(gettext(
2043 "Master volume is already an overflow volume"),
2044 NULL);
2045 else if (strncmp(shadow_volume, p, DSW_NAMELEN) == 0)
2046 dsw_error(gettext(
2047 "Shadow volume is already an overflow volume"),
2048 NULL);
2049 else if (strncmp(bitmap_volume, p, DSW_NAMELEN) == 0)
2050 dsw_error(gettext(
2051 "Bitmap volume is already an overflow volume"),
2052 NULL);
2053 }
2054
2055 /*
2056 * Make sure that the shadow volume is not already configured
2057 */
2058 if (find_shadow_config(shadow_volume, NULL, &temp))
2059 dsw_error(gettext(
2060 "Shadow volume is already configured"), NULL);
2061 if (perform_autosv()) {
2062 /*
2063 * parse the dsvol entries to see if we need to place
2064 * the master or shadow under SV control
2065 */
2066 if (nsc_lookup(volhash, master_volume) == NULL) {
2067 if (cfg_vol_enable(cfg, master_volume, cfg_cluster_tag,
2068 "ii") < 0) {
2069 dsw_error(
2070 gettext("Cannot enable master volume"),
2071 NULL);
2072 }
2073 mvol_enabled = 1;
2074 } else {
2075 mvol_enabled = 0;
2076 }
2077 if (nsc_lookup(volhash, shadow_volume) == NULL) {
2078 if (nflg) {
2079 cfg_resource(cfg, shd_dg);
2080 rc = cfg_vol_enable(cfg, shadow_volume,
2081 shd_dg, "ii");
2082 cfg_resource(cfg, cfg_cluster_tag);
2083 } else {
2084 rc = cfg_vol_enable(cfg, shadow_volume,
2085 cfg_cluster_tag, "ii");
2086 }
2087 if (rc < 0) {
2088 if (mvol_enabled) {
2089 if (cfg_vol_disable(cfg,
2090 master_volume, cfg_cluster_tag,
2091 "ii") < 0)
2092 dsw_error(gettext(
2093 "SV disable of master failed"),
2094 NULL);
2095 }
2096 dsw_error(
2097 gettext("Cannot enable shadow volume"),
2098 NULL);
2099 }
2100 }
2101 unload_ii_vols();
2102 cfg_unload_shadows();
2103 cfg_unload_dsvols();
2104 cfg_unload_svols();
2105 reload_vols = 0;
2106 }
2107
2108 add_cfg_entry(&parms);
2109 cfg_unlock(cfg);
2110 config_locked = 0;
2111
2112 (void) sigset(SIGCHLD, sigchild);
2113 switch (child = fork()) {
2114
2115 case (pid_t)-1:
2116 dsw_error(gettext("Unable to fork"), NULL);
2117 break;
2118
2119 case 0:
2120 rc = do_ioctl(dsw_fd, DSWIOC_ENABLE, &parms);
2121 if (rc == -1 && errno != DSW_EABORTED && errno != DSW_EIO) {
2122 /*
2123 * Failed to enable shadow group, log problem and remove
2124 * the shadow group from the config file.
2125 */
2126 spcs_log("ii", &parms.status,
2127 gettext("Enable failed %s %s %s (%s)"),
2128 master_volume, shadow_volume, bitmap_volume,
2129 parms.flag & DSW_GOLDEN ?
2130 "independent" : "dependent");
2131
2132 if (!ii_lock(cfg, CFG_WRLOCK) ||
2133 !find_shadow_config(shadow_volume, NULL, &temp)) {
2134 dsw_error(gettext(
2135 "Enable failed, can't tidy up cfg"),
2136 &parms.status);
2137 }
2138 config_locked = 1;
2139 remove_iiset(setnumber, shadow_volume, 0);
2140 dsw_error(gettext("Enable failed"), &parms.status);
2141 }
2142
2143 if (rc == -1)
2144 sp_info = &parms.status;
2145 else
2146 sp_info = NULL;
2147 spcs_log("ii", sp_info, gettext("Enabled %s %s %s (%s)"),
2148 master_volume, shadow_volume, bitmap_volume,
2149 parms.flag & DSW_GOLDEN ? "independent" : "dependent");
2150 spcs_s_ufree(&parms.status);
2151 break;
2152
2153 default:
2154 exit(child_wait(child, Status, shadow_volume));
2155 break;
2156 }
2157 }
2158
2159 int
2160 reset(char *volume)
2161 {
2162 dsw_ioctl_t args;
2163 dsw_config_t parms;
2164 int rc;
2165 int wait_loc;
2166 pid_t child = (pid_t)0;
2167 enum copy_wait wait_action;
2168 spcs_s_info_t *stat;
2169 dsw_stat_t prev_stat;
2170 int stat_flags;
2171 static int unlocked = 0;
2172 int do_enable = 0;
2173 char key[CFG_MAX_KEY];
2174 char optval[CFG_MAX_BUF];
2175 unsigned int flags;
2176
2177 wait_action = WaitForStart;
2178
2179 if (unlocked && !ii_lock(cfg, CFG_RDLOCK)) {
2180 dsw_error(gettext("Unable to set locking on the configuration"),
2181 NULL);
2182 }
2183 config_locked = 1;
2184 if (!find_shadow_config(volume, &parms, &args))
2185 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2186 "group"), NULL);
2187
2188 cfg_unlock(cfg);
2189 config_locked = 0;
2190 unlocked = 1;
2191
2192 spcs_log("ii", NULL, gettext("Start reset %s"), volume);
2193 (void) strncpy(prev_stat.shadow_vol, volume, DSW_NAMELEN);
2194 prev_stat.shadow_vol[DSW_NAMELEN - 1] = '\0';
2195 prev_stat.status = spcs_s_ucreate();
2196 if (do_ioctl(dsw_fd, DSWIOC_STAT, &prev_stat) == -1) {
2197 /* set is suspended, so we do the enable processing instead */
2198 do_enable = 1;
2199
2200 /* first check to see whether the set was offline */
2201 (void) snprintf(key, CFG_MAX_KEY, "ii.set%d.options",
2202 setnumber);
2203 if (!ii_lock(cfg, CFG_RDLOCK)) {
2204 dsw_error(gettext("Unable to set locking on the "
2205 "configuration"), NULL);
2206 }
2207 config_locked = 1;
2208 unlocked = 0;
2209 if (cfg_get_single_option(cfg, CFG_SEC_CONF, key,
2210 NSKERN_II_BMP_OPTION, optval, CFG_MAX_BUF) < 0) {
2211 dsw_error(gettext("unable to read config file"), NULL);
2212 }
2213 cfg_unlock(cfg);
2214 config_locked = 0;
2215 unlocked = 1;
2216 (void) sscanf(optval, "%x", &flags);
2217 if ((flags & DSW_OFFLINE) == 0) {
2218 /* set wasn't offline - don't reset */
2219 dsw_error(gettext("Set not offline, will not reset"),
2220 NULL);
2221 }
2222 parms.status = spcs_s_ucreate();
2223 stat = &parms.status;
2224 stat_flags = DSW_BMPOFFLINE;
2225 } else {
2226 args.status = spcs_s_ucreate();
2227 stat = &args.status;
2228 stat_flags = prev_stat.stat;
2229 }
2230 spcs_s_ufree(&prev_stat.status);
2231
2232 if (wait_action == WaitForStart)
2233 (void) sigset(SIGCHLD, sigchild);
2234
2235 switch (child = fork()) {
2236
2237 case (pid_t)-1:
2238 dsw_error(gettext("Unable to fork"), NULL);
2239 break;
2240
2241 case 0:
2242 if (do_enable) {
2243 rc = do_ioctl(dsw_fd, DSWIOC_ENABLE, &parms);
2244 } else {
2245 rc = do_ioctl(dsw_fd, DSWIOC_RESET, &args);
2246 }
2247 if (rc == -1 && errno != DSW_EABORTED && errno != DSW_EIO) {
2248 spcs_log("ii", stat, gettext("Fail reset %s"), volume);
2249 dsw_error(gettext("Reset shadow failed"), stat);
2250 }
2251 /* last_overflow is set during find_shadow_config */
2252 if (strlen(last_overflow) > 0 &&
2253 (stat_flags & (DSW_SHDOFFLINE | DSW_BMPOFFLINE)) != 0) {
2254 /* reattach it */
2255 (void) strncpy(parms.bitmap_vol, last_overflow,
2256 DSW_NAMELEN);
2257 do_attach(&parms);
2258 }
2259 spcs_log("ii", stat, gettext("Finish reset %s"), volume);
2260 spcs_s_ufree(stat);
2261
2262 exit(0);
2263 break;
2264 default:
2265 if (wait_action == WaitForStart) {
2266 rc = child_wait(child, CopyStart, args.shadow_vol);
2267 } else { /* wait_action == WaitForEnd */
2268 wait_loc = 0;
2269 (void) wait(&wait_loc);
2270 if (WIFEXITED(wait_loc) && (WEXITSTATUS(wait_loc) == 0))
2271 rc = 0;
2272 else
2273 rc = -1;
2274 }
2275 break;
2276 }
2277 /* if successful, remove flags entry from options field */
2278 if (rc >= 0) {
2279 if (!ii_lock(cfg, CFG_WRLOCK)) {
2280 dsw_error(gettext("Unable to set locking on the "
2281 "configuration"), NULL);
2282 }
2283 config_locked = 1;
2284 if (!find_shadow_config(volume, &parms, &args)) {
2285 dsw_error(gettext("Volume is not in a Point-in-Time "
2286 "Copy group"), NULL);
2287 }
2288 (void) snprintf(key, CFG_MAX_KEY, "ii.set%d.options",
2289 setnumber);
2290 if (cfg_del_option(cfg, CFG_SEC_CONF, key, NSKERN_II_BMP_OPTION)
2291 < 0) {
2292 dsw_error(gettext("Update of config failed"), NULL);
2293 }
2294 (void) cfg_commit(cfg);
2295 cfg_unlock(cfg);
2296 config_locked = 0;
2297 }
2298
2299 return (rc);
2300 }
2301
2302 int
2303 overflow(char *volume)
2304 {
2305 dsw_ioctl_t args;
2306 int rc;
2307 spcs_s_info_t *stat;
2308
2309 check_action(gettext("Initialize this overflow volume?"));
2310 if (find_matching_cf_line(volume, NULL, &args))
2311 dsw_error(gettext("Volume is part of a Point-in-Time Copy "
2312 "group"), NULL);
2313 args.status = spcs_s_ucreate();
2314 (void) strncpy(args.shadow_vol, volume, DSW_NAMELEN);
2315 rc = do_ioctl(dsw_fd, DSWIOC_OCREAT, &args);
2316 if (rc == -1) {
2317 spcs_log("ii", &args.status,
2318 gettext("Create overflow failed %s"), volume);
2319 dsw_error(gettext("Create overflow failed"), &args.status);
2320 }
2321 if (rc == -1)
2322 stat = &args.status;
2323 else
2324 stat = NULL;
2325 spcs_log("ii", stat, gettext("Create overflow succeeded %s"), volume);
2326 spcs_s_ufree(&args.status);
2327
2328 return (0);
2329 }
2330
2331 void
2332 bitmap_op(char *master_volume, int print_bitmap, int bitmap_percent, int used,
2333 int is_compact)
2334 {
2335 unsigned char *bitmap;
2336 char *name;
2337 int i, x, y;
2338 unsigned j;
2339 unsigned long n;
2340 unsigned long percent;
2341
2342 bitmap = allocate_bitmap(master_volume);
2343 if (bitmap == NULL)
2344 return;
2345
2346 if (bitmap_percent) {
2347 /* count the number of bits set in bitmap */
2348 for (i = n = 0; i < bm_size; i++)
2349 for (j = (unsigned)bitmap[i]; j; j &= j -1)
2350 n++;
2351 if (is_compact)
2352 (void) printf(gettext("Chunks in map: %d used: %d\n"),
2353 used, n);
2354 if (bm_actual < 100) {
2355 percent = 0;
2356 } else {
2357 percent = (n * 100) / bm_actual;
2358 }
2359 (void) printf(gettext("Percent of bitmap set: %u\n"), percent);
2360 percent = percent/100;
2361 /* distinguish between 0.0000% and 0.n% of bitmap set */
2362 if (percent < 1)
2363 (void) printf("\t(%s)\n", n > 0 ?
2364 gettext("bitmap dirty") : gettext("bitmap clean"));
2365 }
2366
2367 if (print_bitmap) {
2368 name = strrchr(master_volume, '/');
2369 if (name++ == NULL)
2370 name = master_volume;
2371 i = bm_size * 8;
2372 x = (int)ceil(sqrt((double)i));
2373 x += (8 - (x % 8)); /* round up to nearest multiple of 8 */
2374 y = i / x;
2375 if (y * x < i)
2376 y++;
2377 (void) printf("#define bm%s_width %d\n#define bm%s_height %d\n",
2378 name, x, name, y);
2379 (void) printf("#define bm%s_x_hot 0\n#define bm%s_y_hot 0\n",
2380 name, name);
2381 (void) printf("static char bm%s_bits[] = {\n", name);
2382 for (i = 0; i < bm_size; i++) {
2383 if (i % 12 == 0)
2384 (void) printf("\n");
2385 (void) printf("0x%02x, ", bitmap[i]);
2386 }
2387 y = x * y;
2388 for (; i < y; i++) {
2389 if (i % 12 == 0)
2390 (void) printf("\n");
2391 (void) printf("0x00, ");
2392 }
2393 (void) printf("\n};\n");
2394 }
2395
2396 free_bitmap(bitmap);
2397 }
2398
2399 static int
2400 validate_group_names(char **vol_list, char *group)
2401 {
2402 ENTRY item, *found;
2403 int i, rc, count;
2404 dsw_aioctl_t *group_list;
2405 char *ptr;
2406
2407 if (group == NULL || *group == NULL) {
2408 /* no group set, just count volume list */
2409 for (i = 0; *vol_list++ != NULL; i++)
2410 ;
2411 return (i);
2412 }
2413
2414 if ((count = do_ioctl(dsw_fd, DSWIOC_LISTLEN, NULL)) < 0)
2415 dsw_error("DSWIOC_LISTLEN", NULL);
2416
2417 group_list = malloc(sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
2418 if (group_list == NULL)
2419 dsw_error(gettext("Failed to allocate memory"), NULL);
2420
2421 bzero(group_list, sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
2422 group_list->count = count;
2423 group_list->flags = 0;
2424 group_list->status = spcs_s_ucreate();
2425 (void) strncpy(group_list->shadow_vol, group, DSW_NAMELEN);
2426
2427 rc = do_ioctl(dsw_fd, DSWIOC_GLIST, group_list);
2428 if (rc < 0)
2429 dsw_error(gettext("Group list access failure"),
2430 &group_list->status);
2431
2432 group_list->shadow_vol[DSW_NAMELEN * group_list->count] = '\0';
2433
2434 /* create hash and enter all volumes into it */
2435 if (hcreate(group_list->count) == 0)
2436 dsw_error(gettext("Failed to allocate memory"), NULL);
2437 ptr = group_list->shadow_vol;
2438 count = group_list->count;
2439 i = 0;
2440 while (i < count) {
2441 ptr[ DSW_NAMELEN - 1 ] = '\0';
2442 item.key = ptr;
2443 item.data = (void *) 0;
2444 (void) hsearch(item, ENTER);
2445 ++i;
2446 ptr += DSW_NAMELEN;
2447 }
2448
2449 /* now compare the volume list with the hash */
2450 for (i = 0; vol_list[ i ]; i++) {
2451 item.key = vol_list[ i ];
2452 found = hsearch(item, FIND);
2453 if (!found)
2454 dsw_error(gettext("Group config does not match kernel"),
2455 NULL);
2456 if (found->data != (void *) 0)
2457 dsw_error(gettext("Duplicate volume specified"), NULL);
2458 found->data = (void *) 1;
2459 }
2460 if (i != count)
2461 dsw_error(gettext("Group config does not match kernel"), NULL);
2462
2463 /* everything checks out */
2464 free(group_list);
2465 hdestroy();
2466
2467 return (count);
2468 }
2469
2470 int
2471 do_acopy(char **vol_list, enum copy_update update_mode,
2472 enum copy_direction direction)
2473 {
2474 dsw_aioctl_t *acopy_args;
2475 dsw_ioctl_t copy_args;
2476 dsw_config_t parms;
2477 dsw_stat_t stat_s;
2478 int i;
2479 int rc;
2480 int n_vols;
2481 char *t;
2482 char buf[1024];
2483 char *sp;
2484 char *ppid;
2485
2486 n_vols = validate_group_names(vol_list, group_name);
2487
2488 acopy_args = calloc(sizeof (dsw_aioctl_t) + n_vols * DSW_NAMELEN, 1);
2489 if (acopy_args == NULL)
2490 dsw_error(gettext("Too many volumes given for update"), NULL);
2491
2492 acopy_args->count = n_vols;
2493
2494 acopy_args->flags = 0;
2495
2496 if (update_mode == Update)
2497 acopy_args->flags |= CV_BMP_ONLY;
2498 if (direction == ToMaster)
2499 acopy_args->flags |= CV_SHD2MST;
2500 if (pflg) {
2501 acopy_args->flags |= CV_LOCK_PID;
2502 #ifdef DEBUG
2503 ppid = getenv("IIADM_PPID");
2504 if (ppid) {
2505 acopy_args->pid = atoi(ppid);
2506 (void) fprintf(stderr, "(using %s for ppid)\n", ppid);
2507 } else {
2508 acopy_args->pid = getppid();
2509 }
2510 #else
2511 acopy_args->pid = getppid();
2512 #endif
2513 }
2514
2515 for (i = 0; i < n_vols; i++) {
2516 if (!find_shadow_config(vol_list[i], &parms, ©_args))
2517 dsw_error(gettext("Volume is not in a Point-in-Time "
2518 "group"), NULL);
2519 if (direction == ToMaster) {
2520 t = parms.master_vol;
2521 } else {
2522 t = parms.shadow_vol;
2523 }
2524
2525 if (mounted(t)) {
2526 errno = EBUSY;
2527 dsw_error(gettext("Target of copy/update is mounted, "
2528 "unmount it first"), NULL);
2529 }
2530
2531 (void) strncpy(stat_s.shadow_vol, parms.shadow_vol,
2532 DSW_NAMELEN);
2533 stat_s.shadow_vol[DSW_NAMELEN-1] = '\0';
2534 stat_s.status = spcs_s_ucreate();
2535 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &stat_s);
2536 spcs_s_ufree(&stat_s.status);
2537 if (rc == -1) {
2538 (void) sprintf(buf,
2539 gettext("Shadow group %s is suspended"),
2540 vol_list[i]);
2541 dsw_error(buf, NULL);
2542 }
2543
2544 if (stat_s.stat & DSW_COPYINGP) {
2545 (void) fprintf(stderr, "%s: %s\n", cmdnam,
2546 gettext("Copy already in progress"));
2547 exit(1);
2548 }
2549 }
2550 acopy_args->status = spcs_s_ucreate();
2551 for (i = 0; i < n_vols; i++) {
2552 spcs_log("ii", NULL, gettext("Atomic %s %s %s"),
2553 update_mode == Update ?
2554 gettext("update") : gettext("copy"),
2555 vol_list[i],
2556 direction == ToMaster ? gettext("from shadow") :
2557 gettext("to shadow"));
2558 }
2559 if (group_name == NULL || *group_name == NULL) {
2560 sp = acopy_args->shadow_vol;
2561 for (i = 0; i < n_vols; i++, sp += DSW_NAMELEN)
2562 (void) strncpy(sp, vol_list[i], DSW_NAMELEN);
2563 } else {
2564 (void) strncpy(acopy_args->shadow_vol, group_name, DSW_NAMELEN);
2565 acopy_args->flags |= CV_IS_GROUP;
2566 }
2567 rc = do_ioctl(dsw_fd, DSWIOC_ACOPY, acopy_args);
2568 if (rc == -1) {
2569 i = acopy_args->count;
2570 if (i < 0 || i >= n_vols) {
2571 spcs_log("ii", NULL, gettext("Atomic update failed"));
2572 (void) sprintf(buf, gettext("Update failed"));
2573 } else {
2574 spcs_log("ii", NULL,
2575 gettext("Atomic update of %s failed"),
2576 vol_list[acopy_args->count]);
2577 (void) sprintf(buf, gettext("Update of %s failed"),
2578 vol_list[acopy_args->count]);
2579 }
2580 dsw_error(buf, &(acopy_args->status));
2581 }
2582 return (rc);
2583 }
2584
2585 int
2586 do_copy(char **vol_list, enum copy_update update_mode,
2587 enum copy_direction direction, enum copy_wait wait_action)
2588 {
2589 dsw_ioctl_t copy_args;
2590 dsw_config_t parms;
2591 dsw_stat_t stat_s;
2592 int rc;
2593 int wait_loc;
2594 char *t;
2595 char *volume;
2596 pid_t child = (pid_t)0;
2597 char *ppid;
2598
2599 if (vol_list[0] && vol_list[1])
2600 return (do_acopy(vol_list, update_mode, direction));
2601
2602 volume = vol_list[0];
2603 if (!find_shadow_config(volume, &parms, ©_args))
2604 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2605 "group"), NULL);
2606
2607 cfg_unlock(cfg);
2608 config_locked = 0;
2609 copy_args.flags = 0;
2610
2611 if (update_mode == Update)
2612 copy_args.flags |= CV_BMP_ONLY;
2613 if (direction == ToMaster) {
2614 copy_args.flags |= CV_SHD2MST;
2615 t = parms.master_vol;
2616 } else {
2617 t = parms.shadow_vol;
2618 }
2619 if (pflg) {
2620 copy_args.flags |= CV_LOCK_PID;
2621 #ifdef DEBUG
2622 ppid = getenv("IIADM_PPID");
2623 if (ppid) {
2624 copy_args.pid = atoi(ppid);
2625 (void) fprintf(stderr, "(using %s for ppid)\n", ppid);
2626 } else {
2627 copy_args.pid = getppid();
2628 }
2629 #else
2630 copy_args.pid = getppid();
2631 #endif
2632 }
2633
2634 if (mounted(t)) {
2635 errno = EBUSY;
2636 dsw_error(gettext("Target of copy/update is mounted, "
2637 "unmount it first"), NULL);
2638 }
2639
2640 (void) strncpy(stat_s.shadow_vol, copy_args.shadow_vol, DSW_NAMELEN);
2641 stat_s.shadow_vol[DSW_NAMELEN-1] = '\0';
2642 stat_s.status = spcs_s_ucreate();
2643 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &stat_s);
2644 spcs_s_ufree(&stat_s.status);
2645 if (rc == -1)
2646 dsw_error(gettext("Shadow group suspended"), NULL);
2647
2648 if (stat_s.stat & DSW_COPYINGP) {
2649 (void) fprintf(stderr, "%s: %s\n", cmdnam,
2650 gettext("Copy already in progress"));
2651 exit(1);
2652 }
2653
2654 copy_args.status = spcs_s_ucreate();
2655 spcs_log("ii", NULL, gettext("Start %s %s %s"),
2656 update_mode == Update ?
2657 gettext("update") : gettext("copy"),
2658 volume,
2659 direction == ToMaster ? gettext("from shadow") :
2660 gettext("to shadow"));
2661
2662 if (wait_action == WaitForStart)
2663 (void) sigset(SIGCHLD, sigchild);
2664 switch (child = fork()) {
2665
2666 case (pid_t)-1:
2667 dsw_error(gettext("Unable to fork"),
2668 NULL);
2669 break;
2670
2671 case 0:
2672 rc = do_ioctl(dsw_fd, DSWIOC_COPY, ©_args);
2673 if (rc == -1) {
2674 spcs_log("ii", ©_args.status,
2675 gettext("Fail %s %s %s"),
2676 update_mode == Update ?
2677 gettext("update") : gettext("copy"),
2678 volume,
2679 direction == ToMaster ? gettext("from shadow")
2680 : gettext("to shadow"));
2681 dsw_error(gettext("Copy failed"), ©_args.status);
2682 }
2683 spcs_s_ufree(©_args.status);
2684 spcs_log("ii", NULL, gettext("Finish %s %s %s"),
2685 update_mode == Update ?
2686 gettext("update") : gettext("copy"),
2687 volume,
2688 direction == ToMaster ? gettext("from shadow") :
2689 gettext("to shadow"));
2690
2691 exit(0);
2692 break;
2693 default:
2694 if (wait_action == WaitForStart) {
2695 rc = child_wait(child, CopyStart, copy_args.shadow_vol);
2696 } else { /* wait_action == WaitForEnd */
2697 wait_loc = 0;
2698 (void) wait(&wait_loc);
2699 if (WIFEXITED(wait_loc) && (WEXITSTATUS(wait_loc) == 0))
2700 rc = 0;
2701 else
2702 rc = 1;
2703 }
2704 break;
2705 }
2706 return (rc);
2707 }
2708
2709 void
2710 print_status(dsw_config_t *conf, int in_config)
2711 {
2712 dsw_stat_t args;
2713 int stat_flags;
2714 static int need_sep = 0;
2715 time_t tmp_time;
2716
2717 if (need_sep++ > 0)
2718 (void) printf("--------------------------------------"
2719 "----------------------------------------\n");
2720 (void) strncpy(args.shadow_vol, conf->shadow_vol, DSW_NAMELEN);
2721 args.shadow_vol[DSW_NAMELEN-1] = '\0';
2722 if (in_config) {
2723 (void) printf("%s: %s\n",
2724 conf->master_vol, gettext("(master volume)"));
2725 (void) printf("%s: %s\n",
2726 conf->shadow_vol, gettext("(shadow volume)"));
2727 (void) printf("%s: %s\n",
2728 conf->bitmap_vol, gettext("(bitmap volume)"));
2729 }
2730
2731 /*
2732 * Do special checking on the status of this volume in a Sun Cluster
2733 */
2734 if (check_cluster() == II_CLUSTER) {
2735 char dgname[CFG_MAX_BUF], *other_node;
2736
2737 if (cfg_dgname(conf->bitmap_vol, dgname, sizeof (dgname))) {
2738 if (strlen(dgname)) {
2739 int rc = cfg_dgname_islocal(dgname, &other_node);
2740 if (rc < 0) {
2741 (void) printf(gettext(
2742 "Suspended on this node, not active elsewhere\n"));
2743 return;
2744 } else if (rc == 0) {
2745 (void) printf(gettext(
2746 "Suspended on this node, active on %s\n"),
2747 other_node);
2748 return;
2749 }
2750 }
2751 }
2752 }
2753
2754 args.status = spcs_s_ucreate();
2755 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) {
2756
2757 /* Handle Not found or not in config */
2758 if (errno != DSW_ENOTFOUND || !in_config)
2759 dsw_error(gettext("Stat failed"), &args.status);
2760
2761 /* Just suspend */
2762 (void) printf(gettext("Suspended.\n"));
2763 return;
2764 }
2765
2766 if (args.overflow_vol[0] != '\0')
2767 (void) printf("%s: %s\n", args.overflow_vol,
2768 gettext("(overflow volume)"));
2769
2770 if (conf->group_name[0] != '\0')
2771 (void) printf(gettext("Group name: %s\n"),
2772 conf->group_name);
2773
2774 if (conf->cluster_tag[0] != '\0')
2775 (void) printf(gettext("Cluster tag: %s\n"),
2776 conf->cluster_tag);
2777
2778 stat_flags = args.stat;
2779 spcs_s_ufree(&args.status);
2780 if (stat_flags & DSW_GOLDEN)
2781 (void) printf(gettext("Independent copy"));
2782 else
2783 (void) printf(gettext("Dependent copy"));
2784
2785 if (stat_flags & DSW_TREEMAP)
2786 (void) printf(gettext(", compacted shadow space"));
2787
2788 if (stat_flags & DSW_COPYINGP)
2789 (void) printf(gettext(", copy in progress"));
2790 else if (stat_flags & DSW_COPYING)
2791 (void) printf(gettext(", copy not active"));
2792
2793 if (stat_flags & DSW_COPYINGM)
2794 (void) printf(gettext(", copying master to shadow"));
2795
2796 if (stat_flags & DSW_COPYINGS)
2797 (void) printf(gettext(", copying shadow to master"));
2798
2799 if (stat_flags & DSW_COPYINGX)
2800 (void) printf(gettext(", abort of copy requested"));
2801
2802 if (stat_flags & DSW_MSTOFFLINE)
2803 (void) printf(gettext(", master volume offline"));
2804
2805 if (stat_flags & DSW_SHDOFFLINE)
2806 (void) printf(gettext(", shadow volume offline"));
2807
2808 if (stat_flags & DSW_BMPOFFLINE)
2809 (void) printf(gettext(", bitmap volume offline"));
2810
2811 if (stat_flags & DSW_OVROFFLINE)
2812 (void) printf(gettext(", overflow volume offline"));
2813
2814 if (stat_flags & DSW_SHDEXPORT)
2815 (void) printf(gettext(", shadow volume exported"));
2816
2817 if (stat_flags & DSW_SHDIMPORT)
2818 (void) printf(gettext(", shadow volume imported"));
2819
2820 if (stat_flags & DSW_OVERFLOW)
2821 (void) printf(gettext(", out of space"));
2822
2823 if (stat_flags & DSW_VOVERFLOW)
2824 (void) printf(gettext(", spilled into overflow volume"));
2825 (void) printf("\n");
2826
2827 tmp_time = args.mtime;
2828 if (tmp_time != 0)
2829 (void) printf("%s %s", gettext("Latest modified time:"),
2830 ctime(&tmp_time));
2831 else
2832 (void) printf("%s\n", gettext("Latest modified time: unknown"));
2833
2834 (void) printf("%s %8llu\n", gettext("Volume size:"), args.size);
2835 if (args.shdsize != 0) {
2836 (void) printf("%s %lld %s %lld\n",
2837 gettext("Shadow chunks total:"), args.shdsize,
2838 gettext("Shadow chunks used:"), args.shdused);
2839 }
2840 bitmap_op(args.shadow_vol, 0, 1, 0, 0);
2841 }
2842
2843 int
2844 abort_copy(char *volume)
2845 {
2846 dsw_ioctl_t args;
2847
2848 if (!find_shadow_config(volume, NULL, &args))
2849 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2850 "group"), NULL);
2851 args.status = spcs_s_ucreate();
2852 if (do_ioctl(dsw_fd, DSWIOC_ABORT, &args) == -1)
2853 dsw_error(gettext("Abort failed"), &args.status);
2854 spcs_log("ii", NULL, gettext("Abort %s"), args.shadow_vol);
2855 spcs_s_ufree(&args.status);
2856 return (0);
2857 }
2858
2859 void
2860 iiversion()
2861 {
2862 dsw_version_t args;
2863
2864 args.status = spcs_s_ucreate();
2865 if (do_ioctl(dsw_fd, DSWIOC_VERSION, &args) == -1)
2866 dsw_error(gettext("Version failed"), &args.status);
2867 spcs_s_ufree(&args.status);
2868 #ifdef DEBUG
2869 (void) printf(gettext("Point in Time Copy version %d.%d.%d.%d\n"),
2870 args.major, args.minor, args.micro, args.baseline);
2871 #else
2872 if (args.micro) {
2873 (void) printf(gettext("Point in Time Copy version %d.%d.%d\n"),
2874 args.major, args.minor, args.micro);
2875 } else {
2876 (void) printf(gettext("Point in Time Copy version %d.%d\n"),
2877 args.major, args.minor);
2878 }
2879 #endif
2880 }
2881
2882 void
2883 list_volumes()
2884 {
2885 dsw_list_t args;
2886 int i, set, found;
2887 dsw_config_t *lp;
2888 ENTRY item, *ip;
2889 dsw_config_t parms;
2890
2891 if ((i = do_ioctl(dsw_fd, DSWIOC_LISTLEN, &args)) == -1)
2892 dsw_error("DSWIOC_LISTLEN", NULL);
2893
2894 args.status = spcs_s_ucreate();
2895 args.list_used = 0;
2896 args.list_size = i + 4;
2897 lp = args.list = (dsw_config_t *)
2898 malloc(args.list_size * sizeof (dsw_config_t));
2899
2900 if (args.list == NULL)
2901 dsw_error(gettext("Failed to allocate memory"), NULL);
2902 if (do_ioctl(dsw_fd, DSWIOC_LIST, &args) == -1)
2903 dsw_error(gettext("List failed"), &args.status);
2904 spcs_s_ufree(&args.status);
2905
2906 /* make a hashtable */
2907 if (args.list_used > 0) {
2908 if (hcreate(args.list_used) == 0) {
2909 dsw_error(gettext("Failed to allocate memory"), NULL);
2910 /*NOTREACHED*/
2911 }
2912 }
2913
2914 /* populate the hashtable */
2915 for (i = 0; i < args.list_used; i++, lp++) {
2916 item.key = lp->shadow_vol;
2917 item.data = (char *)lp;
2918 if (hsearch(item, ENTER) == NULL) {
2919 dsw_error(gettext("Failed to allocate memory"), NULL);
2920 /*NOTREACHED*/
2921 }
2922 }
2923
2924 /* perform action for each line of the stored config file */
2925 for (set = 1; get_dsw_config(set, &parms) == 0; set++) {
2926
2927 /* Are there any II sets configured on this node? */
2928 if (args.list_used > 0) {
2929 item.key = parms.shadow_vol;
2930
2931 /* Is this volume configured on this node? */
2932 if (ip = hsearch(item, FIND)) {
2933
2934 /* Handle Imported Shadows */
2935 /* LINTED alignment of cast ok */
2936 lp = (dsw_config_t *)ip->data;
2937 if (strcmp(parms.master_vol,
2938 II_IMPORTED_SHADOW))
2939 found = !(lp->flag & DSW_SHDIMPORT);
2940 else
2941 found = (lp->flag & DSW_SHDIMPORT);
2942 }
2943 else
2944 found = FALSE;
2945 }
2946 else
2947 found = FALSE;
2948
2949 if ((cfg_cluster_tag) &&
2950 strcmp(cfg_cluster_tag, parms.cluster_tag))
2951 continue;
2952
2953 if ((group_name) && strcmp(group_name, parms.group_name))
2954 continue;
2955
2956 (void) printf("%s %.*s %.*s %.*s%s\n",
2957 (parms.flag & DSW_GOLDEN) ? "ind" : "dep",
2958 DSW_NAMELEN, parms.master_vol,
2959 DSW_NAMELEN, parms.shadow_vol,
2960 DSW_NAMELEN, parms.bitmap_vol,
2961 found ? "" : gettext(" (suspended)"));
2962 }
2963 hdestroy();
2964 free(args.list);
2965 }
2966
2967 int
2968 wait_for_copy(char *volume)
2969 {
2970 dsw_ioctl_t parms;
2971 int rc;
2972 static int unlocked = 0;
2973 char *ppid;
2974
2975 if (unlocked && !ii_lock(cfg, CFG_RDLOCK)) {
2976 dsw_error(gettext("Unable to set locking on the configuration"),
2977 NULL);
2978 }
2979 config_locked = 1;
2980 if (!find_shadow_config(volume, NULL, &parms))
2981 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
2982 "group"), NULL);
2983 cfg_unlock(cfg);
2984 config_locked = 0;
2985 unlocked = 1;
2986
2987 parms.status = spcs_s_ucreate();
2988 if (pflg) {
2989 #ifdef DEBUG
2990 ppid = getenv("IIADM_PPID");
2991 if (ppid) {
2992 parms.pid = atoi(ppid);
2993 (void) fprintf(stderr, "(using %s for ppid)\n", ppid);
2994 } else {
2995 parms.pid = (nflg) ? -1 : getppid();
2996 }
2997 #else
2998 parms.pid = (nflg) ? -1 : getppid();
2999 #endif
3000 parms.flags |= CV_LOCK_PID;
3001 }
3002
3003 rc = do_ioctl(dsw_fd, DSWIOC_WAIT, &parms);
3004 if (rc == -1)
3005 dsw_error(gettext("Wait failed"), &parms.status);
3006 spcs_s_ufree(&parms.status);
3007 return (0);
3008 }
3009
3010 int
3011 export(char *volume)
3012 {
3013 dsw_ioctl_t parms;
3014 dsw_config_t conf;
3015 char *old_ctag, dgname[DSW_NAMELEN];
3016 int rc;
3017
3018 if (!find_shadow_config(volume, &conf, &parms))
3019 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3020 "group"), NULL);
3021 if (mounted(volume))
3022 dsw_error(gettext("Can't export a mounted volume"), NULL);
3023
3024 /* If this is an exportable shadow in the cluster, change ctag */
3025 if (strlen(conf.cluster_tag) &&
3026 (cfg_dgname(volume, dgname, sizeof (dgname)))) {
3027 old_ctag = cfg_cluster_tag;
3028 cfg_resource(cfg, cfg_cluster_tag = strdup(dgname));
3029 } else old_ctag = NULL;
3030
3031 if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) {
3032 dsw_error(gettext("Unable to parse config file"), NULL);
3033 }
3034 reload_vols = LD_DSVOLS | LD_SHADOWS;
3035 conform_name(&volume);
3036
3037 spcs_log("ii", NULL, gettext("Export %s"), volume);
3038 parms.status = spcs_s_ucreate();
3039 rc = do_ioctl(dsw_fd, DSWIOC_EXPORT, &parms);
3040 if (rc == -1)
3041 dsw_error(gettext("Export failed"), &parms.status);
3042 if (perform_autosv()) {
3043 if (cfg_vol_disable(cfg, volume, cfg_cluster_tag, "ii") < 0) {
3044 dsw_error(gettext("SV-disable failed"), NULL);
3045 }
3046 (void) cfg_commit(cfg);
3047 }
3048
3049 /* restore old cluster tag, if changed */
3050 if (old_ctag != NULL)
3051 cfg_resource(cfg, cfg_cluster_tag = old_ctag);
3052
3053 spcs_s_ufree(&parms.status);
3054 return (0);
3055 }
3056
3057 int
3058 detach(char *volume)
3059 {
3060 dsw_ioctl_t parms;
3061 int rc;
3062
3063 if (!find_shadow_config(volume, NULL, &parms))
3064 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3065 "group"), NULL);
3066 parms.status = spcs_s_ucreate();
3067 rc = do_ioctl(dsw_fd, DSWIOC_ODETACH, &parms);
3068 if (rc == 0) {
3069 /* remove overflow from cfg line */
3070 (void) sprintf(key, "ii.set%d.overflow", setnumber);
3071 if (cfg_put_cstring(cfg, key, "-", 1) < 0) {
3072 perror("cfg_put_cstring");
3073 }
3074 (void) cfg_commit(cfg);
3075 } else {
3076 spcs_log("ii", NULL, gettext("Detach of overflow %s failed"),
3077 parms.shadow_vol);
3078 dsw_error(gettext("Failed to detach overflow volume"),
3079 &parms.status);
3080 }
3081 return (rc);
3082 }
3083
3084 static void
3085 can_disable(char *vol)
3086 {
3087 dsw_stat_t args;
3088
3089 if (mounted(vol)) {
3090 (void) strncpy(args.shadow_vol, vol, DSW_NAMELEN);
3091 args.shadow_vol[DSW_NAMELEN - 1] = '\0';
3092 args.status = spcs_s_ucreate();
3093 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) != -1 &&
3094 (args.stat & DSW_GOLDEN) == 0) {
3095 errno = EBUSY;
3096 dsw_error(gettext("Shadow Volume is currently mounted "
3097 "and dependent on the master volume"), NULL);
3098 }
3099 spcs_s_ufree(&args.status);
3100 }
3101 }
3102
3103 static void
3104 clean_up_after_failed_disable(dsw_ioctl_t *parms)
3105 {
3106 char **p;
3107 dsw_stat_t args;
3108
3109 for (p = group_volumes; *p; p++) {
3110 (void) strncpy(args.shadow_vol, *p, DSW_NAMELEN);
3111 args.shadow_vol[DSW_NAMELEN - 1] = '\0';
3112 args.status = spcs_s_ucreate();
3113 if (do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) {
3114 /* set was successfully disabled */
3115 if (find_shadow_config(*p, NULL, NULL))
3116 remove_iiset(setnumber, *p, 0);
3117 }
3118 spcs_s_ufree(&args.status);
3119 }
3120
3121 dsw_error(gettext("Some sets in the group failed to disable"),
3122 &parms->status);
3123 }
3124
3125 int
3126 dsw_group_or_single_disable(int argc, char *argv[])
3127 {
3128 int rc = 0;
3129 char **p;
3130 dsw_ioctl_t parms;
3131 int flags = 0;
3132 dsw_config_t conf;
3133 int shd_exported = 0;
3134
3135 if (argc != 2)
3136 usage(gettext("Incorrect number of arguments"));
3137
3138 if (group_name) {
3139 if (find_group_members(group_name) < 1)
3140 dsw_error(gettext("Group does not exist or "
3141 "has no members"), NULL);
3142 for (p = group_volumes; *p; p++) {
3143 can_disable(*p);
3144 }
3145
3146 (void) strncpy(parms.shadow_vol, group_name, DSW_NAMELEN);
3147 if (*group_name)
3148 flags = CV_IS_GROUP;
3149 } else {
3150 if (!find_shadow_config(argv[1], &conf, &parms)) {
3151 dsw_error(gettext("Volume is not in a Point-in-Time "
3152 "Copy group"), NULL);
3153 }
3154
3155 can_disable(argv[1]);
3156 flags = 0;
3157 }
3158
3159 if (group_name && !*group_name) {
3160 /* user typed iiadm -g "" -d */
3161 for (p = group_volumes; *p; p++) {
3162 parms.status = spcs_s_ucreate();
3163 parms.flags = flags;
3164 (void) strncpy(parms.shadow_vol, *p, DSW_NAMELEN);
3165 rc = do_ioctl(dsw_fd, DSWIOC_DISABLE, &parms);
3166 if (rc == -1 && errno != DSW_ENOTFOUND)
3167 dsw_error(gettext("Disable failed"),
3168 &parms.status);
3169 if (!find_shadow_config(*p, NULL, NULL))
3170 dsw_error(gettext("Volume is not in a Point-in"
3171 "-Time Copy group"), &parms.status);
3172 remove_iiset(setnumber, *p, 0);
3173 spcs_s_ufree(&parms.status);
3174 spcs_log("ii", NULL, gettext("Disabled %s"),
3175 parms.shadow_vol);
3176 }
3177 } else {
3178 if (is_exported(conf.shadow_vol)) {
3179 shd_exported = 1;
3180 }
3181 if ((strcmp(conf.master_vol, II_IMPORTED_SHADOW) == 0) &&
3182 is_exported(conf.shadow_vol)) {
3183 dsw_error(gettext(
3184 "Imported shadow not disabled"), NULL);
3185 }
3186
3187 parms.status = spcs_s_ucreate();
3188 parms.flags = flags;
3189 rc = do_ioctl(dsw_fd, DSWIOC_DISABLE, &parms);
3190 if (rc == -1 && errno != DSW_ENOTFOUND) {
3191 if (errno == DSW_EDISABLE) {
3192 /*
3193 * one or more sets within the group
3194 * couldn't disable
3195 */
3196 clean_up_after_failed_disable(&parms);
3197 } else {
3198 dsw_error(gettext("Disable failed"),
3199 &parms.status);
3200 }
3201 }
3202 spcs_log("ii", NULL, gettext("Disabled %s"), parms.shadow_vol);
3203 }
3204
3205
3206 if (group_name && *group_name) {
3207 for (p = group_volumes; *p; p++) {
3208 if (!find_shadow_config(*p, NULL, NULL)) {
3209 /* argh! */
3210 (void) fprintf(stderr,
3211 gettext("Volume '%s' is not "
3212 "in a Point-in-Time Copy group"), *p);
3213 } else {
3214 remove_iiset(setnumber, *p, 0);
3215 }
3216 }
3217 } else if (!group_name) {
3218 if (!find_shadow_config(argv[1], NULL, NULL)) {
3219 /* argh! */
3220 dsw_error(gettext("Volume is not in a Point-in-Time "
3221 "Copy group"), NULL);
3222 }
3223
3224 remove_iiset(setnumber, argv[1], shd_exported);
3225 }
3226
3227 return (0);
3228 }
3229
3230 int
3231 dsw_group_or_single_op(int argc, char *argv[], int (*op)(char *))
3232 {
3233 int rc = 0;
3234
3235 if (argc != 2)
3236 usage(gettext("Incorrect number of arguments"));
3237
3238 if (group_name) {
3239 if (find_group_members(group_name) < 1)
3240 dsw_error(gettext("Group does not exist or "
3241 "has no members"),
3242 NULL);
3243 for (; *group_volumes; group_volumes++)
3244 rc |= (*op)(*group_volumes);
3245 } else {
3246 rc = (*op)(argv[1]);
3247 }
3248 return (rc);
3249 }
3250
3251 void
3252 dsw_list_clusters(char *cluster)
3253 {
3254 dsw_aioctl_t *acopy_args;
3255 int rc, i, count;
3256 char *ptr;
3257
3258 if ((count = do_ioctl(dsw_fd, DSWIOC_LISTLEN, NULL)) < 0)
3259 dsw_error("DSWIOC_LISTLEN", NULL);
3260
3261 acopy_args = malloc(sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
3262 if (acopy_args == NULL)
3263 dsw_error(gettext("Can't get memory for list enquiry"), NULL);
3264
3265 bzero(acopy_args, sizeof (dsw_aioctl_t) + count * DSW_NAMELEN);
3266 acopy_args->count = count;
3267 acopy_args->flags = 0;
3268 acopy_args->status = spcs_s_ucreate();
3269 if (cluster)
3270 (void) strncpy(acopy_args->shadow_vol, cluster, DSW_NAMELEN);
3271
3272 rc = do_ioctl(dsw_fd, DSWIOC_CLIST, acopy_args);
3273 if (rc == -1)
3274 dsw_error(gettext("Cluster list access failure"),
3275 &acopy_args->status);
3276
3277 acopy_args->shadow_vol[DSW_NAMELEN*acopy_args->count] = NULL;
3278
3279 if (cluster) {
3280 (void) printf(gettext("Sets in cluster resource group %s:\n"),
3281 cluster);
3282 } else {
3283 (void) printf(
3284 gettext("Currently configured resource groups\n"));
3285 }
3286 for (i = 0, ptr = acopy_args->shadow_vol; *ptr &&
3287 i < acopy_args->count; i++, ptr += DSW_NAMELEN) {
3288 (void) printf(" %-64.64s\n", ptr);
3289 }
3290 }
3291
3292 void
3293 dsw_enable(int argc, char *argv[])
3294 {
3295 if (argc != 5)
3296 usage(gettext("Incorrect number of arguments"));
3297
3298 enable(argv[1], argv[2], argv[3], argv[4]);
3299 exit(0);
3300 }
3301
3302
3303 void
3304 dsw_disable(int argc, char *argv[])
3305 {
3306 (void) dsw_group_or_single_disable(argc, argv);
3307 exit(0);
3308 }
3309
3310
3311 void
3312 dsw_copy_to_shadow(int argc, char *argv[])
3313 {
3314 char **volume_list;
3315
3316 if (argc != 2)
3317 usage(gettext("Incorrect number of arguments"));
3318 if (group_name == NULL)
3319 volume_list = ++argv;
3320 else {
3321 if (find_group_members(group_name) < 1)
3322 dsw_error(gettext("Group does not exist or "
3323 "has no members"),
3324 NULL);
3325 volume_list = group_volumes;
3326 }
3327
3328 exit(do_copy(volume_list, Copy, ToShadow, WaitForStart));
3329 }
3330
3331
3332 void
3333 dsw_update_shadow(int argc, char *argv[])
3334 {
3335 char **volume_list;
3336
3337 if (argc != 2)
3338 usage(gettext("Incorrect number of arguments"));
3339 if (group_name == NULL)
3340 volume_list = ++argv;
3341 else {
3342 if (find_group_members(group_name) < 1)
3343 dsw_error(gettext("Group does not exist or "
3344 "has no members"),
3345 NULL);
3346 volume_list = group_volumes;
3347 }
3348
3349 exit(do_copy(volume_list, Update, ToShadow, WaitForStart));
3350 }
3351
3352
3353 void
3354 dsw_copy_to_master(int argc, char *argv[])
3355 {
3356 char **volume_list;
3357
3358 if (argc != 2)
3359 usage(gettext("Incorrect number of arguments"));
3360 if (group_name == NULL) {
3361 volume_list = ++argv;
3362 check_action(gettext("Overwrite master with shadow volume?"));
3363 } else {
3364 check_action(gettext("Overwrite every"
3365 " master in this group with its shadow volume?"));
3366 if (find_group_members(group_name) < 1)
3367 dsw_error(gettext("Group does not exist or "
3368 "has no members"),
3369 NULL);
3370 volume_list = group_volumes;
3371 }
3372
3373 exit(do_copy(volume_list, Copy, ToMaster, WaitForStart));
3374 }
3375
3376
3377 void
3378 dsw_update_master(int argc, char *argv[])
3379 {
3380 char **volume_list;
3381
3382 if (argc != 2)
3383 usage(gettext("Incorrect number of arguments"));
3384 if (group_name == NULL) {
3385 volume_list = ++argv;
3386 check_action(gettext("Overwrite master with shadow volume?"));
3387 } else {
3388 check_action(gettext("Overwrite every"
3389 " master in this group with its shadow volume?"));
3390 if (find_group_members(group_name) < 1)
3391 dsw_error(gettext("Group does not exist or "
3392 "has no members"),
3393 NULL);
3394 volume_list = group_volumes;
3395 }
3396
3397 exit(do_copy(volume_list, Update, ToMaster, WaitForStart));
3398 }
3399
3400
3401 void
3402 dsw_abort_copy(int argc, char *argv[])
3403 {
3404 exit(dsw_group_or_single_op(argc, argv, abort_copy));
3405 }
3406
3407
3408 void
3409 dsw_display_status(int argc, char *argv[])
3410 {
3411 dsw_config_t parms;
3412 int in_config;
3413
3414 if (argc != 2 && argc != 1)
3415 usage(gettext("Incorrect number of arguments"));
3416
3417 /* "iiadm -i" and "iiadm -i all" are equivalent */
3418 if (argc == 2 && strcmp("all", argv[1]) != 0) {
3419 in_config = find_shadow_config(argv[1], &parms, NULL);
3420 if (!in_config) {
3421 (void) printf(gettext(
3422 "Volume is not in configuration file\n"), NULL);
3423 (void) fflush(stdout);
3424 (void) strncpy(parms.shadow_vol, argv[1], DSW_NAMELEN);
3425 parms.shadow_vol[DSW_NAMELEN] = '\0';
3426 }
3427 print_status(&parms, in_config);
3428 } else if (group_name) {
3429 if (find_group_members(group_name) < 1)
3430 dsw_error(gettext("Group does not exist or "
3431 "has no members"),
3432 NULL);
3433 for (; *group_volumes; group_volumes++) {
3434 in_config = find_shadow_config(*group_volumes,
3435 &parms, NULL);
3436 if (in_config)
3437 print_status(&parms, in_config);
3438 }
3439 } else {
3440 /* perform action for each line of the stored config file */
3441 for (setnumber = 1;
3442 !get_dsw_config(setnumber, &parms); setnumber++) {
3443 switch (check_cluster()) {
3444 case II_CLUSTER:
3445 if ((cfg_cluster_tag) &&
3446 (strcmp(cfg_cluster_tag, parms.cluster_tag)))
3447 continue;
3448 break;
3449 case II_CLUSTER_LCL:
3450 if (strlen(parms.cluster_tag))
3451 continue;
3452 break;
3453 }
3454 print_status(&parms, 1);
3455 }
3456 }
3457 exit(0);
3458 }
3459
3460 void
3461 dsw_display_bitmap(int argc, char *argv[])
3462 {
3463 dsw_config_t parms;
3464 int in_config;
3465
3466 if (argc != 2)
3467 usage(gettext("Incorrect number of arguments"));
3468
3469 in_config = find_shadow_config(argv[1], &parms, NULL);
3470 if (!in_config) {
3471 (void) printf(gettext(
3472 "Volume is not in configuration file\n"), NULL);
3473 (void) fflush(stdout);
3474 (void) strncpy(parms.master_vol, argv[1], DSW_NAMELEN);
3475 parms.master_vol[DSW_NAMELEN] = '\0';
3476 }
3477
3478 bitmap_op(parms.shadow_vol, 1, 0, 0, 0);
3479 exit(0);
3480 }
3481
3482
3483 /*ARGSUSED*/
3484 void
3485 dsw_version(int argc, char *argv[])
3486 {
3487 iiversion();
3488 exit(0);
3489 }
3490
3491 void
3492 dsw_reset(int argc, char *argv[])
3493 {
3494 exit(dsw_group_or_single_op(argc, argv, reset));
3495 }
3496
3497 void
3498 dsw_overflow(int argc, char *argv[])
3499 {
3500 if (argc != 2)
3501 usage(gettext("Incorrect number of arguments"));
3502
3503 exit(overflow(argv[1]));
3504 }
3505
3506 void
3507 dsw_wait(int argc, char *argv[])
3508 {
3509 exit(dsw_group_or_single_op(argc, argv, wait_for_copy));
3510 }
3511
3512 /*ARGSUSED*/
3513 void
3514 dsw_list_volumes(int argc, char *argv[])
3515 {
3516 if (argc != 1)
3517 usage(gettext("Incorrect number of arguments"));
3518
3519 list_volumes();
3520 exit(0);
3521 }
3522
3523 void
3524 dsw_export(int argc, char *argv[])
3525 {
3526 if (argc != 2)
3527 usage(gettext("Incorrect number of arguments"));
3528
3529 exit(dsw_group_or_single_op(argc, argv, export));
3530 }
3531
3532 void
3533 dsw_detach(int argc, char *argv[])
3534 {
3535 (void) dsw_group_or_single_op(argc, argv, detach);
3536 exit(0);
3537 }
3538
3539 void
3540 import(char *shadow_volume, char *bitmap_volume)
3541 {
3542 dsw_config_t parms = {0};
3543 int rc = 0;
3544 char shd_dg[DSW_NAMELEN];
3545 char bmp_dg[DSW_NAMELEN];
3546
3547 /*
3548 * If importing a shadow volume and the shadow volume is already
3549 * configured, we only support this if we are in a Sun Cluster
3550 * and the current user specified a cluster tag of -C local
3551 */
3552 if (find_shadow_config(shadow_volume, &parms, NULL)) {
3553 dsw_error(gettext("Can't import volume on same node"), NULL);
3554 }
3555
3556 switch (check_cluster()) {
3557 case II_CLUSTER:
3558 case II_CLUSTER_LCL:
3559 (void) check_resource_group(shadow_volume);
3560 if (cfg_cluster_tag) { /* check all volumes are in same dg */
3561 if (cfg_dgname(shadow_volume, shd_dg, DSW_NAMELEN)
3562 == NULL)
3563 dsw_error(gettext("Shadow volume not in a"
3564 " disk group"), NULL);
3565 if (cfg_dgname(bitmap_volume, bmp_dg, DSW_NAMELEN)
3566 == NULL)
3567 dsw_error(gettext("Bitmap volume not in a"
3568 " disk group"), NULL);
3569 if (strcmp(bmp_dg, shd_dg) != 0)
3570 dsw_error(gettext("Bitmap volume not in"
3571 " same disk group as shadow set members"),
3572 NULL);
3573 }
3574 break;
3575 case II_NOT_CLUSTER:
3576 /* do nothing */
3577 break;
3578 default:
3579 dsw_error(gettext(
3580 "Unexpected return from check_cluster()"), NULL);
3581 }
3582
3583 /* Local configuration volumes */
3584 if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) {
3585 dsw_error(gettext("Unable to parse config file"), NULL);
3586 }
3587
3588 reload_vols = LD_DSVOLS | LD_SHADOWS;
3589 conform_name(&shadow_volume);
3590 (void) strcpy(parms.master_vol, II_IMPORTED_SHADOW);
3591 (void) strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
3592 parms.shadow_vol[DSW_NAMELEN-1] = '\0';
3593 (void) strncpy(parms.bitmap_vol, bitmap_volume, DSW_NAMELEN);
3594 parms.bitmap_vol[DSW_NAMELEN-1] = '\0';
3595 parms.flag = DSW_GOLDEN;
3596
3597 spcs_log("ii", NULL, gettext("Import %s %s"),
3598 parms.shadow_vol, parms.bitmap_vol);
3599 parms.status = spcs_s_ucreate();
3600 rc = do_ioctl(dsw_fd, DSWIOC_IMPORT, &parms);
3601 if (rc == -1) {
3602 spcs_log("ii", NULL, gettext("Import failed %s %s"),
3603 parms.shadow_vol, parms.bitmap_vol);
3604 dsw_error(gettext("Import failed"), &parms.status);
3605 }
3606 if (perform_autosv()) {
3607 if (cfg_vol_enable(cfg, shadow_volume, cfg_cluster_tag, "ii")
3608 < 0) {
3609 dsw_error(gettext("SV-enable failed"), NULL);
3610 }
3611 /* cfg_commit is called by add_cfg_entry below */
3612 }
3613 spcs_s_ufree(&parms.status);
3614 add_cfg_entry(&parms);
3615 }
3616
3617 void
3618 dsw_import(int argc, char *argv[])
3619 {
3620 if (argc != 3)
3621 usage(gettext("Incorrect number of arguments"));
3622 import(argv[1], argv[2]);
3623
3624 exit(0);
3625 }
3626
3627 void
3628 join(char *shadow_volume, char *bitmap_file)
3629 {
3630 dsw_ioctl_t shd;
3631 dsw_config_t conf;
3632 dsw_bitmap_t parms;
3633 int rc = 0;
3634 int size;
3635 FILE *bmpfp;
3636 uchar_t *shd_bitmap = 0;
3637 ii_header_t header;
3638 char dgname[DSW_NAMELEN];
3639
3640 if (!find_shadow_config(shadow_volume, &conf, &shd))
3641 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3642 "group"), NULL);
3643
3644 /* If this is an exportable shadow in the cluster, change ctag */
3645 if (strlen(conf.cluster_tag) &&
3646 (cfg_dgname(shadow_volume, dgname, sizeof (dgname))))
3647 cfg_resource(cfg, cfg_cluster_tag = strdup(dgname));
3648
3649 if (cfg_load_dsvols(cfg) < 0 || cfg_load_shadows(cfg) < 0) {
3650 dsw_error(gettext("Unable to parse config file"), NULL);
3651 }
3652 reload_vols = LD_DSVOLS | LD_SHADOWS;
3653 conform_name(&shadow_volume);
3654
3655 if ((bmpfp = fopen(bitmap_file, "r")) == NULL) {
3656 perror(bitmap_file);
3657 (void) fprintf(stderr,
3658 gettext("Can't open imported bitmap volume\n"));
3659 exit(1);
3660 }
3661
3662 if (fread(&header, sizeof (header), 1, bmpfp) != 1) {
3663 (void) fprintf(stderr,
3664 gettext("Can't read imported bitmap volume\n"));
3665 exit(1);
3666 }
3667
3668 /* See if this is a bitmap header */
3669 switch (header.ii_magic) {
3670 case DSW_DIRTY: /* A copy of a enable bitmap volume */
3671 case DSW_CLEAN:
3672 check_action(gettext("Use the never imported bitmap?"));
3673 break;
3674 case DSW_INVALID: /* A valid diskable secondary bitmap */
3675 break;
3676 default:
3677 (void) fprintf(stderr,
3678 gettext("Secondary bitmap is not a valid bitmap volume\n"));
3679 exit(1);
3680 }
3681
3682 size = FBA_SIZE(header.ii_copyfba - header.ii_shdfba);
3683 if ((shd_bitmap = malloc(size)) == NULL) {
3684 perror("malloc");
3685 exit(1);
3686 }
3687
3688 if (fseek(bmpfp, FBA_SIZE(header.ii_shdfba), SEEK_SET)) {
3689 perror("fseek");
3690 exit(1);
3691 }
3692
3693 if (fread(shd_bitmap, 1, size, bmpfp) != size) {
3694 (void) fprintf(stderr,
3695 gettext("Can't read imported bitmap volume\n"));
3696 exit(1);
3697 }
3698
3699 (void) fclose(bmpfp);
3700
3701 (void) strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
3702 parms.shadow_vol[DSW_NAMELEN-1] = '\0';
3703 parms.shd_bitmap = shd_bitmap;
3704 parms.shd_size = size;
3705 parms.copy_bitmap = NULL;
3706 parms.copy_size = 0;
3707
3708 spcs_log("ii", NULL, gettext("Join %s %s"),
3709 parms.shadow_vol, bitmap_file);
3710 parms.status = spcs_s_ucreate();
3711 rc = do_ioctl(dsw_fd, DSWIOC_JOIN, &parms);
3712 if (rc == -1) {
3713 spcs_log("ii", NULL, gettext("Join failed %s %s"),
3714 parms.shadow_vol, bitmap_file);
3715 dsw_error(gettext("Join failed"), &parms.status);
3716 }
3717 if (perform_autosv()) {
3718 rc = cfg_vol_enable(cfg, shadow_volume, cfg_cluster_tag, "ii");
3719 if (rc < 0) {
3720 dsw_error(gettext("SV-enable failed"), NULL);
3721 }
3722 (void) cfg_commit(cfg);
3723 }
3724 spcs_s_ufree(&parms.status);
3725 }
3726
3727 int
3728 params(char *shadow_volume)
3729 {
3730 char *delay = param_delay;
3731 char *unit = param_unit;
3732 dsw_copyp_t parms;
3733 int rc = 0;
3734 int get = 0;
3735 int new_delay;
3736 int new_unit;
3737
3738 (void) strncpy(parms.shadow_vol, shadow_volume, DSW_NAMELEN);
3739 parms.shadow_vol[DSW_NAMELEN-1] = '\0';
3740 if (delay == NULL || unit == NULL) {
3741 get = 1;
3742 parms.copy_delay = -1;
3743 parms.copy_unit = -1;
3744 } else {
3745 new_delay = parms.copy_delay = convert_int(delay);
3746 new_unit = parms.copy_unit = convert_int(unit);
3747 }
3748
3749 parms.status = spcs_s_ucreate();
3750 rc = do_ioctl(dsw_fd, DSWIOC_COPYP, &parms);
3751 if (rc == -1) {
3752 (void) fprintf(stderr,
3753 gettext("Parameter ranges are delay(%d - %d), "
3754 "units(%d - %d)\n"), MIN_THROTTLE_DELAY, MAX_THROTTLE_DELAY,
3755 MIN_THROTTLE_UNIT, MAX_THROTTLE_UNIT);
3756 dsw_error(gettext("Set Copy Parameters failed"), &parms.status);
3757 }
3758 if (!get)
3759 spcs_log("ii", NULL, gettext("Changed copy parameters %s from "
3760 "%d %d to %d %d"), parms.shadow_vol, parms.copy_delay,
3761 parms.copy_unit, new_delay, new_unit);
3762 else
3763 (void) printf(gettext("volume: %s\ncopy delay: %d\ncopy unit:"
3764 " %d\n"), parms.shadow_vol, parms.copy_delay,
3765 parms.copy_unit);
3766 spcs_s_ufree(&parms.status);
3767 return (0);
3768 }
3769
3770 static void
3771 do_attach(dsw_config_t *parms)
3772 {
3773 dsw_config_t io;
3774 int rc;
3775 int check = 0;
3776
3777 spcs_log("ii", NULL, gettext("Attach %s %s"),
3778 parms->shadow_vol, parms->bitmap_vol);
3779 parms->status = spcs_s_ucreate();
3780 rc = do_ioctl(dsw_fd, DSWIOC_OATTACH, parms);
3781 if (rc == -1) {
3782 check = 1;
3783 /* if overflow() fails, it calls dsw_error to exit */
3784 (void) overflow(parms->bitmap_vol);
3785 }
3786 spcs_s_ufree(&parms->status);
3787 if (check == 1) {
3788 if (!find_shadow_config(parms->shadow_vol, &io, NULL))
3789 dsw_error(
3790 gettext("Volume is not in a Point-in-Time Copy "
3791 "group"), NULL);
3792 (void) strncpy(io.bitmap_vol, parms->bitmap_vol, DSW_NAMELEN);
3793 io.bitmap_vol[DSW_NAMELEN-1] = '\0';
3794 io.status = spcs_s_ucreate();
3795 if (do_ioctl(dsw_fd, DSWIOC_OATTACH, &io) == -1) {
3796 spcs_log("ii", NULL, gettext("Attach failed %s %s"),
3797 io.shadow_vol, parms->bitmap_vol);
3798 dsw_error(gettext("Attach failed"), &io.status);
3799 }
3800 spcs_s_ufree(&io.status);
3801 }
3802 }
3803
3804 int
3805 attach(char *shadow_volume)
3806 {
3807 dsw_config_t parms;
3808 dsw_stat_t args;
3809 char shd_dg[DSW_NAMELEN];
3810 char ovr_dg[DSW_NAMELEN];
3811
3812 switch (check_cluster()) {
3813 case II_CLUSTER:
3814 case II_CLUSTER_LCL:
3815 (void) check_resource_group(shadow_volume);
3816 if (cfg_cluster_tag) { /* check all volumes are in same dg */
3817 if (cfg_dgname(shadow_volume, shd_dg, DSW_NAMELEN)
3818 == NULL)
3819 dsw_error(gettext("Shadow volume not in a"
3820 " disk group"), NULL);
3821 if (cfg_dgname(overflow_file, ovr_dg, DSW_NAMELEN)
3822 == NULL)
3823 dsw_error(gettext("Overflow volume not in a"
3824 " disk group"), NULL);
3825 if (strcmp(ovr_dg, shd_dg) != 0)
3826 dsw_error(gettext("Overflow volume not in"
3827 " same disk group as shadow set members"),
3828 NULL);
3829 }
3830 break;
3831 case II_NOT_CLUSTER:
3832 /* do nothing */
3833 break;
3834 default:
3835 dsw_error(gettext(
3836 "Unexpected return from check_cluster()"), NULL);
3837 }
3838
3839 /* assure that the overflow_file is not an II volume */
3840 if (find_any_cf_line(overflow_file))
3841 dsw_error(gettext(
3842 "Overflow volume is already in a Point-in-Time Copy "
3843 "group"), NULL);
3844
3845 /* use find_shadow_config() to find setnumber */
3846 if (!find_shadow_config(shadow_volume, &parms, NULL))
3847 dsw_error(gettext("Volume is not in a Point-in-Time Copy "
3848 "group"), NULL);
3849
3850 /* can only attach an overflow volume to dependent, compact shadow */
3851 (void) strncpy(args.shadow_vol, shadow_volume, DSW_NAMELEN);
3852 args.shadow_vol[DSW_NAMELEN-1] = '\0';
3853
3854 args.status = spcs_s_ucreate();
3855 if ((do_ioctl(dsw_fd, DSWIOC_STAT, &args) == -1) ||
3856 !(args.stat & DSW_TREEMAP))
3857 dsw_error(gettext("Not a compact dependent shadow"), NULL);
3858
3859 /* bitmap_vol is overloaded */
3860 (void) strncpy(parms.bitmap_vol, overflow_file, DSW_NAMELEN);
3861 parms.bitmap_vol[DSW_NAMELEN-1] = '\0';
3862
3863 do_attach(&parms);
3864
3865 /* add overflow to cfg line */
3866 (void) sprintf(key, "ii.set%d.overflow", setnumber);
3867 if (cfg_put_cstring(cfg, key, overflow_file,
3868 strlen(overflow_file)) < 0) {
3869 perror("cfg_put_cstring");
3870 }
3871 (void) cfg_commit(cfg);
3872 return (0);
3873 }
3874
3875 void
3876 dsw_join(int argc, char *argv[])
3877 {
3878 if (argc != 3)
3879 usage(gettext("Incorrect number of arguments"));
3880
3881 join(argv[1], argv[2]);
3882 exit(0);
3883 }
3884
3885 void
3886 dsw_params(int argc, char *argv[])
3887 {
3888 if (argc != 4 && argc != 2 && argc != 0)
3889 usage(gettext("Incorrect number of arguments"));
3890
3891 if ((argc == 4) || (argc == 2)) {
3892 param_delay = argv[1];
3893 param_unit = argv[2];
3894 if (argc == 4) {
3895 argv[1] = argv[3];
3896 argv[2] = NULL;
3897 }
3898 }
3899 exit(dsw_group_or_single_op(2, argv, params));
3900 }
3901
3902 /*ARGSUSED*/
3903 void
3904 dsw_attach(int argc, char *argv[])
3905 {
3906 overflow_file = argv[1];
3907 argv[1] = argv[2];
3908 (void) dsw_group_or_single_op(2, argv, attach);
3909 exit(0);
3910 }
3911
3912 /*ARGSUSED*/
3913 void
3914 dsw_olist(int argc, char *argv[])
3915 {
3916 char *sp, *overflow_list, **vol;
3917 int count, i;
3918 ENTRY item, *found;
3919 char key[ CFG_MAX_KEY ], buf[ CFG_MAX_BUF ];
3920
3921 overflow_list = get_overflow_list();
3922
3923 /* count entries */
3924 count = 0;
3925 for (sp = overflow_list; *sp; sp += DSW_NAMELEN) {
3926 ++count;
3927 }
3928
3929 /* create hash (adding room for suspended overflow volumes) */
3930 if (hcreate(count + 1024) == 0) {
3931 dsw_error(gettext("Out of memory creating lookup table"), NULL);
3932 /*NOTREACHED*/
3933 }
3934
3935 if (count > 0) {
3936 /* create memory to store copy of list */
3937 vol = (char **)calloc(count, sizeof (char *));
3938 if (!vol) {
3939 dsw_error(
3940 gettext("Out of memory creating lookup table"),
3941 NULL);
3942 /*NOTREACHED*/
3943 }
3944
3945 /* fill hash */
3946 for (i = 0, sp = overflow_list; *sp; sp += DSW_NAMELEN, i++) {
3947
3948 /* make copy of string */
3949 vol[ i ] = (char *)malloc(DSW_NAMELEN + 1);
3950 (void) strncpy(vol[ i ], sp, DSW_NAMELEN);
3951 vol[ i ][ DSW_NAMELEN ] = '\0';
3952
3953 item.key = vol[ i ];
3954 item.data = (char *)0;
3955 (void) hsearch(item, ENTER);
3956 }
3957 }
3958
3959 /* loop through config file entries */
3960 i = 0;
3961 cfg_rewind(cfg, CFG_SEC_CONF);
3962
3963 /*CONSTCOND*/
3964 while (1) {
3965 ++i;
3966 (void) snprintf(key, CFG_MAX_KEY, "ii.set%d.overflow", i);
3967 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) {
3968 break;
3969 }
3970
3971 /* has this set got an overflow volume? */
3972 if (!*buf) {
3973 continue;
3974 }
3975
3976 /* look up overflow in hash */
3977 item.key = buf;
3978 if (count > 0 && (found = hsearch(item, FIND)) != NULL) {
3979 if (0 == (int)found->data) {
3980 (void) printf("%s\n", buf);
3981 found->data = (char *)1;
3982 (void) hsearch(*found, ENTER);
3983 }
3984 } else {
3985 /* must be part of a suspended set */
3986 (void) printf("%s (attached to suspended set)\n", buf);
3987 item.key = buf;
3988 item.data = (char *)1;
3989 (void) hsearch(item, ENTER);
3990 }
3991 }
3992
3993 exit(0);
3994 }
3995
3996 void
3997 dsw_ostat(int argc, char *argv[])
3998 {
3999 dsw_ostat_t args;
4000 int stat_flags;
4001
4002 if (argc != 2)
4003 usage(gettext("Incorrect number of arguments"));
4004
4005 (void) strncpy(args.overflow_vol, argv[1], DSW_NAMELEN);
4006 args.overflow_vol[DSW_NAMELEN-1] = '\0';
4007
4008 args.status = spcs_s_ucreate();
4009 if (do_ioctl(dsw_fd, DSWIOC_OSTAT2, &args) == -1)
4010 dsw_error(gettext("Stat failed"), &args.status);
4011 spcs_s_ufree(&args.status);
4012
4013 if ((args.hversion >= 1) && (args.hmagic == II_OMAGIC)) {
4014 stat_flags = args.flags;
4015 if (stat_flags & IIO_CNTR_INVLD)
4016 (void) printf(gettext("Clean shutdown of volume "
4017 "sets associated with overflow volume "
4018 "did not occur.\n"
4019 "Overflow counters will be inconsistent "
4020 "until new point-in-time(s) are taken.\n"));
4021 }
4022 (void) printf(gettext("Total number of attached shadows: %d\n"),
4023 args.drefcnt);
4024 (void) printf(gettext("Number of currently attached shadows: %d\n"),
4025 args.crefcnt);
4026 (void) printf(gettext("Total number of chunks: %lld\n"), args.nchunks);
4027 (void) printf(gettext("Number of chunks ever allocated: %lld\n"),
4028 args.used);
4029 (void) printf(gettext("Number of used chunks: %lld\n"),
4030 (args.nchunks - args.unused));
4031 (void) printf(gettext("Number of unused chunks: %lld\n"), args.unused);
4032 exit(0);
4033 }
4034
4035 /*ARGSUSED*/
4036 void
4037 dsw_move_2_group(int argc, char *argv[])
4038 {
4039 dsw_config_t parms;
4040 dsw_movegrp_t movegrp;
4041 grptag_t *gdata;
4042 int waserr = 0;
4043
4044 /* handle move to NULL group, or group of all spaces or tabs */
4045 (void) strncpy(movegrp.new_group, group_name, DSW_NAMELEN);
4046 if ((strlen(group_name) == 0) || (strcspn(group_name, " \t") == 0)) {
4047 group_name = "-";
4048 bzero(movegrp.new_group, DSW_NAMELEN);
4049 gdata = NULL;
4050 } else {
4051 /* get the ctag for this group (if any) */
4052 gdata = (grptag_t *)nsc_lookup(volhash, group_name);
4053 }
4054
4055 movegrp.status = spcs_s_ucreate();
4056
4057 for (++argv; *argv; argv++) {
4058 if (!find_shadow_config(*argv, &parms, NULL))
4059 dsw_error(gettext("Volume is not in a Point-in-Time "
4060 "Copy group"), NULL);
4061
4062 /* ensure the ctag matches the group */
4063 if (gdata && *gdata->ctag) {
4064 if (strncmp(parms.cluster_tag, gdata->ctag,
4065 DSW_NAMELEN) != 0) {
4066 (void) fprintf(stderr, "%s: %s %s %s\n", cmdnam,
4067 gettext("unable to move set"), *argv,
4068 gettext("into new group - cluster "
4069 "resource mismatch"));
4070 waserr = 1;
4071 continue;
4072 }
4073 }
4074
4075 /* move the set in the kernel */
4076 (void) strncpy(movegrp.shadow_vol, parms.shadow_vol,
4077 DSW_NAMELEN);
4078 if (do_ioctl(dsw_fd, DSWIOC_MOVEGRP, &movegrp) < 0)
4079 dsw_error(gettext("Failed to move group in kernel"),
4080 NULL);
4081
4082 /* now update the config */
4083 (void) sprintf(key, "ii.set%d.group", setnumber);
4084 if (cfg_put_cstring(cfg, key, group_name,
4085 strlen(group_name)) < 0) {
4086 perror("cfg_put_cstring");
4087 }
4088 (void) cfg_commit(cfg);
4089 }
4090 spcs_s_ufree(&movegrp.status);
4091 cfg_close(cfg);
4092 exit(waserr);
4093 }
4094
4095 void
4096 dsw_list_groups()
4097 {
4098 FILE *pfp;
4099
4100 if ((pfp = popen("/usr/bin/sort -u", "w")) == NULL) {
4101 dsw_error(gettext("Can't open sort program"), NULL);
4102 }
4103
4104 (void) fflush(stdout);
4105 for (setnumber = 1; /*CSTYLED*/; setnumber++) {
4106 (void) snprintf(key, sizeof (key), "ii.set%d.group", setnumber);
4107 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0)
4108 break;
4109
4110 /* skip if shadow set is not in any group */
4111 if (strcmp(buf, "") == 0)
4112 continue;
4113 (void) fprintf(pfp, "%s\n", buf);
4114 }
4115 (void) pclose(pfp);
4116 }
4117
4118 void
4119 dsw_list_group_volumes()
4120 {
4121 FILE *pfp;
4122
4123 if (find_group_members(group_name) < 1)
4124 dsw_error(gettext("Group does not exist or has no members"),
4125 NULL);
4126
4127 if ((pfp = popen("/usr/bin/sort -u", "w")) == NULL) {
4128 dsw_error(gettext("Can't open sort program"), NULL);
4129 }
4130
4131 (void) fflush(stdout);
4132 for (; *group_volumes; group_volumes++)
4133 (void) fprintf(pfp, "%s\n", *group_volumes);
4134 (void) pclose(pfp);
4135 }
4136
4137 static void
4138 load_ii_vols(CFGFILE *cfg)
4139 {
4140 int set, entries;
4141 char *mst, *shd, *buf, **entry;
4142 char *ctag, *group;
4143 mstcount_t *mdata;
4144 shdvol_t *sdata;
4145 grptag_t *gdata;
4146 static int whinged = 0;
4147
4148 if (volhash) {
4149 return;
4150 }
4151
4152 volhash = nsc_create_hash();
4153 cfg_rewind(cfg, CFG_SEC_CONF);
4154 entries = cfg_get_section(cfg, &entry, "ii");
4155 for (set = 1; set <= entries; set++) {
4156 buf = entry[set - 1];
4157
4158 /* grab master volume name */
4159 mst = strtok(buf, " ");
4160 if (!mst) {
4161 free(buf);
4162 break;
4163 }
4164
4165 /* grab shadow, group & cnode fields */
4166 shd = strtok(NULL, " ");
4167 (void) strtok(NULL, " "); /* bitmap */
4168 (void) strtok(NULL, " "); /* mode */
4169 (void) strtok(NULL, " "); /* overflow */
4170 ctag = strtok(NULL, " "); /* cnode */
4171 (void) strtok(NULL, " "); /* options */
4172 group = strtok(NULL, " "); /* group */
4173
4174 /* Fix optional tags */
4175 if (ctag)
4176 ctag += strspn(ctag, "-");
4177 if (group)
4178 group += strspn(group, "-");
4179
4180 /* If cluster tags don't match, skip record */
4181 if ((cfg_cluster_tag && strcmp(ctag, cfg_cluster_tag)) ||
4182 (!cfg_cluster_tag && strlen(ctag))) {
4183 free(buf);
4184 continue;
4185 }
4186
4187 /* master volume, may be duplicates */
4188 mdata = (mstcount_t *)nsc_lookup(volhash, mst);
4189 if (mdata) {
4190 ++mdata->count;
4191 } else {
4192 mdata = (mstcount_t *)malloc(sizeof (mstcount_t));
4193 mdata->count = 1;
4194 (void) nsc_insert_node(volhash, mdata, mst);
4195 }
4196
4197 /* grab shadow volume name */
4198 sdata = (shdvol_t *)malloc(sizeof (shdvol_t));
4199 (void) strncpy(sdata->master, mst, DSW_NAMELEN);
4200 (void) nsc_insert_node(volhash, sdata, shd);
4201
4202 /* No need to continue if no groups or ctags */
4203 if (!group || !*group || !ctag || !*ctag) {
4204 free(buf);
4205 continue;
4206 }
4207
4208 gdata = (grptag_t *)nsc_lookup(volhash, group);
4209 if (gdata) {
4210 /* group already exists - check ctag */
4211 if (*ctag &&
4212 (strncmp(ctag, gdata->ctag, DSW_NAMELEN) != 0)) {
4213 if (!whinged) {
4214 (void) printf(gettext(
4215 "Warning: multiple "
4216 "cluster resource groups "
4217 "defined within a single "
4218 "I/O group\n"));
4219 whinged = 1;
4220 }
4221 }
4222 } else {
4223 gdata = (grptag_t *)malloc(sizeof (grptag_t));
4224 (void) strncpy(gdata->ctag, ctag, DSW_NAMELEN);
4225 (void) nsc_insert_node(volhash, gdata, group);
4226 }
4227
4228 free(buf);
4229 }
4230
4231 /* free up any leftovers */
4232 while (set < entries)
4233 free(entry[set++]);
4234 if (entries)
4235 free(entry);
4236 }
4237
4238 static void
4239 unload_ii_vols()
4240 {
4241 nsc_remove_all(volhash, free);
4242 volhash = 0;
4243 }
4244
4245 static int
4246 perform_autosv()
4247 {
4248 static int result;
4249 static int calculated = 0;
4250 int rc;
4251
4252 #ifdef DEBUG
4253 if (getenv("II_SET_CLUSTER"))
4254 return (1);
4255 #endif
4256
4257 if (calculated) {
4258 return (result);
4259 }
4260
4261 /*
4262 * we only perform auto-sv if we're in a sun cluster or if
4263 * we're on a standalone system. I.e. we don't do auto-sv on Harry
4264 */
4265 rc = check_cluster();
4266
4267 if (II_NOT_CLUSTER == rc) {
4268 result = 1;
4269 } else {
4270 result = cfg_issuncluster();
4271 }
4272
4273 calculated = 1;
4274 return (result);
4275 }
4276
4277 /*
4278 * Returns true if set has had the shadow volume exported.
4279 * Returns false if shadow volume is not exported, or set is suspended.
4280 */
4281 static int
4282 is_exported(char *set)
4283 {
4284 dsw_stat_t args;
4285 int rc;
4286
4287 (void) strncpy(args.shadow_vol, set, DSW_NAMELEN);
4288 args.shadow_vol[DSW_NAMELEN-1] = '\0';
4289 args.status = spcs_s_ucreate();
4290
4291 rc = do_ioctl(dsw_fd, DSWIOC_STAT, &args);
4292 spcs_s_ufree(&args.status);
4293
4294 if (-1 == rc) {
4295 /* set must be suspended, or being disabled */
4296 return (0);
4297 }
4298
4299 return ((args.stat & DSW_SHDEXPORT) == DSW_SHDEXPORT);
4300 }
4301
4302 static void
4303 conform_name(char **path)
4304 {
4305 char *cfgname;
4306 int rc = cfg_get_canonical_name(cfg, *path, &cfgname);
4307
4308 if (rc < 0) {
4309 dsw_error(gettext("Unable to parse config file"), NULL);
4310 }
4311 if (rc) {
4312 (void) printf(" '%s'\n%s\n '%s'\n", *path,
4313 gettext("is currently configured as"), cfgname);
4314 check_action(gettext("Perform operation with indicated volume"
4315 " name?"));
4316 *path = cfgname;
4317 /*
4318 * NOTE: *path ought to be deallocated ('free(*path)') after
4319 * we're done with it, but since this routine is called just
4320 * before we exit, it doesn't really matter
4321 */
4322 }
4323 }
4324
4325 /*
4326 * verify_groupname(char *, int);
4327 *
4328 * Check the group name for the following rules:
4329 * 1. The name does not start with a '-'
4330 * 2. The name does not contain any space characters as defined by
4331 * isspace(3C).
4332 * If either of these rules are broken, error immediately. The check for a
4333 * leading dash can be skipped if the 'testDash' argument is false. This is to
4334 * allow for the '-g -L' functionality.
4335 *
4336 */
4337 static void
4338 verify_groupname(char *grp, int testDash)
4339 {
4340 int i;
4341
4342 if (testDash && grp[0] == '-') {
4343 errno = EINVAL;
4344 dsw_error(gettext("group name cannot start with a '-'"), NULL);
4345 }
4346
4347 for (i = 0; grp[i] != '\0'; i++) {
4348 if (isspace(grp[i])) {
4349 errno = EINVAL;
4350 dsw_error(gettext("group name cannot contain a space"),
4351 NULL);
4352 }
4353 }
4354 }
4355
4356 void
4357 check_iishadow(char *shadow_vol) {
4358 int i;
4359 int entries;
4360 char **entry;
4361 char *shost;
4362 char *svol;
4363 char *buf;
4364 void *librdc;
4365
4366 /*
4367 * See if librdc is around
4368 * If not, we can just return
4369 */
4370 if (librdc = dlopen(RDC_LIB, RTLD_LAZY | RTLD_GLOBAL))
4371 self_check = (int (*)(char *)) dlsym(librdc, "self_check");
4372 else {
4373 return;
4374 }
4375
4376 entry = NULL;
4377 entries = cfg_get_section(cfg, &entry, "sndr");
4378 for (i = 0; i < entries; i++) {
4379 buf = entry[i];
4380
4381 (void) strtok(buf, " "); /* phost */
4382 (void) strtok(NULL, " "); /* primary */
4383 (void) strtok(NULL, " "); /* pbitmap */
4384 shost = strtok(NULL, " "); /* shost */
4385 svol = strtok(NULL, " "); /* secondary */
4386
4387 if (self_check(shost) && (strcmp(shadow_vol, svol) == 0)) {
4388 free(buf);
4389 if (entries)
4390 free(entry);
4391 errno = EINVAL;
4392 dsw_error(gettext(
4393 "shadow volume is in use as SNDR secondary volume"),
4394 NULL);
4395 }
4396 free(buf);
4397 }
4398
4399 (void) dlclose(librdc);
4400 if (entries)
4401 free(entry);
4402 }
4403