1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Utility to import SVM disksets into an active SVM configuration. 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <assert.h> 34*0Sstevel@tonic-gate #include <strings.h> 35*0Sstevel@tonic-gate #include <string.h> 36*0Sstevel@tonic-gate #include <meta.h> 37*0Sstevel@tonic-gate #include <sys/utsname.h> 38*0Sstevel@tonic-gate #include <sys/lvm/md_mddb.h> 39*0Sstevel@tonic-gate #include <sys/lvm/md_names.h> 40*0Sstevel@tonic-gate #include <sdssc.h> 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate static md_im_drive_info_t *overlap_disks = NULL; 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate static void 45*0Sstevel@tonic-gate usage(mdsetname_t *sp, char *string) 46*0Sstevel@tonic-gate { 47*0Sstevel@tonic-gate if ((string != NULL) && (*string != '\0')) 48*0Sstevel@tonic-gate md_eprintf("%s\n", string); 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate (void) fprintf(stderr, 51*0Sstevel@tonic-gate "%s:\t%s -s setname [-n] [-f] [-v] [%s...]\n", 52*0Sstevel@tonic-gate gettext("usage"), myname, gettext("disk")); 53*0Sstevel@tonic-gate (void) fprintf(stderr, " %s -r [%s...]\n", 54*0Sstevel@tonic-gate myname, gettext("disk")); 55*0Sstevel@tonic-gate (void) fprintf(stderr, " %s -?\n", myname); 56*0Sstevel@tonic-gate (void) fprintf(stderr, " %s -V\n", myname); 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate md_exit(sp, (string == NULL) ? 0 : 1); 59*0Sstevel@tonic-gate } 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate static void 62*0Sstevel@tonic-gate print_version(mdsetname_t *sp) 63*0Sstevel@tonic-gate { 64*0Sstevel@tonic-gate struct utsname curname; 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate if (uname(&curname) == -1) { 67*0Sstevel@tonic-gate md_eprintf("%s\n", strerror(errno)); 68*0Sstevel@tonic-gate md_exit(sp, 1); 69*0Sstevel@tonic-gate } 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate (void) fprintf(stderr, "%s %s\n", myname, curname.version); 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate md_exit(sp, 0); 74*0Sstevel@tonic-gate } 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate /* 77*0Sstevel@tonic-gate * Returns 0 if there is no overlap, 1 otherwise 78*0Sstevel@tonic-gate */ 79*0Sstevel@tonic-gate static int 80*0Sstevel@tonic-gate set_disk_overlap(md_im_set_desc_t *misp) 81*0Sstevel@tonic-gate { 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate md_im_set_desc_t *next, *isp = misp; 84*0Sstevel@tonic-gate md_im_drive_info_t *set_dr, *next_set_dr, **chain; 85*0Sstevel@tonic-gate int is_overlap = 0; 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate for (; isp != NULL; isp = isp->mis_next) { 88*0Sstevel@tonic-gate for (next = isp->mis_next; next != NULL; next = next->mis_next) { 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate for (set_dr = isp->mis_drives; set_dr != NULL; 91*0Sstevel@tonic-gate set_dr = set_dr->mid_next) { 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate for (next_set_dr = next->mis_drives; 94*0Sstevel@tonic-gate next_set_dr != NULL; 95*0Sstevel@tonic-gate next_set_dr = next_set_dr->mid_next) { 96*0Sstevel@tonic-gate if (strcmp(set_dr->mid_dnp->cname, 97*0Sstevel@tonic-gate next_set_dr->mid_dnp->cname) == 0) { 98*0Sstevel@tonic-gate /* 99*0Sstevel@tonic-gate * Chain it, skip if already there 100*0Sstevel@tonic-gate */ 101*0Sstevel@tonic-gate if (overlap_disks == NULL) { 102*0Sstevel@tonic-gate set_dr->overlap = NULL; 103*0Sstevel@tonic-gate overlap_disks = set_dr; 104*0Sstevel@tonic-gate } else { 105*0Sstevel@tonic-gate for (chain = &overlap_disks; 106*0Sstevel@tonic-gate *chain != NULL; 107*0Sstevel@tonic-gate chain = &(*chain)->overlap) { 108*0Sstevel@tonic-gate if (strcmp(set_dr->mid_dnp->cname, 109*0Sstevel@tonic-gate (*chain)->mid_dnp->cname) 110*0Sstevel@tonic-gate == 0) 111*0Sstevel@tonic-gate break; 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate if (*chain == NULL) { 115*0Sstevel@tonic-gate *chain = set_dr; 116*0Sstevel@tonic-gate set_dr->overlap = NULL; 117*0Sstevel@tonic-gate } 118*0Sstevel@tonic-gate } 119*0Sstevel@tonic-gate if (!is_overlap) 120*0Sstevel@tonic-gate is_overlap = 1; 121*0Sstevel@tonic-gate } 122*0Sstevel@tonic-gate } 123*0Sstevel@tonic-gate } 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate return (is_overlap); 128*0Sstevel@tonic-gate } 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate static void 131*0Sstevel@tonic-gate report_overlap_recommendation() 132*0Sstevel@tonic-gate { 133*0Sstevel@tonic-gate mddb_mb_t *mbp; 134*0Sstevel@tonic-gate md_error_t status = mdnullerror; 135*0Sstevel@tonic-gate md_error_t *ep = &status; 136*0Sstevel@tonic-gate md_im_drive_info_t *d; 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate (void) fprintf(stdout, "%s\n", gettext("Warning: The following disks " 139*0Sstevel@tonic-gate "have been detected in more than one set.\n" 140*0Sstevel@tonic-gate "Import recommendation based upon set creation time.\n" 141*0Sstevel@tonic-gate "Proceed with the import with caution.")); 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate /* 144*0Sstevel@tonic-gate * Look at all overlapping disks. Determine which slice 145*0Sstevel@tonic-gate * would have a replica on it. i.e. either slice 7 or 6. 146*0Sstevel@tonic-gate * Then read the master block. If the disk doesn't have a 147*0Sstevel@tonic-gate * metadb on it, the master block is a dummy master block. 148*0Sstevel@tonic-gate * Both dummy or normal master block contain the timestamp 149*0Sstevel@tonic-gate * which is what we are after. Use this timestamp to issue 150*0Sstevel@tonic-gate * the appropriate recommendation. 151*0Sstevel@tonic-gate */ 152*0Sstevel@tonic-gate mbp = Malloc(DEV_BSIZE); 153*0Sstevel@tonic-gate for (d = overlap_disks; d != NULL; d = d->overlap) { 154*0Sstevel@tonic-gate mdname_t *rsp; 155*0Sstevel@tonic-gate uint_t sliceno; 156*0Sstevel@tonic-gate int fd = -1; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate if (meta_replicaslice(d->mid_dnp, &sliceno, ep) != 0) 159*0Sstevel@tonic-gate continue; 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate if (d->mid_dnp->vtoc.parts[sliceno].size == 0) 162*0Sstevel@tonic-gate continue; 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate if ((rsp = metaslicename(d->mid_dnp, sliceno, ep)) == NULL) 165*0Sstevel@tonic-gate continue; 166*0Sstevel@tonic-gate if ((fd = open(rsp->rname, O_RDONLY| O_NDELAY)) < 0) 167*0Sstevel@tonic-gate continue; 168*0Sstevel@tonic-gate if (read_master_block(ep, fd, mbp, DEV_BSIZE) <= 0) { 169*0Sstevel@tonic-gate (void) close(fd); 170*0Sstevel@tonic-gate mdclrerror(ep); 171*0Sstevel@tonic-gate continue; 172*0Sstevel@tonic-gate } 173*0Sstevel@tonic-gate (void) close(fd); 174*0Sstevel@tonic-gate fprintf(stdout, " %s ", d->mid_dnp->cname); 175*0Sstevel@tonic-gate (void) fprintf(stdout, "%s: %s\n", 176*0Sstevel@tonic-gate gettext(" - recommend importing with set " 177*0Sstevel@tonic-gate "created at "), meta_print_time((md_timeval32_t *) 178*0Sstevel@tonic-gate (&(mbp->mb_setcreatetime)))); 179*0Sstevel@tonic-gate } 180*0Sstevel@tonic-gate Free(mbp); 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate static void 184*0Sstevel@tonic-gate report_standard(md_im_set_desc_t *s, int do_cmd, int overlap) 185*0Sstevel@tonic-gate { 186*0Sstevel@tonic-gate md_im_drive_info_t *d; 187*0Sstevel@tonic-gate md_im_replica_info_t *r; 188*0Sstevel@tonic-gate md_im_drive_info_t *good_disk = NULL; 189*0Sstevel@tonic-gate int i; 190*0Sstevel@tonic-gate md_timeval32_t firstdisktime; 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate for (i = 0; s != NULL; s = s->mis_next, i++) { 193*0Sstevel@tonic-gate int time_conflict = 0; 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate /* Choose the best drive to use for the import command */ 196*0Sstevel@tonic-gate for (good_disk = NULL, d = s->mis_drives; 197*0Sstevel@tonic-gate d != NULL; d = d->mid_next) { 198*0Sstevel@tonic-gate if (good_disk == NULL) { 199*0Sstevel@tonic-gate for (r = d->mid_replicas; 200*0Sstevel@tonic-gate r != NULL; 201*0Sstevel@tonic-gate r = r->mir_next) { 202*0Sstevel@tonic-gate if (r->mir_flags & MDDB_F_ACTIVE) { 203*0Sstevel@tonic-gate good_disk = d; 204*0Sstevel@tonic-gate break; 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate } 207*0Sstevel@tonic-gate } 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate /* 211*0Sstevel@tonic-gate * Make the distinction between a regular diskset and 212*0Sstevel@tonic-gate * a replicated diskset. 213*0Sstevel@tonic-gate */ 214*0Sstevel@tonic-gate if (s->mis_flags & MD_IM_SET_REPLICATED) { 215*0Sstevel@tonic-gate (void) fprintf(stdout, "%s :\n", 216*0Sstevel@tonic-gate gettext("Replicated diskset found containing disks")); 217*0Sstevel@tonic-gate } else { 218*0Sstevel@tonic-gate (void) fprintf(stdout, "%s :\n", 219*0Sstevel@tonic-gate gettext("Regular diskset found containing disks")); 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate /* 224*0Sstevel@tonic-gate * Save the set creation time from the first disk in the 225*0Sstevel@tonic-gate * diskset and compare the set creation time on all other 226*0Sstevel@tonic-gate * disks in the set to that. If they are the same, the 227*0Sstevel@tonic-gate * disk really belongs here. If they are different the 228*0Sstevel@tonic-gate * disk probably belongs to a different set and we'll 229*0Sstevel@tonic-gate * need to print out a warning. 230*0Sstevel@tonic-gate */ 231*0Sstevel@tonic-gate firstdisktime = s->mis_drives->mid_setcreatetimestamp; 232*0Sstevel@tonic-gate for (d = s->mis_drives; d != NULL; d = d->mid_next) { 233*0Sstevel@tonic-gate if ((firstdisktime.tv_sec == 234*0Sstevel@tonic-gate d->mid_setcreatetimestamp.tv_sec) && 235*0Sstevel@tonic-gate (firstdisktime.tv_usec == 236*0Sstevel@tonic-gate d->mid_setcreatetimestamp.tv_usec)) { 237*0Sstevel@tonic-gate (void) fprintf(stdout, " %s\n", 238*0Sstevel@tonic-gate d->mid_dnp->cname); 239*0Sstevel@tonic-gate } else { 240*0Sstevel@tonic-gate (void) fprintf(stdout, " %s *\n", 241*0Sstevel@tonic-gate d->mid_dnp->cname); 242*0Sstevel@tonic-gate time_conflict = 1; 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate if (time_conflict) { 247*0Sstevel@tonic-gate fprintf(stdout, "* WARNING: This disk has been reused " 248*0Sstevel@tonic-gate "in another set.\n Import may corrupt data in the " 249*0Sstevel@tonic-gate "disk set.\n"); 250*0Sstevel@tonic-gate } 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate if (overlap) { 253*0Sstevel@tonic-gate (void) fprintf(stdout, "%s: %s\n", 254*0Sstevel@tonic-gate gettext("Diskset creation time"), 255*0Sstevel@tonic-gate meta_print_time(&s->mis_drives->mid_replicas-> 256*0Sstevel@tonic-gate mir_timestamp)); 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate /* 260*0Sstevel@tonic-gate * when do_cmd is true, we are not actually importing 261*0Sstevel@tonic-gate * a disk set, but want to print out extra information 262*0Sstevel@tonic-gate */ 263*0Sstevel@tonic-gate if (do_cmd) { 264*0Sstevel@tonic-gate /* 265*0Sstevel@tonic-gate * TRANSLATION_NOTE 266*0Sstevel@tonic-gate * 267*0Sstevel@tonic-gate * The translation of the phrase "For more information 268*0Sstevel@tonic-gate * about this set" will be followed by a ":" and a 269*0Sstevel@tonic-gate * suggested command (untranslatable) that the user 270*0Sstevel@tonic-gate * may use to request additional information. 271*0Sstevel@tonic-gate */ 272*0Sstevel@tonic-gate (void) fprintf(stdout, "%s:\n %s -r -v %s\n", 273*0Sstevel@tonic-gate gettext("For more information about this set"), 274*0Sstevel@tonic-gate myname, good_disk->mid_dnp->cname); 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate /* 277*0Sstevel@tonic-gate * TRANSLATION_NOTE 278*0Sstevel@tonic-gate * 279*0Sstevel@tonic-gate * The translation of the phrase "To import this set" 280*0Sstevel@tonic-gate * will be followed by a ":" and a suggested command 281*0Sstevel@tonic-gate * (untranslatable) that the user may use to import 282*0Sstevel@tonic-gate * the specified diskset. 283*0Sstevel@tonic-gate */ 284*0Sstevel@tonic-gate (void) fprintf(stdout, "%s:\n %s -s <newsetname> %s\n", 285*0Sstevel@tonic-gate gettext("To import this set"), myname, 286*0Sstevel@tonic-gate good_disk->mid_dnp->cname); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate (void) fprintf(stdout, "\n"); 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate if (overlap) { 293*0Sstevel@tonic-gate report_overlap_recommendation(); 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate static void 298*0Sstevel@tonic-gate report_verbose(md_im_set_desc_t *s, int do_cmd, int overlap) 299*0Sstevel@tonic-gate { 300*0Sstevel@tonic-gate md_im_drive_info_t *d; 301*0Sstevel@tonic-gate md_im_replica_info_t *r; 302*0Sstevel@tonic-gate md_im_drive_info_t *good_disk; 303*0Sstevel@tonic-gate static const char fmt1[] = "%-*.*s %12.12s %12.12s %s\n"; 304*0Sstevel@tonic-gate static const char fmt2[] = "%-*.*s %12d %12d "; 305*0Sstevel@tonic-gate int dlen = 0; 306*0Sstevel@tonic-gate int f; 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate for (; s != NULL; s = s->mis_next) { 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate /* 311*0Sstevel@tonic-gate * Run through the drives in this set to find the one with the 312*0Sstevel@tonic-gate * longest common name and the one we want to consider "best" 313*0Sstevel@tonic-gate */ 314*0Sstevel@tonic-gate for (d = s->mis_drives, good_disk = NULL; 315*0Sstevel@tonic-gate d != NULL; d = d->mid_next) { 316*0Sstevel@tonic-gate dlen = max(dlen, strlen(d->mid_dnp->cname)); 317*0Sstevel@tonic-gate for (r = d->mid_replicas; r != NULL; r = r->mir_next) { 318*0Sstevel@tonic-gate if ((good_disk == NULL) && 319*0Sstevel@tonic-gate (r->mir_flags & MDDB_F_ACTIVE)) { 320*0Sstevel@tonic-gate good_disk = d; 321*0Sstevel@tonic-gate break; 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate if (do_cmd) { 327*0Sstevel@tonic-gate (void) fprintf(stdout, "%s: %s -s <newsetname> %s\n", 328*0Sstevel@tonic-gate gettext("To import this set"), myname, 329*0Sstevel@tonic-gate good_disk->mid_dnp->cname); 330*0Sstevel@tonic-gate } 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate (void) fprintf(stdout, "%s: %s\n", gettext("Last update"), 333*0Sstevel@tonic-gate meta_print_time(&good_disk->mid_replicas->mir_timestamp)); 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate /* Make sure the length will hold the column heading */ 337*0Sstevel@tonic-gate dlen = max(dlen, strlen(gettext("Device"))); 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate (void) fprintf(stdout, fmt1, dlen, dlen, gettext("Device"), 340*0Sstevel@tonic-gate gettext("offset"), gettext("length"), 341*0Sstevel@tonic-gate gettext("replica flags")); 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate for (d = s->mis_drives; d != NULL; d = d->mid_next) { 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate if (d->mid_replicas != NULL) { 346*0Sstevel@tonic-gate for (r = d->mid_replicas; 347*0Sstevel@tonic-gate r != NULL; 348*0Sstevel@tonic-gate r = r->mir_next) { 349*0Sstevel@tonic-gate (void) fprintf(stdout, fmt2, dlen, dlen, 350*0Sstevel@tonic-gate (r == d->mid_replicas) ? 351*0Sstevel@tonic-gate d->mid_dnp->cname : "", 352*0Sstevel@tonic-gate r->mir_offset, r->mir_length); 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate for (f = 0; f < MDDB_FLAGS_LEN; f++) { 355*0Sstevel@tonic-gate (void) putchar( 356*0Sstevel@tonic-gate (r->mir_flags & (1 << f)) ? 357*0Sstevel@tonic-gate MDDB_FLAGS_STRING[f] : ' '); 358*0Sstevel@tonic-gate } 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate (void) fprintf(stdout, "\n"); 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate } else { 363*0Sstevel@tonic-gate (void) fprintf(stdout, fmt1, 364*0Sstevel@tonic-gate dlen, dlen, d->mid_dnp->cname, 365*0Sstevel@tonic-gate gettext("no replicas"), "", ""); 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate if (overlap) { 370*0Sstevel@tonic-gate (void) fprintf(stdout, "%s: %s\n", 371*0Sstevel@tonic-gate gettext("Diskset creation time"), 372*0Sstevel@tonic-gate meta_print_time(&s->mis_drives->mid_replicas-> 373*0Sstevel@tonic-gate mir_timestamp)); 374*0Sstevel@tonic-gate } 375*0Sstevel@tonic-gate 376*0Sstevel@tonic-gate (void) fprintf(stdout, "\n"); 377*0Sstevel@tonic-gate } 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate if (overlap) { 380*0Sstevel@tonic-gate report_overlap_recommendation(); 381*0Sstevel@tonic-gate } 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate int 385*0Sstevel@tonic-gate main(int argc, char *argv[]) 386*0Sstevel@tonic-gate { 387*0Sstevel@tonic-gate char c; 388*0Sstevel@tonic-gate md_error_t status = mdnullerror; 389*0Sstevel@tonic-gate md_error_t *ep = &status; 390*0Sstevel@tonic-gate mdsetname_t *sp = NULL; 391*0Sstevel@tonic-gate char *setname_new = NULL; 392*0Sstevel@tonic-gate int report_only = 0; 393*0Sstevel@tonic-gate int verbose = 0; 394*0Sstevel@tonic-gate int version = 0; 395*0Sstevel@tonic-gate bool_t dry_run = 0; 396*0Sstevel@tonic-gate md_im_names_t cnames = { 0, NULL }; 397*0Sstevel@tonic-gate int err_on_prune = 0; 398*0Sstevel@tonic-gate mddrivenamelist_t *dnlp = NULL; 399*0Sstevel@tonic-gate mddrivenamelist_t *dp; 400*0Sstevel@tonic-gate mddrivenamelist_t *skiph = NULL; 401*0Sstevel@tonic-gate mddrivenamelist_t **skipt = &skiph; 402*0Sstevel@tonic-gate int rscount = 0; 403*0Sstevel@tonic-gate int hasreplica; 404*0Sstevel@tonic-gate md_im_set_desc_t *misp = NULL; 405*0Sstevel@tonic-gate md_im_set_desc_t **mispp = &misp; 406*0Sstevel@tonic-gate mhd_mhiargs_t mhiargs = defmhiargs; 407*0Sstevel@tonic-gate int have_multiple_sets = 0; 408*0Sstevel@tonic-gate int force = 0; 409*0Sstevel@tonic-gate int overlap = 0; 410*0Sstevel@tonic-gate int partial = 0; 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate /* 413*0Sstevel@tonic-gate * Get the locale set up before calling any other routines 414*0Sstevel@tonic-gate * with messages to output. Just in case we're not in a build 415*0Sstevel@tonic-gate * environment, make sure that TEXT_DOMAIN gets set to 416*0Sstevel@tonic-gate * something. 417*0Sstevel@tonic-gate */ 418*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 419*0Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 420*0Sstevel@tonic-gate #endif 421*0Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 422*0Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate /* 425*0Sstevel@tonic-gate * Check to see if the libsds_sc.so is bound on the 426*0Sstevel@tonic-gate * current system. If it is, it means the system is 427*0Sstevel@tonic-gate * part of a cluster. 428*0Sstevel@tonic-gate * 429*0Sstevel@tonic-gate * The import operation is currently not supported 430*0Sstevel@tonic-gate * in a SunCluster environment. 431*0Sstevel@tonic-gate */ 432*0Sstevel@tonic-gate if (sdssc_bind_library() != SDSSC_NOT_BOUND) { 433*0Sstevel@tonic-gate printf(gettext( 434*0Sstevel@tonic-gate "%s: Import operation not supported under SunCluster\n"), 435*0Sstevel@tonic-gate argv[0]); 436*0Sstevel@tonic-gate exit(0); 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate /* initialize */ 440*0Sstevel@tonic-gate if (md_init(argc, argv, 0, 1, ep) != 0) { 441*0Sstevel@tonic-gate mde_perror(ep, ""); 442*0Sstevel@tonic-gate md_exit(sp, 1); 443*0Sstevel@tonic-gate } 444*0Sstevel@tonic-gate 445*0Sstevel@tonic-gate optind = 1; 446*0Sstevel@tonic-gate opterr = 1; 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate while ((c = getopt(argc, argv, "frns:vV?")) != -1) { 449*0Sstevel@tonic-gate switch (c) { 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate case 'f': 452*0Sstevel@tonic-gate force = 1; 453*0Sstevel@tonic-gate break; 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate case 'n': 456*0Sstevel@tonic-gate dry_run = 1; 457*0Sstevel@tonic-gate break; 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate case 'r': 460*0Sstevel@tonic-gate report_only = 1; 461*0Sstevel@tonic-gate break; 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate case 's': 464*0Sstevel@tonic-gate setname_new = optarg; 465*0Sstevel@tonic-gate break; 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate case 'v': 468*0Sstevel@tonic-gate verbose = 1; 469*0Sstevel@tonic-gate break; 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate case 'V': 472*0Sstevel@tonic-gate version = 1; 473*0Sstevel@tonic-gate break; 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate case '?': 476*0Sstevel@tonic-gate default: 477*0Sstevel@tonic-gate usage(sp, NULL); 478*0Sstevel@tonic-gate break; 479*0Sstevel@tonic-gate } 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate if (version == 1) 483*0Sstevel@tonic-gate print_version(sp); 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate /* Detect conflicting options */ 486*0Sstevel@tonic-gate if ((dry_run != 0) && (report_only != 0)) 487*0Sstevel@tonic-gate usage(sp, gettext("The -n and -r options conflict.")); 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate if ((report_only != 0) && (setname_new != NULL)) 490*0Sstevel@tonic-gate usage(sp, gettext("The -r and -s options conflict.")); 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate if ((report_only == 0) && (setname_new == NULL)) 493*0Sstevel@tonic-gate usage(sp, gettext("You must specify either -r or -s.")); 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate /* Don't do any real work if we don't have root privilege */ 496*0Sstevel@tonic-gate if (meta_check_root(ep) != 0) { 497*0Sstevel@tonic-gate mde_perror(ep, ""); 498*0Sstevel@tonic-gate md_exit(sp, 1); 499*0Sstevel@tonic-gate } 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate if (meta_setup_db_locations(ep) != 0) { 502*0Sstevel@tonic-gate mde_perror(ep, ""); 503*0Sstevel@tonic-gate if (mdismddberror(ep, MDE_DB_STALE)) 504*0Sstevel@tonic-gate md_exit(sp, 66); 505*0Sstevel@tonic-gate if (! mdiserror(ep, MDE_MDDB_CKSUM)) 506*0Sstevel@tonic-gate md_exit(sp, 1); 507*0Sstevel@tonic-gate } 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate /* 510*0Sstevel@tonic-gate * Read remaining arguments into drive name list, otherwise 511*0Sstevel@tonic-gate * call routine to list all drives in system. 512*0Sstevel@tonic-gate */ 513*0Sstevel@tonic-gate if (argc > optind) { 514*0Sstevel@tonic-gate int i; 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate /* For user specified disks, they MUST not be in use */ 517*0Sstevel@tonic-gate err_on_prune = 1; 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate /* All remaining args should be disks */ 520*0Sstevel@tonic-gate cnames.min_count = argc - optind; 521*0Sstevel@tonic-gate cnames.min_names = Malloc(cnames.min_count * sizeof (char *)); 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate for (i = 0; i < cnames.min_count; i++, optind++) { 524*0Sstevel@tonic-gate mddrivename_t *dnp; 525*0Sstevel@tonic-gate dnp = metadrivename(&sp, argv[optind], ep); 526*0Sstevel@tonic-gate if (dnp == NULL) { 527*0Sstevel@tonic-gate mde_perror(ep, ""); 528*0Sstevel@tonic-gate md_exit(sp, 1); 529*0Sstevel@tonic-gate } else { 530*0Sstevel@tonic-gate cnames.min_names[i] = dnp->rname; 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate } 533*0Sstevel@tonic-gate } else { 534*0Sstevel@tonic-gate if (meta_list_disks(ep, &cnames) != 0) { 535*0Sstevel@tonic-gate mde_perror(ep, ""); 536*0Sstevel@tonic-gate md_exit(sp, 1); 537*0Sstevel@tonic-gate } 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate /* 541*0Sstevel@tonic-gate * If the user specified disks on the command line, min_count will be 542*0Sstevel@tonic-gate * greater than zero. If they didn't, it should be safe to assume that 543*0Sstevel@tonic-gate * the system in question has at least one drive detected by the 544*0Sstevel@tonic-gate * snapshot code, or we would have barfed earlier initializing the 545*0Sstevel@tonic-gate * metadb. 546*0Sstevel@tonic-gate */ 547*0Sstevel@tonic-gate assert(cnames.min_count > 0); 548*0Sstevel@tonic-gate 549*0Sstevel@tonic-gate /* 550*0Sstevel@tonic-gate * Prune the list: 551*0Sstevel@tonic-gate * - get rid of drives in current svm configuration 552*0Sstevel@tonic-gate * - get rid of mounted drives 553*0Sstevel@tonic-gate * - get rid of swap drives 554*0Sstevel@tonic-gate * - get rid of drives in other sets 555*0Sstevel@tonic-gate * 556*0Sstevel@tonic-gate * If drives were specified on the command line, it should be 557*0Sstevel@tonic-gate * an error to find in-use disks in the list. (err_on_prune) 558*0Sstevel@tonic-gate * 559*0Sstevel@tonic-gate * On return from meta_prune_cnames call, dnlp 560*0Sstevel@tonic-gate * will have candidate for replica scan. 561*0Sstevel@tonic-gate */ 562*0Sstevel@tonic-gate dnlp = meta_prune_cnames(ep, &cnames, err_on_prune); 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate /* 565*0Sstevel@tonic-gate * Doctor the drive string in the error structure to list all of the 566*0Sstevel@tonic-gate * unused disks, rather than just one. The output will be done in the 567*0Sstevel@tonic-gate * following !mdisok() block. 568*0Sstevel@tonic-gate */ 569*0Sstevel@tonic-gate if (mdisdserror(ep, MDE_DS_DRIVEINUSE)) { 570*0Sstevel@tonic-gate md_ds_error_t *ip = 571*0Sstevel@tonic-gate &ep->info.md_error_info_t_u.ds_error; 572*0Sstevel@tonic-gate char *dlist; 573*0Sstevel@tonic-gate int sizecnt = 0; 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate sizecnt += strlen(ip->drive); 576*0Sstevel@tonic-gate for (dp = dnlp->next; dp != NULL; dp = dp->next) { 577*0Sstevel@tonic-gate sizecnt += 2; /* for the ", " */ 578*0Sstevel@tonic-gate sizecnt += strlen(dp->drivenamep->cname); 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate dlist = Malloc(sizecnt); 582*0Sstevel@tonic-gate 583*0Sstevel@tonic-gate strlcpy(dlist, ip->drive, sizecnt); 584*0Sstevel@tonic-gate Free(ip->drive); 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate dlist += strlen(ip->drive); 587*0Sstevel@tonic-gate for (dp = dnlp->next; dp != NULL; dp = dp->next) { 588*0Sstevel@tonic-gate strlcat(dlist, ", ", sizecnt); 589*0Sstevel@tonic-gate strlcat(dlist, dp->drivenamep->cname, sizecnt); 590*0Sstevel@tonic-gate } 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate ip->drive = Strdup(dlist); 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate /* Don't continue if we're already hosed */ 596*0Sstevel@tonic-gate if (!mdisok(ep)) { 597*0Sstevel@tonic-gate mde_perror(ep, ""); 598*0Sstevel@tonic-gate md_exit(sp, 1); 599*0Sstevel@tonic-gate } 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate /* ...or if there's nothing to scan */ 602*0Sstevel@tonic-gate if (dnlp == NULL) { 603*0Sstevel@tonic-gate md_eprintf("%s\n", gettext("no unused disks detected")); 604*0Sstevel@tonic-gate md_exit(sp, 0); 605*0Sstevel@tonic-gate } 606*0Sstevel@tonic-gate 607*0Sstevel@tonic-gate /* Scan qualified disks */ 608*0Sstevel@tonic-gate for (dp = dnlp; dp != NULL; dp = dp->next) { 609*0Sstevel@tonic-gate mddrivenamelist_t *slp; 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate /* is the current drive on the skip list? */ 612*0Sstevel@tonic-gate for (slp = skiph; slp != NULL; slp = slp->next) { 613*0Sstevel@tonic-gate if (dp->drivenamep == slp->drivenamep) 614*0Sstevel@tonic-gate goto skipdisk; 615*0Sstevel@tonic-gate } 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate hasreplica = meta_get_set_info(dp, mispp, 0, ep); 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate /* 620*0Sstevel@tonic-gate * If current disk is part of a partial diskset, 621*0Sstevel@tonic-gate * meta_get_set_info returns an ENOTSUP for this disk. 622*0Sstevel@tonic-gate * Import of partial disksets isn't supported yet, 623*0Sstevel@tonic-gate * so do NOT put this disk onto any list being set up 624*0Sstevel@tonic-gate * by metaimport. The partial diskset error message will 625*0Sstevel@tonic-gate * only be printed once when the first partial diskset is 626*0Sstevel@tonic-gate * detected. If the user is actually trying to import the 627*0Sstevel@tonic-gate * partial diskset, print the error and exit; otherwise, 628*0Sstevel@tonic-gate * print the error and continue. 629*0Sstevel@tonic-gate */ 630*0Sstevel@tonic-gate if (hasreplica == ENOTSUP) { 631*0Sstevel@tonic-gate if (report_only) { 632*0Sstevel@tonic-gate if (!partial) { 633*0Sstevel@tonic-gate mde_perror(ep, ""); 634*0Sstevel@tonic-gate partial = 1; 635*0Sstevel@tonic-gate } 636*0Sstevel@tonic-gate mdclrerror(ep); 637*0Sstevel@tonic-gate goto skipdisk; 638*0Sstevel@tonic-gate } else { 639*0Sstevel@tonic-gate mde_perror(ep, ""); 640*0Sstevel@tonic-gate md_exit(sp, 1); 641*0Sstevel@tonic-gate } 642*0Sstevel@tonic-gate } 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate if (hasreplica < 0) { 645*0Sstevel@tonic-gate mde_perror(ep, ""); 646*0Sstevel@tonic-gate mdclrerror(ep); 647*0Sstevel@tonic-gate } else { 648*0Sstevel@tonic-gate md_im_set_desc_t *p; 649*0Sstevel@tonic-gate md_im_drive_info_t *d; 650*0Sstevel@tonic-gate 651*0Sstevel@tonic-gate rscount += hasreplica; 652*0Sstevel@tonic-gate 653*0Sstevel@tonic-gate /* Eliminate duplicate reporting */ 654*0Sstevel@tonic-gate if (hasreplica > 0) { 655*0Sstevel@tonic-gate md_timeval32_t firstdisktime; 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate /* 658*0Sstevel@tonic-gate * Go to the tail for the current set 659*0Sstevel@tonic-gate */ 660*0Sstevel@tonic-gate for (p = misp; p->mis_next != NULL; 661*0Sstevel@tonic-gate p = p->mis_next); 662*0Sstevel@tonic-gate firstdisktime = 663*0Sstevel@tonic-gate p->mis_drives->mid_setcreatetimestamp; 664*0Sstevel@tonic-gate for (d = p->mis_drives; 665*0Sstevel@tonic-gate d != NULL; 666*0Sstevel@tonic-gate d = d->mid_next) { 667*0Sstevel@tonic-gate /* 668*0Sstevel@tonic-gate * if the mb_setcreatetime for a disk 669*0Sstevel@tonic-gate * is not the same as the first disk 670*0Sstevel@tonic-gate * in the set, don't put it on the 671*0Sstevel@tonic-gate * skip list. This disk probably 672*0Sstevel@tonic-gate * doesn't really belong in this set 673*0Sstevel@tonic-gate * and we'll want to look at it again 674*0Sstevel@tonic-gate * to figure out where it does belong. 675*0Sstevel@tonic-gate */ 676*0Sstevel@tonic-gate if ((d->mid_setcreatetimestamp.tv_sec != 677*0Sstevel@tonic-gate firstdisktime.tv_sec) || 678*0Sstevel@tonic-gate (d->mid_setcreatetimestamp.tv_usec 679*0Sstevel@tonic-gate != firstdisktime.tv_usec)) 680*0Sstevel@tonic-gate continue; 681*0Sstevel@tonic-gate skipt = 682*0Sstevel@tonic-gate meta_drivenamelist_append_wrapper( 683*0Sstevel@tonic-gate skipt, d->mid_dnp); 684*0Sstevel@tonic-gate } 685*0Sstevel@tonic-gate } 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate skipdisk: 689*0Sstevel@tonic-gate ; 690*0Sstevel@tonic-gate } 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate /* 693*0Sstevel@tonic-gate * Now have entire list of disks associated with diskset including 694*0Sstevel@tonic-gate * disks listed in mddb locator blocks and namespace. Before importing 695*0Sstevel@tonic-gate * diskset need to recheck that none of these disks is already in use. 696*0Sstevel@tonic-gate * If a disk is found that is already in use, print error and exit. 697*0Sstevel@tonic-gate */ 698*0Sstevel@tonic-gate if (!report_only) { 699*0Sstevel@tonic-gate md_im_set_desc_t *p; 700*0Sstevel@tonic-gate md_im_drive_info_t *d; 701*0Sstevel@tonic-gate mddrivename_t *dnp; 702*0Sstevel@tonic-gate 703*0Sstevel@tonic-gate for (p = misp; p != NULL; p = p->mis_next) { 704*0Sstevel@tonic-gate for (d = p->mis_drives; d != NULL; d = d->mid_next) { 705*0Sstevel@tonic-gate dnp = d->mid_dnp; 706*0Sstevel@tonic-gate if (meta_imp_drvused(sp, dnp, ep)) { 707*0Sstevel@tonic-gate (void) mddserror(ep, 708*0Sstevel@tonic-gate MDE_DS_DRIVEINUSE, 0, NULL, 709*0Sstevel@tonic-gate dnp->cname, NULL); 710*0Sstevel@tonic-gate mde_perror(ep, ""); 711*0Sstevel@tonic-gate md_exit(sp, 0); 712*0Sstevel@tonic-gate } 713*0Sstevel@tonic-gate } 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate } 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate /* 718*0Sstevel@tonic-gate * If there are no unconfigured sets, then our work here is done. 719*0Sstevel@tonic-gate * Hopefully this is friendlier than just not printing anything at all. 720*0Sstevel@tonic-gate */ 721*0Sstevel@tonic-gate if (rscount == 0) { 722*0Sstevel@tonic-gate md_eprintf("%s\n", gettext("no unconfigured sets detected")); 723*0Sstevel@tonic-gate md_exit(sp, 0); 724*0Sstevel@tonic-gate } 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate /* 727*0Sstevel@tonic-gate * We'll need this info for both the report content and the import 728*0Sstevel@tonic-gate * decision. By the time we're here, misp should NOT be NULL (or we 729*0Sstevel@tonic-gate * would have exited in the rscount == 0 test above). 730*0Sstevel@tonic-gate */ 731*0Sstevel@tonic-gate assert(misp != NULL); 732*0Sstevel@tonic-gate if (misp->mis_next != NULL) { 733*0Sstevel@tonic-gate have_multiple_sets = 1; 734*0Sstevel@tonic-gate } 735*0Sstevel@tonic-gate 736*0Sstevel@tonic-gate /* 737*0Sstevel@tonic-gate * Generate the appropriate (verbose or not) report for all sets 738*0Sstevel@tonic-gate * detected. If we're planning on importing later, only include the 739*0Sstevel@tonic-gate * "suggested import" command if multiple sets were detected. (That 740*0Sstevel@tonic-gate * way, when we error out later, we have still provided useful 741*0Sstevel@tonic-gate * information.) 742*0Sstevel@tonic-gate */ 743*0Sstevel@tonic-gate 744*0Sstevel@tonic-gate /* 745*0Sstevel@tonic-gate * Now we should have all the unconfigured sets detected 746*0Sstevel@tonic-gate * check for the overlapping 747*0Sstevel@tonic-gate */ 748*0Sstevel@tonic-gate if (have_multiple_sets) { 749*0Sstevel@tonic-gate overlap = set_disk_overlap(misp); 750*0Sstevel@tonic-gate if (!report_only) { 751*0Sstevel@tonic-gate md_eprintf("%s\n\n", gettext("multiple unconfigured " 752*0Sstevel@tonic-gate "sets detected.\nRerun the command with the " 753*0Sstevel@tonic-gate "suggested options for the desired set.")); 754*0Sstevel@tonic-gate } 755*0Sstevel@tonic-gate } 756*0Sstevel@tonic-gate 757*0Sstevel@tonic-gate if (verbose) { 758*0Sstevel@tonic-gate report_verbose(misp, (report_only || have_multiple_sets), overlap); 759*0Sstevel@tonic-gate } else { 760*0Sstevel@tonic-gate report_standard(misp, (report_only || have_multiple_sets), overlap); 761*0Sstevel@tonic-gate } 762*0Sstevel@tonic-gate 763*0Sstevel@tonic-gate /* 764*0Sstevel@tonic-gate * If it's a report-only request, we're done. If it's an import 765*0Sstevel@tonic-gate * request, make sure that we only have one entry in the set list. 766*0Sstevel@tonic-gate */ 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate if (report_only) { 769*0Sstevel@tonic-gate md_exit(sp, 0); 770*0Sstevel@tonic-gate } else if (have_multiple_sets) { 771*0Sstevel@tonic-gate md_exit(sp, 1); 772*0Sstevel@tonic-gate } 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate if (setname_new == NULL) { 775*0Sstevel@tonic-gate usage(sp, gettext("You must specify a new set name.")); 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate (void) meta_imp_set(misp, setname_new, force, dry_run, ep); 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate if (dry_run) { 781*0Sstevel@tonic-gate md_exit(sp, 0); 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate if (!mdisok(ep)) { 785*0Sstevel@tonic-gate mde_perror(ep, ""); 786*0Sstevel@tonic-gate md_exit(sp, 1); 787*0Sstevel@tonic-gate } 788*0Sstevel@tonic-gate 789*0Sstevel@tonic-gate if ((sp = metasetname(setname_new, ep)) == NULL) { 790*0Sstevel@tonic-gate mde_perror(ep, ""); 791*0Sstevel@tonic-gate md_exit(sp, 1); 792*0Sstevel@tonic-gate } 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate if (meta_lock_nowait(sp, ep) != 0) { 795*0Sstevel@tonic-gate mde_perror(ep, ""); 796*0Sstevel@tonic-gate md_exit(sp, 10); /* special errcode */ 797*0Sstevel@tonic-gate } 798*0Sstevel@tonic-gate 799*0Sstevel@tonic-gate if (meta_set_take(sp, &mhiargs, 0, 0, &status)) { 800*0Sstevel@tonic-gate mde_perror(&status, ""); 801*0Sstevel@tonic-gate md_exit(sp, 1); 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate md_exit(sp, 0); 805*0Sstevel@tonic-gate /*NOTREACHED*/ 806*0Sstevel@tonic-gate return (0); 807*0Sstevel@tonic-gate } 808