4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
29 #include <sys/param.h>
44 #include <sys/nsctl/cfg.h>
46 #include <sys/unistat/spcs_s.h>
47 #include <sys/unistat/spcs_s_u.h>
48 #include <sys/unistat/spcs_errors.h>
50 #include <sys/nsctl/dsw.h>
51 #include <sys/nskernd.h>
53 #define MAX_PROCESSES 64
55 int parseopts(int, char **, int *);
56 int read_resume_cfg();
57 int read_suspend_cfg();
58 void iiboot_usage(void);
59 extern char *basename(char *);
61 dsw_config_t
*resume_list
= 0;
62 dsw_ioctl_t
*suspend_list
= 0;
65 char *cfg_cluster_tag
= NULL
;
67 volatile int fork_cnt
;
71 iiboot_msg(char *prefix
, spcs_s_info_t
*status
, char *string
, va_list ap
)
74 (void) fprintf(stderr
, "II: %s\n", prefix
);
75 spcs_s_report(*status
, stderr
);
78 (void) fprintf(stderr
, "%s: %s: ", program
, prefix
);
81 if (string
&& *string
!= '\0') {
82 (void) vfprintf(stderr
, string
, ap
);
85 (void) fprintf(stderr
, "\n");
89 iiboot_err(spcs_s_info_t
*status
, char *string
, ...)
94 iiboot_msg(gettext("Error"), status
, string
, ap
);
101 iiboot_warn(spcs_s_info_t
*status
, char *string
, ...)
104 va_start(ap
, string
);
106 iiboot_msg(gettext("warning"), status
, string
, ap
);
117 (void) wait(&wait_loc
);
118 if (WIFEXITED(wait_loc
) && (WEXITSTATUS(wait_loc
) == 0)) {
122 fork_rc
= WEXITSTATUS(wait_loc
);
132 iiboot_lintmain(int argc
, char *argv
[])
134 main(int argc
, char *argv
[])
144 dsw_ioctl_t
*ii_iop
, ii_suspend
;
145 dsw_list_t args
= {0};
146 dsw_config_t
*ii_cfgp
, *lp
= NULL
;
147 spcs_s_info_t ustatus
;
148 int max_processes
= MAX_PROCESSES
;
150 (void) setlocale(LC_ALL
, "");
151 (void) textdomain("ii");
153 program
= strdup(basename(argv
[0]));
155 if ((ioctl_fd
= open(DSWDEV
, O_RDWR
, 0)) == -1) {
156 spcs_log("ii", NULL
, "iiboot open %s failed, errno %d",
159 gettext("Failed to open Point-in-Time Copy control "
163 if (parseopts(argc
, argv
, &flag
))
166 if (flag
== DSWIOC_RESUME
)
167 pairs
= read_resume_cfg();
174 gettext("Config contains no Point-in-Time Copy sets"));
179 if (cfg_cluster_tag
== NULL
&& flag
!= DSWIOC_RESUME
) {
180 if (ioctl(ioctl_fd
, DSWIOC_SHUTDOWN
, 0) < 0) {
181 spcs_log("ii", &ustatus
, "iiboot shutdown failed");
182 iiboot_err(NULL
, gettext("SHUTDOWN ioctl error"));
185 } else if (cfg_cluster_tag
!= NULL
&& flag
== DSWIOC_SUSPEND
) {
186 bzero(&ii_suspend
, sizeof (dsw_ioctl_t
));
187 ii_suspend
.status
= spcs_s_ucreate();
188 ii_suspend
.flags
= CV_IS_CLUSTER
;
189 (void) strncpy(ii_suspend
.shadow_vol
, cfg_cluster_tag
,
191 rc
= ioctl(ioctl_fd
, flag
, &ii_suspend
);
192 if ((rc
) && (errno
!= DSW_ECNOTFOUND
)) {
193 spcs_log("ii", &ii_suspend
.status
,
194 "iiboot resume cluster %s failed", cfg_cluster_tag
);
195 iiboot_err(&ii_suspend
.status
, gettext("ioctl error"));
196 spcs_s_ufree(&ii_suspend
.status
);
199 spcs_s_ufree(&ii_suspend
.status
);
202 } else if ((cfg_cluster_tag
!= NULL
) && (flag
== DSWIOC_RESUME
)) {
204 * If we are running in a Sun Cluster, this is a resume
205 * operation, get a list of all shadow volumes, where the
206 * shadow volumes match the shadows of the sets being resumed
208 rc
= ioctl(ioctl_fd
, DSWIOC_LISTLEN
, &args
);
211 "iiboot get LIST failed, errno %d", errno
);
213 gettext("Failed to get LIST of Point-in-Time "
218 args
.status
= spcs_s_ucreate();
220 args
.list_size
= rc
+ 4;
221 lp
= args
.list
= (dsw_config_t
*)
222 malloc(args
.list_size
* sizeof (dsw_config_t
));
223 if (args
.list
== NULL
) {
225 gettext("Failed to allocate memory"));
227 if (ioctl(ioctl_fd
, DSWIOC_LIST
, &args
) == -1) {
228 spcs_log("ii", &args
.status
, "Failed to get LIST");
229 iiboot_err(&args
.status
, gettext("ioctl error"));
231 spcs_s_ufree(&args
.status
);
233 /* Remove all elements that are not in the resume list */
234 for (j
= args
.list_used
; j
; j
--) {
235 for (i
= 0; i
< pairs
; i
++) {
236 if (strcmp(lp
->shadow_vol
,
237 resume_list
[i
].shadow_vol
) == 0) {
238 if (strlen(lp
->cluster_tag
) == 0) {
246 (void) memmove(lp
, lp
+ 1, j
* sizeof (dsw_config_t
));
251 (void) sigset(SIGCHLD
, sigchld
);
252 fork_cnt
= fork_rc
= 0;
253 for (i
= 0; i
< pairs
; i
++) {
254 ustatus
= spcs_s_ucreate();
255 if (flag
== DSWIOC_RESUME
) {
256 ioarg
= (void *) (ii_cfgp
= (resume_list
+ i
));
257 ii_cfgp
->status
= ustatus
;
260 ioarg
= (void *) (ii_iop
= (suspend_list
+ i
));
261 ii_iop
->status
= ustatus
;
263 while (pid
== -1) { /* error forking */
266 /* back off on the max processes and try again */
274 if (pid
> 0) { /* this is parent process */
276 while (fork_cnt
> MAX_PROCESSES
) {
282 rc
= ioctl(ioctl_fd
, flag
, ioarg
);
283 if (rc
== SPCS_S_ERROR
) {
284 if (flag
== DSWIOC_RESUME
)
285 spcs_log("ii", &ustatus
,
286 "iiboot resume %s failed",
287 ii_cfgp
->shadow_vol
);
289 spcs_log("ii", &ustatus
,
290 "iiboot suspend %s failed",
292 iiboot_err(&ustatus
, gettext("ioctl error"));
295 spcs_s_ufree(&ustatus
);
296 if (flag
== DSWIOC_RESUME
)
301 * Allow all processes to finish up before exiting
304 while (fork_cnt
> 0) {
305 (void) alarm(60); /* wake up in 60 secs just in case */
310 /* Disable duplicate shadows that were part of the implicit join */
311 if ((j
= args
.list_used
) != 0) {
313 char key
[CFG_MAX_KEY
], buf
[CFG_MAX_BUF
], sn
[CFG_MAX_BUF
];
315 char *mst
, *shd
, *ctag
;
319 iiboot_err(NULL
, gettext("Failed to fork"));
321 } else if (pid
> 0) {
322 return (0); /* Parent, OK exit */
325 for (j
= args
.list_used
, lp
= args
.list
; j
; j
--, lp
++) {
330 * Open the configuration database
332 if (!(cfg
= cfg_open(""))) {
333 iiboot_err(NULL
, gettext("Failed to open dscfg"));
337 /* Sooner or later, this lock will be free */
338 while (!cfg_lock(cfg
, CFG_WRLOCK
))
341 (void) snprintf(key
, CFG_MAX_KEY
, "ii.set%d", setno
);
342 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
347 /* For imported shadows, master must be special tag */
348 mst
= strtok(buf
, " "); /* master */
349 shd
= strtok(NULL
, " "); /* shadow */
350 (void) strtok(NULL
, " "); /* bitmap */
351 (void) strtok(NULL
, " "); /* mode */
352 (void) strtok(NULL
, " "); /* overflow */
353 ctag
= strtok(NULL
, " "); /* cnode */
356 * For this record to be processed, the shadow volume
357 * name must match and the cluster tag must be blank
359 if (strcmp(lp
->shadow_vol
, shd
) || strcmp(ctag
, "-")) {
364 /* Derrive local cluster tag */
365 if (cfg_l_dgname(lp
->shadow_vol
, sn
, sizeof (sn
)))
368 iiboot_err(NULL
, gettext(
369 "Failed to device group for shadow %s"),
372 /* disable master volume if not imported */
373 if (strcmp(mst
, II_IMPORTED_SHADOW
))
374 if (cfg_vol_disable(cfg
, mst
, cfg_cluster_tag
,
376 iiboot_err(NULL
, gettext(
377 "SV disable of master failed"));
380 * Delete the Imported Shadow set
382 if (cfg_put_cstring(cfg
, key
, NULL
, 0) < 0) {
383 iiboot_err(NULL
, gettext(
384 "Failed to delete Imported shadow %s"),
389 * SV disable shadow volume
391 if (cfg_vol_disable(cfg
, shd
, NULL
, "ii") < 0)
392 iiboot_err(NULL
, gettext(
393 "SV disable of shadow failed"));
398 (void) cfg_commit(cfg
);
402 * Open the configuration database
404 if (!(cfg
= cfg_open(""))) {
405 iiboot_err(NULL
, gettext("Failed to open dscfg"));
409 /* Sooner or later, this lock will be free */
410 while (!cfg_lock(cfg
, CFG_WRLOCK
))
413 /* Set cluster tag for Shadow volume */
414 (void) cfg_vol_enable(cfg
, shd
, ctag
, "ii");
420 (void) cfg_commit(cfg
);
429 set_is_offline(char *cflags
)
434 if (!cflags
|| !*cflags
)
437 /* convert flags to an int */
438 conv
= sscanf(cflags
, "%x", &flags
);
439 return ((conv
== 1) && ((flags
& DSW_OFFLINE
) != 0));
445 * DESCRIPTION: Read the relevant config info via libcfg
448 * int i Number of Point-in-Time Copy sets
450 * Side Effects: The 0 to i-1 entries in the resume_list are filled.
459 char *buf
, **entry
, *mst
, *shd
, *bmp
, *ctag
, *opt
, *ptr
;
462 static int offset
= sizeof (NSKERN_II_BMP_OPTION
);
464 spcs_log("ii", NULL
, "iiboot resume cluster tag %s",
465 cfg_cluster_tag
? cfg_cluster_tag
: "<none>");
466 if ((cfg
= cfg_open("")) == NULL
) {
467 spcs_log("ii", NULL
, "iiboot cfg_open failed, errno %d",
469 iiboot_err(NULL
, gettext("Error opening config"));
472 cfg_resource(cfg
, cfg_cluster_tag
);
473 if (!cfg_lock(cfg
, CFG_RDLOCK
)) {
474 spcs_log("ii", NULL
, "iiboot CFG_RDLOCK failed, errno %d",
476 iiboot_err(NULL
, gettext("Error locking config"));
479 /* Determine number of set, if zero return 0 */
480 if ((n_structs
= cfg_get_section(cfg
, &entry
, "ii")) == 0)
483 resume_list
= calloc(n_structs
, sizeof (*resume_list
));
484 if (resume_list
== NULL
) {
485 spcs_log("ii", NULL
, "iiboot resume realloc failed, errno %d",
487 iiboot_err(NULL
, gettext("Resume realloc failed"));
492 for (i
= 0; i
< n_structs
; i
++) {
494 mst
= strtok(buf
, " ");
495 shd
= strtok(NULL
, " ");
496 bmp
= strtok(NULL
, " ");
497 (void) strtok(NULL
, " "); /* mode */
498 (void) strtok(NULL
, " "); /* overflow */
499 ctag
= strtok(NULL
, " "); /* ctag */
501 ctag
+= strspn(ctag
, "-");
502 opt
= strtok(NULL
, " ");
504 if (!mst
|| !shd
|| !bmp
)
507 /* If cluster tags don't match, skip record */
508 if ((cfg_cluster_tag
&& strcmp(ctag
, cfg_cluster_tag
)) ||
509 (!cfg_cluster_tag
&& strlen(ctag
))) {
514 ptr
= strstr(opt
, NSKERN_II_BMP_OPTION
"=");
515 if (ptr
&& set_is_offline(ptr
+ offset
)) {
520 (void) strncpy(p
->master_vol
, mst
, DSW_NAMELEN
);
521 (void) strncpy(p
->shadow_vol
, shd
, DSW_NAMELEN
);
522 (void) strncpy(p
->bitmap_vol
, bmp
, DSW_NAMELEN
);
524 (void) strncpy(p
->cluster_tag
, ctag
, DSW_NAMELEN
);
530 while (i
< n_structs
)
542 * DESCRIPTION: Read the relevant config info via libcfg
545 * int i Number of Point-in-Time Copy sets
547 * Side Effects: The 0 to i-1 entries in the suspend_list are filled.
557 char buf
[CFG_MAX_BUF
];
558 char key
[CFG_MAX_KEY
];
562 spcs_log("ii", NULL
, "iiboot suspend cluster tag %s",
563 cfg_cluster_tag
? cfg_cluster_tag
: "<none>");
565 if (cfg_cluster_tag
== NULL
) {
569 if ((cfg
= cfg_open("")) == NULL
) {
570 spcs_log("ii", NULL
, "iiboot cfg_open failed, errno %d",
572 iiboot_err(NULL
, gettext("Error opening config"));
575 cfg_resource(cfg
, cfg_cluster_tag
);
576 if (!cfg_lock(cfg
, CFG_RDLOCK
)) {
577 spcs_log("ii", NULL
, "iiboot CFG_RDLOCK failed, errno %d",
579 iiboot_err(NULL
, gettext("Error locking config"));
587 bzero(buf
, CFG_MAX_BUF
);
588 (void) snprintf(key
, sizeof (key
), "ii.set%d", setnumber
);
589 rc
= cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
);
592 if (n_structs
< setnumber
) {
594 suspend_list
= realloc(suspend_list
,
595 sizeof (*suspend_list
) * n_structs
);
596 if (suspend_list
== NULL
) {
598 "iiboot suspend realloc failed, errno %d",
600 iiboot_err(NULL
, gettext("Suspend realloc failed"));
603 p
= suspend_list
+ i
;
605 (void) snprintf(key
, sizeof (key
), "ii.set%d.shadow",
607 (void) cfg_get_cstring(cfg
, key
, p
->shadow_vol
, DSW_NAMELEN
);
617 parseopts(argc
, argv
, flag
)
627 while ((c
= getopt(argc
, argv
, "hrsC:")) != -1) {
632 gettext("-C specified multiple times"));
638 cfg_cluster_tag
= (optarg
[0] == '-') ? NULL
: optarg
;
649 *flag
= DSWIOC_RESUME
;
654 *flag
= DSWIOC_SUSPEND
;
662 iiboot_warn(NULL
, gettext("Invalid argument combination"));
666 if (!*flag
|| errflag
) {
677 (void) fprintf(stderr
, gettext("usage:\n"));
678 (void) fprintf(stderr
,
679 gettext("\t%s -r [-C tag]\t\tresume\n"), program
);
680 (void) fprintf(stderr
,
681 gettext("\t%s -s [-C tag]\t\tsuspend\n"), program
);
682 (void) fprintf(stderr
, gettext("\t%s -h\t\t\tthis help message\n"),