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 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 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 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 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 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 */ 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 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