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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Utility to import SVM disksets into an active SVM configuration.
28 */
29
30 #include <assert.h>
31 #include <strings.h>
32 #include <string.h>
33 #include <meta.h>
34 #include <sys/utsname.h>
35 #include <sys/lvm/md_mddb.h>
36 #include <sys/lvm/md_names.h>
37 #include <sdssc.h>
38
39 static md_im_drive_info_t *overlap_disks;
40
41 static void
usage(mdsetname_t * sp,char * string)42 usage(mdsetname_t *sp, char *string)
43 {
44 if ((string != NULL) && (*string != '\0'))
45 md_eprintf("%s\n", string);
46
47 (void) fprintf(stderr,
48 "%s:\t%s -s setname [-n] [-f] [-v] [%s...]\n",
49 gettext("usage"), myname, gettext("disk"));
50 (void) fprintf(stderr, " %s -r [%s...]\n",
51 myname, gettext("disk"));
52 (void) fprintf(stderr, " %s -?\n", myname);
53 (void) fprintf(stderr, " %s -V\n", myname);
54
55 md_exit(sp, (string == NULL) ? 0 : 1);
56 }
57
58 static void
print_version(mdsetname_t * sp)59 print_version(mdsetname_t *sp)
60 {
61 struct utsname curname;
62
63 if (uname(&curname) == -1) {
64 md_eprintf("%s\n", strerror(errno));
65 md_exit(sp, 1);
66 }
67
68 (void) fprintf(stderr, "%s %s\n", myname, curname.version);
69
70 md_exit(sp, 0);
71 }
72
73 /*
74 * Returns 0 if there is no overlap, 1 otherwise
75 */
76 static int
set_disk_overlap(md_im_set_desc_t * misp)77 set_disk_overlap(md_im_set_desc_t *misp)
78 {
79 md_im_set_desc_t *next, *isp = misp;
80 md_im_drive_info_t *set_dr, *next_set_dr, **chain;
81 int is_overlap = 0;
82 md_im_drive_info_t *good_disk = NULL;
83 md_im_drive_info_t *d;
84 md_timeval32_t gooddisktime;
85 int disk_not_available = 0;
86 /*
87 * There are 2 ways we could get an "overlap" disk.
88 * One is if the ctd's are the same. The other is if
89 * the setcreatetimestamp on the disk doesn't agree with the
90 * "good" disk in the set. However, if we have a disk that is
91 * unavailable and the other instance of the ctd is available we
92 * really don't have a conflict. It's just that the unavailable ctd
93 * is it's "old" location and the available instance is a current
94 * location.
95 */
96 for (; isp != NULL; isp = isp->mis_next) {
97 for (next = isp->mis_next; next != NULL; next = next->mis_next) {
98 for (set_dr = isp->mis_drives; set_dr != NULL;
99 set_dr = set_dr->mid_next) {
100 if (set_dr->mid_available == MD_IM_DISK_NOT_AVAILABLE)
101 disk_not_available = 1;
102 else
103 disk_not_available = 0;
104 for (next_set_dr = next->mis_drives; next_set_dr != NULL;
105 next_set_dr = next_set_dr->mid_next) {
106 if (disk_not_available &&
107 (next_set_dr->mid_available
108 == MD_IM_DISK_AVAILABLE))
109 continue;
110 else if (!disk_not_available &&
111 (next_set_dr->mid_available ==
112 MD_IM_DISK_NOT_AVAILABLE))
113 continue;
114 if (strcmp(set_dr->mid_dnp->cname,
115 next_set_dr->mid_dnp->cname) == 0) {
116 /*
117 * Chain it, skip if
118 * already there
119 */
120 if (overlap_disks == NULL) {
121 set_dr->overlap = NULL;
122 set_dr->overlapped_disk = 1;
123 next_set_dr->overlapped_disk = 1;
124 overlap_disks = set_dr;
125 } else {
126 for (chain = &overlap_disks;
127 *chain != NULL;
128 chain = &(*chain)->overlap) {
129 if (strcmp(set_dr->mid_dnp->cname,
130 (*chain)->mid_dnp->cname) == 0)
131 break;
132 }
133
134 if (*chain == NULL) {
135 *chain = set_dr;
136 set_dr->overlap = NULL;
137 set_dr->overlapped_disk = 1;
138 next_set_dr->overlapped_disk = 1;
139 }
140 }
141 if (!is_overlap)
142 is_overlap = 1;
143 }
144 }
145 }
146 }
147 }
148
149 for (isp = misp; isp != NULL; isp = isp->mis_next) {
150 good_disk = pick_good_disk(isp);
151 if (good_disk == NULL) {
152 /* didn't find a good disk */
153 continue;
154 }
155 gooddisktime = good_disk->mid_setcreatetimestamp;
156 for (d = isp->mis_drives; d != NULL; d = d->mid_next) {
157 if (d->mid_available == MD_IM_DISK_NOT_AVAILABLE)
158 continue;
159 /*
160 * If the disk doesn't have the same set creation
161 * time as the designated "good disk" we have a
162 * time conflict/overlap situation. Mark the disk
163 * as such.
164 */
165 if ((gooddisktime.tv_usec !=
166 d->mid_setcreatetimestamp.tv_usec) ||
167 (gooddisktime.tv_sec !=
168 d->mid_setcreatetimestamp.tv_sec)) {
169 d->overlapped_disk = 1;
170 if (overlap_disks == NULL) {
171 d->overlap = NULL;
172 d->overlapped_disk = 1;
173 overlap_disks = d;
174 } else {
175 for (chain = &overlap_disks;
176 *chain != NULL;
177 chain = &(*chain)->overlap) {
178 if (strcmp(d->mid_dnp->cname,
179 (*chain)->mid_dnp->cname)
180 == 0) {
181 break;
182 }
183 }
184
185 if (*chain == NULL) {
186 *chain = d;
187 d->overlap = NULL;
188 d->overlapped_disk = 1;
189 }
190 }
191 if (!is_overlap)
192 is_overlap = 1;
193 }
194 }
195 }
196 return (is_overlap);
197 }
198
199 static void
report_overlap_recommendation()200 report_overlap_recommendation()
201 {
202 mddb_mb_t *mbp;
203 md_error_t status = mdnullerror;
204 md_error_t *ep = &status;
205 md_im_drive_info_t *d;
206
207 (void) fprintf(stdout, "%s\n", gettext("Warning: The following disks "
208 "have been detected in more than one set.\n"
209 "Import recommendation based upon set creation time.\n"
210 "Proceed with the import with caution."));
211
212 /*
213 * Look at all overlapping disks. Determine which slice
214 * would have a replica on it. i.e. either slice 7 or 6.
215 * Then read the master block. If the disk doesn't have a
216 * metadb on it, the master block is a dummy master block.
217 * Both dummy or normal master block contain the timestamp
218 * which is what we are after. Use this timestamp to issue
219 * the appropriate recommendation.
220 */
221 mbp = Malloc(DEV_BSIZE);
222 for (d = overlap_disks; d != NULL; d = d->overlap) {
223 mdname_t *rsp;
224 uint_t sliceno;
225 int fd = -1;
226
227 /*
228 * If the disk isn't available (i.e. powered off or dead)
229 * we can't read the master block timestamp and thus
230 * cannot make a recommendation as to which set it belongs to.
231 */
232 if (d->mid_available != MD_IM_DISK_AVAILABLE) {
233 (void) fprintf(stdout, " %s ", d->mid_dnp->cname);
234 (void) fprintf(stdout,
235 gettext(" - no recommendation can "
236 "be made because disk is unavailable\n"));
237 continue;
238 }
239
240 if (meta_replicaslice(d->mid_dnp, &sliceno, ep) != 0)
241 continue;
242
243 if (d->mid_dnp->vtoc.parts[sliceno].size == 0)
244 continue;
245
246 if ((rsp = metaslicename(d->mid_dnp, sliceno, ep)) == NULL)
247 continue;
248 if ((fd = open(rsp->rname, O_RDONLY| O_NDELAY)) < 0)
249 continue;
250 if (read_master_block(ep, fd, mbp, DEV_BSIZE) <= 0) {
251 (void) close(fd);
252 mdclrerror(ep);
253 continue;
254 }
255 (void) close(fd);
256 (void) fprintf(stdout, " %s ", d->mid_dnp->cname);
257 (void) fprintf(stdout, "%s: %s\n",
258 gettext(" - must import with set "
259 "created at "), meta_print_time((md_timeval32_t *)
260 (&(mbp->mb_setcreatetime))));
261 }
262 Free(mbp);
263 }
264
265 /*
266 * is_first_disk is called to determine if the disk passed to it is
267 * eligible to be used as the "first disk time" in the set. It checks to
268 * see if the disk is available, on the skip list or not (thus already in
269 * an importable set) or being used by the system already.
270 * RETURN:
271 * 1 The time can be used as the first disk time
272 * 0 The time should not be used.
273 */
274 static int
is_first_disk(md_im_drive_info_t * d,mddrivenamelist_t ** skiph)275 is_first_disk(
276 md_im_drive_info_t *d,
277 mddrivenamelist_t **skiph)
278 {
279 mddrivenamelist_t *slp;
280 md_error_t status = mdnullerror;
281 md_error_t *ep = &status;
282 mdsetname_t *sp = metasetname(MD_LOCAL_NAME, ep);
283
284 /*
285 * If a disk is not available there is no
286 * set creation timestamp available.
287 */
288 if (d->mid_available == MD_IM_DISK_AVAILABLE) {
289 /*
290 * We also need to make sure this disk isn't already on
291 * the skip list.
292 */
293 for (slp = *skiph; slp != NULL; slp = slp->next) {
294 if (d->mid_dnp == slp->drivenamep)
295 return (0);
296 }
297 /*
298 * And we need to make sure the drive isn't
299 * currently being used for something else
300 * like a mounted file system or a current
301 * metadevice or in a set.
302 */
303 if (meta_imp_drvused(sp, d->mid_dnp, ep)) {
304 return (0);
305 }
306 } else {
307 return (0);
308 }
309 return (1);
310 }
311
312 /*
313 * Input a list of disks (dnlp), find the sets that are importable, create
314 * a list of these sets (mispp), and a list of the disks within each of these
315 * sets (midp). These lists (mispp and midp) will be used by metaimport.
316 */
process_disks(mddrivenamelist_t * dnlp,mddrivenamelist_t ** skipt,md_im_set_desc_t ** mispp,int flags,int * set_count,int overlap,md_error_t * ep)317 static int process_disks(
318 mddrivenamelist_t *dnlp,
319 mddrivenamelist_t **skipt,
320 md_im_set_desc_t **mispp,
321 int flags,
322 int *set_count,
323 int overlap,
324 md_error_t *ep
325 )
326 {
327 mddrivenamelist_t *dp;
328 int rscount = 0;
329 int hasreplica;
330 md_im_set_desc_t *p;
331 md_im_drive_info_t *d;
332 mddrivenamelist_t **skiph = skipt;
333
334 /* Scan qualified disks */
335 for (dp = dnlp; dp != NULL; dp = dp->next) {
336 mddrivenamelist_t *slp;
337
338 /* is the current drive on the skip list? */
339 for (slp = *skiph; slp != NULL; slp = slp->next) {
340 if (dp->drivenamep == slp->drivenamep)
341 break;
342 }
343 /* drive on the skip list ? */
344 if (slp != NULL)
345 continue;
346
347 /*
348 * In addition to updating the misp list, either verbose or
349 * standard output will be generated.
350 *
351 */
352 hasreplica = meta_get_and_report_set_info(dp, mispp, 0,
353 flags, set_count, overlap, overlap_disks, ep);
354
355 if (hasreplica < 0) {
356 mde_perror(ep, "");
357 mdclrerror(ep);
358 } else {
359
360 rscount += hasreplica;
361
362 /* Eliminate duplicate reporting */
363 if (hasreplica > 0) {
364 md_timeval32_t firstdisktime;
365
366 /*
367 * Go to the tail for the current set
368 */
369 for (p = *mispp; p->mis_next != NULL;
370 p = p->mis_next)
371 ;
372
373 /*
374 * Now look for the set creation timestamp.
375 * If a disk is not available there is no
376 * set creation timestamp available so look
377 * for the first available disk to grab this
378 * information from. We also need to make
379 * sure this disk isn't already on the skip
380 * list. If so go to the next available drive.
381 * And we need to make sure the drive isn't
382 * currently being used for something else
383 * like a mounted file system or a current
384 * metadevice or in a set.
385 */
386 for (d = p->mis_drives; d != NULL;
387 d = d->mid_next) {
388 if (is_first_disk(d, skiph)) {
389 firstdisktime =
390 d->mid_setcreatetimestamp;
391 break;
392 }
393 }
394 for (d = p->mis_drives; d != NULL;
395 d = d->mid_next) {
396 /*
397 * if the mb_setcreatetime for a disk
398 * is not the same as the first disk
399 * in the set, don't put it on the
400 * skip list. This disk probably
401 * doesn't really belong in this set
402 * and we'll want to look at it again
403 * to figure out where it does belong.
404 * If the disk isn't available, there's
405 * really no point in looking at it
406 * again so put it on the skip list.
407 */
408 if (d->mid_available ==
409 MD_IM_DISK_AVAILABLE) {
410 if ((d->mid_setcreatetimestamp.
411 tv_sec != firstdisktime.
412 tv_sec) ||
413 (d->mid_setcreatetimestamp.
414 tv_usec !=
415 firstdisktime.tv_usec))
416 continue;
417 }
418 skipt =
419 meta_drivenamelist_append_wrapper(
420 skipt, d->mid_dnp);
421 }
422 }
423 }
424 }
425 return (rscount);
426 }
427
428 int
main(int argc,char * argv[])429 main(int argc, char *argv[])
430 {
431 char c;
432 md_error_t status = mdnullerror;
433 md_error_t *ep = &status;
434 mdsetname_t *sp = NULL;
435 char *setname_new = NULL;
436 int report_only = 0;
437 int version = 0;
438 bool_t dry_run = 0;
439 md_im_names_t cnames = { 0, NULL };
440 int err_on_prune = 0;
441 mddrivenamelist_t *dnlp = NULL;
442 mddrivenamelist_t *dp;
443 mddrivenamelist_t *skiph = NULL;
444 int rscount = 0;
445 md_im_set_desc_t *pass1_misp = NULL;
446 md_im_set_desc_t *misp = NULL;
447 md_im_set_desc_t **pass1_mispp = &pass1_misp;
448 md_im_set_desc_t **mispp = &misp;
449 mhd_mhiargs_t mhiargs = defmhiargs;
450 int have_multiple_sets = 0;
451 int force = 0;
452 int overlap = 0;
453 uint_t imp_flags = 0;
454 int set_count = 0;
455 int no_quorum = 0;
456
457 /*
458 * Get the locale set up before calling any other routines
459 * with messages to output. Just in case we're not in a build
460 * environment, make sure that TEXT_DOMAIN gets set to
461 * something.
462 */
463 #if !defined(TEXT_DOMAIN)
464 #define TEXT_DOMAIN "SYS_TEST"
465 #endif
466 (void) setlocale(LC_ALL, "");
467 (void) textdomain(TEXT_DOMAIN);
468
469 /*
470 * Check to see if the libsds_sc.so is bound on the
471 * current system. If it is, it means the system is
472 * part of a cluster.
473 *
474 * The import operation is currently not supported
475 * in a SunCluster environment.
476 */
477 if (sdssc_bind_library() != SDSSC_NOT_BOUND) {
478 (void) printf(gettext(
479 "%s: Import operation not supported under SunCluster\n"),
480 argv[0]);
481 exit(0);
482 }
483
484 /* initialize */
485 if (md_init(argc, argv, 0, 1, ep) != 0) {
486 mde_perror(ep, "");
487 md_exit(sp, 1);
488 }
489
490 optind = 1;
491 opterr = 1;
492
493 while ((c = getopt(argc, argv, "frns:vV?")) != -1) {
494 switch (c) {
495
496 case 'f':
497 force = 1;
498 break;
499
500 case 'n':
501 dry_run = 1;
502 break;
503
504 case 'r':
505 report_only = 1;
506 imp_flags |= META_IMP_REPORT;
507 break;
508
509 case 's':
510 setname_new = optarg;
511 break;
512
513 case 'v':
514 imp_flags |= META_IMP_VERBOSE;
515 break;
516
517 case 'V':
518 version = 1;
519 break;
520
521 case '?':
522 default:
523 usage(sp, NULL);
524 break;
525 }
526 }
527
528 if (version == 1)
529 print_version(sp);
530
531 /* Detect conflicting options */
532 if ((dry_run != 0) && (report_only != 0))
533 usage(sp, gettext("The -n and -r options conflict."));
534
535 if ((report_only != 0) && (setname_new != NULL))
536 usage(sp, gettext("The -r and -s options conflict."));
537
538 if ((report_only == 0) && (setname_new == NULL))
539 usage(sp, gettext("You must specify either -r or -s."));
540
541 /* Don't do any real work if we don't have root privilege */
542 if (meta_check_root(ep) != 0) {
543 mde_perror(ep, "");
544 md_exit(sp, 1);
545 }
546
547 if (meta_setup_db_locations(ep) != 0) {
548 mde_perror(ep, "");
549 if (mdismddberror(ep, MDE_DB_STALE))
550 md_exit(sp, 66);
551 if (! mdiserror(ep, MDE_MDDB_CKSUM))
552 md_exit(sp, 1);
553 }
554
555 /*
556 * Read remaining arguments into drive name list, otherwise
557 * call routine to list all drives in system.
558 */
559 if (argc > optind) {
560 int i;
561
562 /* For user specified disks, they MUST not be in use */
563 err_on_prune = 1;
564
565 /* All remaining args should be disks */
566 cnames.min_count = argc - optind;
567 cnames.min_names = Malloc(cnames.min_count * sizeof (char *));
568
569 for (i = 0; i < cnames.min_count; i++, optind++) {
570 mddrivename_t *dnp;
571 dnp = metadrivename(&sp, argv[optind], ep);
572 if (dnp == NULL) {
573 mde_perror(ep, "");
574 md_exit(sp, 1);
575 } else {
576 cnames.min_names[i] = dnp->rname;
577 }
578 }
579 } else {
580 if (meta_list_disks(ep, &cnames) != 0) {
581 mde_perror(ep, "");
582 md_exit(sp, 1);
583 }
584 }
585
586 /*
587 * If the user specified disks on the command line, min_count will be
588 * greater than zero. If they didn't, it should be safe to assume that
589 * the system in question has at least one drive detected by the
590 * snapshot code, or we would have barfed earlier initializing the
591 * metadb.
592 */
593 assert(cnames.min_count > 0);
594
595 /*
596 * Prune the list:
597 * - get rid of drives in current svm configuration
598 * - get rid of mounted drives
599 * - get rid of swap drives
600 * - get rid of drives in other sets
601 *
602 * If drives were specified on the command line, it should be
603 * an error to find in-use disks in the list. (err_on_prune)
604 *
605 * On return from meta_prune_cnames call, dnlp
606 * will have candidate for replica scan.
607 */
608 dnlp = meta_prune_cnames(ep, &cnames, err_on_prune);
609
610 /*
611 * Doctor the drive string in the error structure to list all of the
612 * unused disks, rather than just one. The output will be done in the
613 * following !mdisok() block.
614 */
615 if (mdisdserror(ep, MDE_DS_DRIVEINUSE)) {
616 md_ds_error_t *ip =
617 &ep->info.md_error_info_t_u.ds_error;
618 char *dlist;
619 int sizecnt = 0;
620
621 /* add 1 for null terminator */
622 sizecnt += strlen(ip->drive) + 1;
623 for (dp = dnlp->next; dp != NULL; dp = dp->next) {
624 sizecnt += 2; /* for the ", " */
625 sizecnt += strlen(dp->drivenamep->cname);
626 }
627
628 dlist = Malloc(sizecnt);
629
630 (void) strlcpy(dlist, ip->drive, sizecnt);
631
632 Free(ip->drive);
633 for (dp = dnlp->next; dp != NULL; dp = dp->next) {
634 (void) strlcat(dlist, ", ", sizecnt);
635 (void) strlcat(dlist, dp->drivenamep->cname, sizecnt);
636 }
637
638 ip->drive = dlist;
639 }
640
641 /* Don't continue if we're already hosed */
642 if (!mdisok(ep)) {
643 mde_perror(ep, "");
644 md_exit(sp, 1);
645 }
646
647 /* ...or if there's nothing to scan */
648 if (dnlp == NULL) {
649 md_eprintf("%s\n", gettext("no unused disks detected"));
650 md_exit(sp, 0);
651 }
652
653 /*
654 * META_IMP_PASS1 means gather the info, but don't report.
655 */
656 (void) process_disks(dnlp, &skiph, pass1_mispp,
657 imp_flags | META_IMP_PASS1, &set_count, overlap, ep);
658
659 overlap_disks = NULL;
660 overlap = set_disk_overlap(pass1_misp);
661 skiph = NULL;
662
663 /*
664 * This time call without META_IMP_PASS1 set and we gather
665 * and report the information.
666 * We need to do this twice because of the overlap detection.
667 * The first pass generates a list of disks to detect overlap on.
668 * We then do a second pass using that overlap list to generate
669 * the report.
670 */
671 rscount = process_disks(dnlp, &skiph, mispp, imp_flags, &set_count,
672 overlap, ep);
673
674 /*
675 * Now have entire list of disks associated with diskset including
676 * disks listed in mddb locator blocks and namespace. Before importing
677 * diskset need to recheck that none of these disks is already in use.
678 * If a disk is found that is already in use, print error and exit.
679 */
680 if (!report_only) {
681 md_im_set_desc_t *p;
682 md_im_drive_info_t *d;
683 mddrivename_t *dnp;
684
685 if (sp == NULL) {
686 /* Get sp for local set */
687 if ((sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
688 mde_perror(ep, "");
689 meta_free_im_set_desc(misp);
690 md_exit(sp, 1);
691 }
692 }
693
694 for (p = misp; p != NULL; p = p->mis_next) {
695 for (d = p->mis_drives; d != NULL; d = d->mid_next) {
696 dnp = d->mid_dnp;
697 if (d->mid_available == MD_IM_DISK_AVAILABLE) {
698 if (meta_imp_drvused(sp, dnp, ep)) {
699 (void) mddserror(ep,
700 MDE_DS_DRIVEINUSE, 0, NULL,
701 dnp->cname, NULL);
702 mde_perror(ep, "");
703 meta_free_im_set_desc(misp);
704 md_exit(sp, 1);
705 }
706 } else {
707 /*
708 * If drive is unavailable, then check
709 * that this drive hasn't already been
710 * imported as part of another partial
711 * diskset. Check by devid instead of
712 * cname since the unavailable drive
713 * would have the cname from its
714 * previous system and this may collide
715 * with a valid cname on this system.
716 * Fail if devid is found in another
717 * set or if the routine fails.
718 */
719 mdsetname_t *tmp_sp = NULL;
720
721 if ((meta_is_devid_in_anyset(
722 d->mid_devid, &tmp_sp, ep) == -1) ||
723 (tmp_sp != NULL)) {
724 (void) mddserror(ep,
725 MDE_DS_DRIVEINUSE, 0, NULL,
726 dnp->cname, NULL);
727 mde_perror(ep, "");
728 meta_free_im_set_desc(misp);
729 md_exit(sp, 1);
730 }
731 }
732 }
733 }
734 }
735
736 /*
737 * If there are no unconfigured sets, then our work here is done.
738 * Hopefully this is friendlier than just not printing anything at all.
739 */
740 if (rscount == 0) {
741 /*
742 * If we've found partial disksets but no complete disksets,
743 * we don't want this to print.
744 */
745 if (!misp) {
746 md_eprintf("%s\n", gettext("no unconfigured sets "
747 "detected"));
748 meta_free_im_set_desc(misp);
749 md_exit(sp, 1);
750 }
751 md_exit(sp, 0);
752 }
753
754 /*
755 * We'll need this info for both the report content and the import
756 * decision. By the time we're here, misp should NOT be NULL (or we
757 * would have exited in the rscount == 0 test above).
758 */
759 assert(misp != NULL);
760 if (misp->mis_next != NULL) {
761 have_multiple_sets = 1;
762 }
763 /*
764 * Generate the appropriate (verbose or not) report for all sets
765 * detected. If we're planning on importing later, only include the
766 * "suggested import" command if multiple sets were detected. (That
767 * way, when we error out later, we have still provided useful
768 * information.)
769 */
770
771 /*
772 * Now we should have all the unconfigured sets detected
773 * check for the overlapping
774 */
775 if (have_multiple_sets) {
776 /* Printing out how many candidate disksets we found. */
777 if (imp_flags & META_IMP_REPORT) {
778 (void) printf("%s: %i\n\n",
779 gettext("Number of disksets eligible for import"),
780 set_count);
781 }
782 }
783 if (overlap) {
784 report_overlap_recommendation();
785 }
786
787 if (have_multiple_sets && !report_only) {
788 md_eprintf("%s\n\n", gettext("multiple unconfigured "
789 "sets detected.\nRerun the command with the "
790 "suggested options for the desired set."));
791 }
792
793
794 /*
795 * If it's a report-only request, we're done. If it's an import
796 * request, make sure that we only have one entry in the set list.
797 */
798
799 if (report_only) {
800 meta_free_im_set_desc(misp);
801 md_exit(sp, 0);
802 } else if (have_multiple_sets) {
803 meta_free_im_set_desc(misp);
804 md_exit(sp, 1);
805 } else if (overlap) {
806 md_im_drive_info_t *d;
807 /*
808 * The only way we can get here is if we're doing an import
809 * request on a set that contains at least one disk with
810 * a time conflict. We are prohibiting the importation of
811 * this type of set until the offending disk(s) are turned
812 * off to prevent data corruption.
813 */
814 (void) printf(gettext("To import this set, "));
815 for (d = pass1_misp->mis_drives;
816 d != NULL;
817 d = d->mid_next) {
818 if (d->overlapped_disk)
819 (void) printf("%s ", d->mid_dnp->cname);
820 }
821 (void) printf(gettext("must be removed from the system\n"));
822 meta_free_im_set_desc(misp);
823 md_exit(sp, 1);
824 }
825
826 if (setname_new == NULL) {
827 usage(sp, gettext("You must specify a new set name."));
828 }
829
830 /*
831 * The user must specify the -f (force) flag if the following
832 * conditions exist:
833 * - partial diskset
834 * - stale diskset
835 */
836 if (meta_replica_quorum(misp) != 0)
837 no_quorum = 1;
838 if (misp->mis_partial || no_quorum) {
839 if (!force)
840 usage(sp, gettext("You must specify the force flag"));
841 }
842 (void) meta_imp_set(misp, setname_new, force, dry_run, ep);
843 if (dry_run) {
844 meta_free_im_set_desc(misp);
845 md_exit(sp, 0);
846 }
847
848 if (!mdisok(ep)) {
849 meta_free_im_set_desc(misp);
850 mde_perror(ep, "");
851 md_exit(sp, 1);
852 }
853
854 if ((sp = metasetname(setname_new, ep)) == NULL) {
855 meta_free_im_set_desc(misp);
856 mde_perror(ep, "");
857 md_exit(sp, 1);
858 }
859
860 if (meta_lock_nowait(sp, ep) != 0) {
861 meta_free_im_set_desc(misp);
862 mde_perror(ep, "");
863 md_exit(sp, 10); /* special errcode */
864 }
865
866 if (meta_set_take(sp, &mhiargs, (misp->mis_partial | TAKE_IMP),
867 0, &status)) {
868 meta_free_im_set_desc(misp);
869 mde_perror(&status, "");
870 md_exit(sp, 1);
871 }
872
873 meta_free_im_set_desc(misp);
874 md_exit(sp, 0);
875 /*NOTREACHED*/
876 return (0);
877 }
878