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