/* * get swap info */ static int get_swapinfo( struct swaptable **swtpp, int *nswap, md_error_t *ep ) { int i; size_t swtsize; *swtpp = NULL; /* get number of entries */ if ((*nswap = swapctl(SC_GETNSWP, NULL)) < 0) { return (mdsyserror(ep, errno, "swapctl(SC_GETNSWP)")); } /* allocate structure */ swtsize = sizeof ((*swtpp)->swt_n) + ((*nswap) * sizeof ((*swtpp)->swt_ent[0])); *swtpp = (struct swaptable *)Zalloc(swtsize); (*swtpp)->swt_n = *nswap; for (i = 0; (i < (*nswap)); ++i) (*swtpp)->swt_ent[i].ste_path = Zalloc(MAXPATHLEN); /* get info */ if (((*nswap) = swapctl(SC_LIST, (*swtpp))) < 0) { (void) mdsyserror(ep, errno, "swapctl(SC_LIST)"); free_swapinfo(*swtpp); return (-1); } /* return success */ return (0); }
/* * steal and convert mherror_t */ int mhstealerror( mhd_error_t *mhep, md_error_t *ep ) { int rval = -1; /* no error */ if (mhep->errnum == 0) { /* assert(mhep->name == NULL); */ rval = 0; goto out; } /* steal error */ switch (mhep->errnum) { case MHD_E_MAJORITY: (void) mderror(ep, MDE_TAKE_OWN, mhep->name); break; case MHD_E_RESERVED: (void) mderror(ep, MDE_RESERVED, mhep->name); break; default: (void) mdsyserror(ep, mhep->errnum, mhep->name); break; } /* cleanup, return success */ out: if (mhep->name != NULL) Free(mhep->name); (void) memset(mhep, 0, sizeof (*mhep)); return (rval); }
/* * Named service entry point: MDRNM_CHECK */ intptr_t stripe_rename_check( md_rendelta_t *delta, md_rentxn_t *rtxnp) { int err = 0; ASSERT(delta); ASSERT(rtxnp); ASSERT(delta->unp); ASSERT(delta->uip); ASSERT((rtxnp->op == MDRNOP_RENAME) || (MDRNOP_EXCHANGE == rtxnp->op)); if (!delta || !rtxnp || !delta->uip || !delta->unp) { (void) mdsyserror(&rtxnp->mde, EINVAL); return (EINVAL); } /* self does additional checks */ if (delta->old_role == MDRR_SELF) { err = stripe_may_renexch_self((ms_unit_t *)delta->unp, delta->uip, rtxnp); } out: return (err); }
/* * check AUTH_SYS */ static int check_sys( struct svc_req *rqstp, /* RPC stuff */ int amode, /* R_OK | W_OK */ md_error_t *ep /* returned status */ ) { static mutex_t mx = DEFAULTMUTEX; struct authsys_parms *sys_credp; /* for read, anything is OK */ if (! (amode & W_OK)) return (0); /* single thread (not really needed if daemon stays single threaded) */ mutex_lock(&mx); /* check for remote root or METAD_GID */ /*LINTED*/ sys_credp = (struct authsys_parms *)rqstp->rq_clntcred; if ((check_gid14(sys_credp->aup_uid) == 0) || (check_host(rqstp) == 0)) { mutex_unlock(&mx); return (0); } /* return failure */ mutex_unlock(&mx); return (mdsyserror(ep, EACCES, "rpc.metad")); }
/* * Is a file system currently mounted on this disk drive? */ int meta_check_drivemounted( mdsetname_t *sp, mddrivename_t *dnp, md_error_t *ep ) { FILE *mfp; struct mnttab m; int rval = 0; char mountp[MNT_LINE_MAX]; char mnt_special[MNT_LINE_MAX]; /* should have a set */ assert(sp != NULL); /* look in mnttab */ if ((mfp = open_mnttab()) == NULL) return (mdsyserror(ep, errno, MNTTAB)); while ((getmntent(mfp, &m) == 0) && (rval == 0)) { char **fstype = skip_these_mntents; int skipit = 0; mdname_t *mnp; if ((m.mnt_special == NULL) || (m.mnt_mountp == NULL)) continue; if (m.mnt_mountp[0] != '/') continue; while (*fstype != NULL) if (strcmp(m.mnt_fstype, *fstype++) == 0) { skipit++; break; } if (skipit == 1) continue; (void) strcpy(mountp, m.mnt_mountp); (void) strcpy(mnt_special, m.mnt_special); if ((mnp = metaname(&sp, mnt_special, LOGICAL_DEVICE, ep)) == NULL) { mdclrerror(ep); continue; } if (strcmp(dnp->cname, mnp->drivenamep->cname) == 0) { rval = mduseerror(ep, MDE_IS_MOUNTED, NODEV64, mountp, dnp->cname); } } /* return success */ return (rval); }
/* * set filesystem device name in vfstab */ int meta_patch_fsdev( char *fsname, /* filesystem mount point */ mdname_t *fsnp, /* filesystem device */ char *vname, /* vfstab file name */ md_error_t *ep /* returned error */ ) { int doit = 1; int verbose = 0; char *tvname = NULL; int rval = -1; /* check names */ assert(fsname != NULL); if (vname == NULL) vname = "/etc/vfstab"; /* replace lines in vfstab */ if (meta_patch_vfstab(fsname, fsnp, vname, NULL, doit, verbose, &tvname, ep) != 0) { goto out; } /* rename temp file on top of real one */ if (rename(tvname, vname) != 0) { (void) mdsyserror(ep, errno, vname); goto out; } Free(tvname); tvname = NULL; rval = 0; /* cleanup, return error */ out: if (tvname != NULL) { if (doit) (void) unlink(tvname); Free(tvname); } return (rval); }
/* * Return the current root filesystem block device name */ void * meta_get_current_root( md_error_t *ep ) { FILE *fp; struct mnttab mp; if ((fp = open_mnttab()) == NULL) { (void) mdsyserror(ep, errno, MNTTAB); return (NULL); } while (getmntent(fp, &mp) == 0) { if (strcmp(mp.mnt_mountp, "/") == 0) return (mp.mnt_special); } (void) mderror(ep, MDE_NOROOT, NULL); return (NULL); }
/* * check whether device is a dump device */ static int meta_check_dump( mdsetname_t *sp, mdname_t *np, md_error_t *ep ) { int rval = 0; int dump_fd; char device[MAXPATHLEN]; if ((dump_fd = open("/dev/dump", O_RDONLY)) < 0) return (mdsyserror(ep, errno, "/dev/dump")); if (ioctl(dump_fd, DIOCGETDEV, device) != -1) { mdname_t *dump_np; if ((dump_np = metaname(&sp, device, UNKNOWN, ep)) == NULL) { mdclrerror(ep); (void) close(dump_fd); return (0); } if (np->dev == dump_np->dev) { rval = mddeverror(ep, MDE_IS_DUMP, np->dev, np->cname); } else { /* not a dump device - but does it overlap? */ rval = meta_check_overlap(dump_np->cname, np, 0, -1, dump_np, 0, -1, ep); if (rval != 0) { (void) mdoverlaperror(ep, MDE_OVERLAP_DUMP, np->cname, NULL, dump_np->cname); } } } (void) close(dump_fd); return (rval); }
/* * patch filesystem lines into vfstab file, return tempfilename */ int meta_patch_vfstab( char *cmpname, /* filesystem mount point or */ /* "swap" if updating swap partition */ mdname_t *fsnp, /* filesystem device name */ char *vname, /* vfstab file name */ char *old_bdevname, /* old name of block device, needed */ /* for deciding which of multiple */ /* swap file entries to change */ /* if NULL then not changing swap */ int doit, /* really patch file */ int verbose, /* show what we're doing */ char **tname, /* returned temp file name */ md_error_t *ep /* returned error */ ) { char *chrname = fsnp->rname; char *blkname = fsnp->bname; FILE *fp = NULL; FILE *tfp = NULL; struct stat sbuf; char buf[512]; char cdev[512]; char bdev[512]; char mntpt[512]; char fstype[512]; char fsckpass[512]; char mntboot[512]; char mntopt[512]; int gotfs = 0; char *cmpstr = &mntpt[0]; /* compare against mntpnt if fs, */ /* or fstype if swap */ char *char_device = chrname; /* check names */ assert(vname != NULL); assert(tname != NULL); /* get temp names */ *tname = NULL; *tname = Malloc(strlen(vname) + strlen(".tmp") + 1); (void) strcpy(*tname, vname); (void) strcat(*tname, ".tmp"); /* check if going to update swap entry in file */ /* if so then compare against file system type */ if ((old_bdevname != NULL) && (strcmp("swap", cmpname) == 0)) { cmpstr = &fstype[0]; char_device = &cdev[0]; } /* copy vfstab file, replace filesystem line */ if ((fp = fopen(vname, "r")) == NULL) { (void) mdsyserror(ep, errno, vname); goto out; } if (fstat(fileno(fp), &sbuf) != 0) { (void) mdsyserror(ep, errno, vname); goto out; } if (doit) { if ((tfp = fopen(*tname, "w")) == NULL) { (void) mdsyserror(ep, errno, *tname); goto out; } if (fchmod(fileno(tfp), (sbuf.st_mode & 0777)) != 0) { (void) mdsyserror(ep, errno, *tname); goto out; } if (fchown(fileno(tfp), sbuf.st_uid, sbuf.st_gid) != 0) { (void) mdsyserror(ep, errno, *tname); goto out; } } while (fgets(buf, sizeof (buf), fp) != NULL) { /* check that have all required params from vfstab file */ /* or that the line isnt a comment */ /* or that the fstype/mntpoint match what was passed in */ /* or that the block device matches if changing swap */ /* the last check is needed since there may be multiple */ /* entries of swap in the file, and so the fstype is not */ /* a sufficient check */ if ((sscanf(buf, "%512s %512s %512s %512s %512s %512s %512s", bdev, cdev, mntpt, fstype, fsckpass, mntboot, mntopt) != 7) || (bdev[0] == '#') || (strcmp(cmpstr, cmpname) != 0) || ((old_bdevname != NULL) && (strstr(bdev, old_bdevname) == NULL))) { if (doit) { if (fputs(buf, tfp) == EOF) { (void) mdsyserror(ep, errno, *tname); goto out; } } continue; } if (verbose) { (void) printf(dgettext(TEXT_DOMAIN, "Delete the following line from %s:\n\n"), vname); (void) printf("%s\n", buf); (void) printf( dgettext(TEXT_DOMAIN, "Add the following line to %s:\n\n"), vname); (void) printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\n\n", blkname, char_device, mntpt, fstype, fsckpass, mntboot, mntopt); } if (doit) { if (fprintf(tfp, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", blkname, char_device, mntpt, fstype, fsckpass, mntboot, mntopt) == EOF) { (void) mdsyserror(ep, errno, *tname); goto out; } } gotfs = 1; } if (! feof(fp)) { (void) mdsyserror(ep, errno, vname); goto out; } if (! gotfs) { (void) mderror(ep, MDE_VFSTAB_FILE, vname); goto out; } if (fclose(fp) != 0) { (void) mdsyserror(ep, errno, vname); goto out; } fp = NULL; if (doit) { if ((fflush(tfp) != 0) || (fsync(fileno(tfp)) != 0) || (fclose(tfp) != 0)) { (void) mdsyserror(ep, errno, *tname); goto out; } tfp = NULL; } /* return success */ return (0); /* cleanup, return error */ out: if (fp != NULL) (void) fclose(fp); if (tfp != NULL) (void) fclose(tfp); if (*tname != NULL) { (void) unlink(*tname); Free(*tname); } return (-1); }
/* * check for overlap */ int meta_check_overlap( char *uname, /* user supplied name for errors */ mdname_t *np1, /* first comp */ diskaddr_t slblk1, /* first comp - start logical block */ diskaddr_t nblks1, /* first comp - # of blocks */ mdname_t *np2, /* second comp */ diskaddr_t slblk2, /* second comp - start logical block */ diskaddr_t nblks2, /* second comp - # of blocks */ md_error_t *ep ) { diskaddr_t sblk1, sblk2; mdvtoc_t *vtocp1, *vtocp2; uint_t partno1, partno2; mdpart_t *partp1, *partp2; int ret; /* verify args */ if (slblk1 == MD_DISKADDR_ERROR) { assert(0); return (mdsyserror(ep, EINVAL, np1->cname)); } if (slblk2 == MD_DISKADDR_ERROR) { assert(0); return (mdsyserror(ep, EINVAL, np2->cname)); } /* check for same drive */ if ((ret = meta_check_samedrive(np1, np2, ep)) == 0) { return (0); /* not same drive */ } else if (ret < 0) { return (-1); /* can't tell */ } /* check for overlap */ if (((vtocp1 = metagetvtoc(np1, FALSE, &partno1, ep)) == NULL) || ((vtocp2 = metagetvtoc(np2, FALSE, &partno2, ep)) == NULL)) { return (-1); /* can't tell */ } partp1 = &vtocp1->parts[partno1]; partp2 = &vtocp2->parts[partno2]; sblk1 = partp1->start + slblk1; if (nblks1 == -1) nblks1 = partp1->size - slblk1; sblk2 = partp2->start + slblk2; if (nblks2 == -1) nblks2 = partp2->size - slblk2; if (((sblk1 >= sblk2) && (sblk1 < (sblk2 + nblks2))) || ((sblk2 >= sblk1) && (sblk2 < (sblk1 + nblks1)))) { if (np1->dev == np2->dev) { /* slice in use */ return (mduseerror(ep, MDE_ALREADY, np1->dev, uname, np1->cname)); } if (ret == IDENTICAL_NAME_DEVT) return (mduseerror(ep, /* slice overlaps */ MDE_OVERLAP, np1->dev, uname, np1->cname)); else return (mduseerror(ep, /* same devid */ MDE_SAME_DEVID, np1->dev, uname, np2->cname)); } /* return success */ return (0); /* no overlap */ }
/* * check whether device is mounted */ static int meta_check_mounted( mdsetname_t *sp, mdname_t *np, md_error_t *ep ) { FILE *mfp; struct mnttab m; int rval = 0; char mountp[MNT_LINE_MAX]; char mnt_special[MNT_LINE_MAX]; /* should have a set */ assert(sp != NULL); /* look in mnttab */ if ((mfp = open_mnttab()) == NULL) return (mdsyserror(ep, errno, MNTTAB)); while ((getmntent(mfp, &m) == 0) && (rval == 0)) { char **fstype = skip_these_mntents; int skipit = 0; mdname_t *mnp; if ((m.mnt_special == NULL) || (m.mnt_mountp == NULL)) continue; if (m.mnt_mountp[0] != '/') continue; while (*fstype != NULL) if (strcmp(m.mnt_fstype, *fstype++) == 0) { skipit++; break; } if (skipit == 1) continue; (void) strcpy(mountp, m.mnt_mountp); (void) strcpy(mnt_special, m.mnt_special); if ((mnp = metaname(&sp, mnt_special, UNKNOWN, ep)) == NULL) { mdclrerror(ep); continue; } if (np->dev == mnp->dev) { rval = mduseerror(ep, MDE_IS_MOUNTED, np->dev, mountp, np->cname); } else { /* device isn't in mnttab - does it overlap? */ rval = meta_check_overlap(mnp->cname, np, 0, -1, mnp, 0, -1, ep); if (rval != 0) { (void) mdoverlaperror(ep, MDE_OVERLAP_MOUNTED, np->cname, mountp, mnp->cname); } } } /* return success */ return (rval); }
/* * FUNCTION: meta_replicaslice() * INPUT: dnp - the name of the drive to check * OUTPUT: slicep - pointer to slice number * ep - pointer to an md_error_t structure in which * to return errors to the caller * RETURNS: int - 0 - value pointed to by slicep is valid * -1 - otherwise * * PURPOSE: Determine which slice of the specified drive to * reserve, presumably for metadb replica usage. * * NOTE: If slicep is NULL, the return code will indicate * whether or not the slice number could be determined */ int meta_replicaslice( mddrivename_t *dnp, uint_t *slicep, md_error_t *ep ) { int err = 0; int ioctl_return; int fd; char *rname; struct dk_geom geom; rname = dnp->rname; if ((fd = open(rname, (O_RDONLY|O_NDELAY), 0)) < 0) { char *n; int open_errno; size_t len; if (errno != ENOENT) return (mdsyserror(ep, errno, rname)); len = strlen(rname) + 3; n = Zalloc(len); (void) snprintf(n, len, "%ss0", rname); fd = open(n, (O_RDONLY|O_NDELAY), 0); open_errno = errno; Free(n); if (fd < 0) { return (mdsyserror(ep, open_errno, rname)); } } /* * if our drivenamep points to a device not supporting * DKIOCGGEOM, we have an EFI label. */ errno = 0; ioctl_return = ioctl(fd, DKIOCGGEOM, &geom); err = errno; (void) close(fd); /* * If the DKIOCGGEOM ioctl succeeded, then the device has a * VTOC style label. In this case, we use slice 7. */ if (ioctl_return == 0) { if (slicep != NULL) { *slicep = MD_SLICE7; } return (0); } /* * ENOTSUP indicates an EFI style label, in which case slice 7 * cannot be used because its minor number is reserved. In * this case, use slice 6. */ if (err == ENOTSUP) { if (slicep != NULL) { *slicep = MD_SLICE6; } return (0); } /* * Those are the only two cases we know how to deal with; * either the drivenamep didn't point to a disk, or the ioctl * failed for some other reason. */ if (err == ENOTTY) { return (mddeverror(ep, MDE_NOT_DISK, NODEV, rname)); } return (mdsyserror(ep, err, rname)); }
/* * save metadevice configuration in md.cf */ int meta_update_md_cf( mdsetname_t *sp, md_error_t *ep ) { char *name = METACONF; char *tname = METACONFTMP; FILE *tfp = NULL; FILE *mfp = NULL; mdprtopts_t options = PRINT_SHORT | PRINT_FAST; struct stat sbuf; char line[1000]; /* If this is not the local set, no need to do anything */ if (!metaislocalset(sp)) return (0); /* open temp file */ if ((tfp = fopen(tname, "w")) == NULL) return (mdsyserror(ep, errno, tname)); if (stat(name, &sbuf) == 0) { (void) fchmod(fileno(tfp), (sbuf.st_mode & 0777)); (void) fchown(fileno(tfp), sbuf.st_uid, sbuf.st_gid); } /* dump header */ if (fputs(dgettext(TEXT_DOMAIN, "# metadevice configuration file\n" "# do not hand edit\n"), tfp) == EOF) { (void) mdsyserror(ep, errno, tname); goto errout; } /* dump device configuration */ if (meta_print_all(sp, tname, NULL, tfp, options, NULL, ep) != 0) goto errout; /* close and rename file */ if (fclose(tfp) != 0) { (void) mdsyserror(ep, errno, tname); goto errout; } tfp = NULL; /* * Renames don't work in the miniroot since tmpfiles are * created in /var/tmp. Hence we copy the data out. */ if (rename(tname, name) != 0) { if (errno == EROFS) { if ((tfp = fopen(tname, "r")) == NULL) { goto errout; } if ((mfp = fopen(METACONF, "w+")) == NULL) { goto errout; } while (fgets(line, 1000, tfp) != NULL) { if (fputs(line, mfp) == NULL) { (void) mdsyserror(ep, errno, METACONF); goto errout; } } if (fclose(tfp) != 0) { tfp = NULL; goto errout; } tfp = NULL; /* delete the tempfile */ (void) unlink(tname); if (fflush(mfp) != 0) { goto errout; } if (fsync(fileno(mfp)) != 0) { goto errout; } if (fclose(mfp) != 0) { mfp = NULL; goto errout; } mfp = NULL; } else { (void) mdsyserror(ep, errno, name); goto errout; } } /* success */ return (0); /* cleanup, return error */ errout: if (tfp != NULL) { (void) fclose(tfp); (void) unlink(tname); } if (mfp != NULL) { (void) fclose(mfp); } return (-1); }
/* * setup RPC service * * if can't authenticate return < 0 * any other error return > 0 */ int svc_init( struct svc_req *rqstp, /* RPC stuff */ int amode, /* R_OK | W_OK */ md_error_t *ep /* returned status */ ) { SVCXPRT *transp; if (sdssc_bind_library() == SDSSC_ERROR) { mdsyserror(ep, EACCES, "can't bind to cluster library"); return (1); } /* * if we have no rpc service info, we must have been * called recursively from within the daemon */ if (rqstp == NULL) { mdclrerror(ep); return (0); /* OK */ } /* * initialize */ transp = rqstp->rq_xprt; assert(transp != NULL); *ep = mdnullerror; /* * check credentials */ switch (rqstp->rq_cred.oa_flavor) { /* UNIX flavor */ case AUTH_SYS: { if (check_sys(rqstp, amode, ep) != 0) return (1); /* error */ break; } /* can't authenticate anything else */ default: svcerr_weakauth(transp); return (-1); /* weak authentication */ } /* * (re)initialize */ if (md_init_daemon("rpc.metad", ep) != 0) return (1); /* error */ if (set_snarf(ep)) return (1); sr_validate(); /* success */ return (0); }
/* * This routine is called from preenlib the first time. It is then * recursively called through preen_subdev. * * The argument passed in (uname) starts with the special device from * /etc/vfstab. Recursive calls pass in the underlying physical device * names. */ void preen_build_devs( char *uname, /* name of metadevice */ struct dk_cinfo *dkiop, /* associated controller info */ void *dp /* magic info */ ) { char *setname = NULL; char *tname = NULL; mdsetname_t *sp; mdname_t *namep; /* metadevice name */ mdnamelist_t *nlp = NULL; /* list of real devices */ mdnamelist_t *p; devid_nmlist_t *nm_list = NULL; md_error_t status = mdnullerror; md_error_t *ep = &status; int ep_valid = 0; /* does ep contain a real error */ struct stat statb; static int md_major = -1; side_t sideno; /* * The rest of the code in this library can't work within a * non-global zone so we just return the top level metadevice back * to be fscked. */ if (getzoneid() != GLOBAL_ZONEID) { preen_addunit(dp, dkiop->dki_dname, NULL, NULL, dkiop->dki_unit); return; } if (stat(uname, &statb) != 0) return; if (md_major == -1 && get_major_from_n2m(MD_MODULE, &md_major) != 0) return; /* * If the path passed in is not a metadevice, then add that * device to the list (preen_addunit) since it has to be a * physical device. */ if (major(statb.st_rdev) != md_major) { preen_addunit(dp, dkiop->dki_dname, NULL, NULL, dkiop->dki_unit); return; } /* * Bind to the cluster library */ if (sdssc_bind_library() == SDSSC_ERROR) return; if (md_init_daemon("fsck", ep) != 0) { ep_valid = 1; goto out; } /* * parse the path name to get the diskset name. */ parse_device(NULL, uname, &tname, &setname); Free(tname); if ((sp = metasetname(setname, ep)) == NULL) { ep_valid = 1; goto out; } /* check for ownership */ if (meta_check_ownership(sp, ep) != 0) { /* * Don't own the set but we are here implies * that this is a clustered proxy device. Simply add * the unit. */ preen_addunit(dp, dkiop->dki_dname, NULL, NULL, dkiop->dki_unit); ep_valid = 1; goto out; } /* * get list of underlying physical devices. */ if ((namep = metaname(&sp, uname, UNKNOWN, ep)) == NULL) { ep_valid = 1; goto out; } if (namep->dev == NODEV64) { goto out; } if (meta_getdevs(sp, namep, &nlp, ep) != 0) { ep_valid = 1; goto out; } if ((sideno = getmyside(sp, ep)) == MD_SIDEWILD) { ep_valid = 1; goto out; } /* gather and add the underlying devs */ for (p = nlp; (p != NULL); p = p->next) { mdname_t *devnp = p->namep; int fd; struct dk_cinfo cinfo; ddi_devid_t md_did; char *devname; char *minor_name = NULL; char mname[MAXPATHLEN]; /* * we don't want to use the rname anymore because * that may have changed. Use the device id information * to find the correct ctd name and open based on that. * If there isn't a devid or we have a did device, then * use the rname. In clustering, it's corrected for us. * If no devid it's at least worth a try. */ if (((md_did = meta_getdidbykey(sp->setno, sideno, devnp->key, ep)) == NULL) || ((minor_name = meta_getdidminorbykey(sp->setno, sideno, devnp->key, ep)) == NULL)) { devname = devnp->rname; if (md_did) Free(md_did); } else { if (strstr(minor_name, ",raw") == NULL) { (void) snprintf(mname, MAXPATHLEN, "%s,raw", minor_name); } else { (void) snprintf(mname, MAXPATHLEN, "%s", minor_name); } /* * We need to make sure we call this with a specific * mname (raw mname) so that we get the exact slice * with the given device id. Otherwise we could try * to open a slice that doesn't really exist. */ if (meta_deviceid_to_nmlist("/dev", md_did, mname, &nm_list) != 0) { (void) mdsyserror(ep, errno, devnp->rname); ep_valid = 1; Free(md_did); Free(minor_name); goto out; } devname = Strdup(nm_list->devname); Free(md_did); Free(minor_name); devid_free_nmlist(nm_list); } /* get device name and (real) cinfo */ if ((fd = open(devname, O_RDONLY, 0)) < 0) { (void) mdsyserror(ep, errno, devname); ep_valid = 1; /* * We need to scan all sub devices even if some fail * since exit here would end up in not finishing fsck * on all devices and prevent us from going into * multiuser mode. */ continue; } if (ioctl(fd, DKIOCINFO, &cinfo) != 0) { (void) mdsyserror(ep, errno, devname); (void) close(fd); ep_valid = 1; /* Continue here too. See comment from before */ continue; } (void) close(fd); /* sd/ssd bug */ /* * preen_subdev fails when the device name has been * resolved to the physical layer. Hence it is added * to preen_addunit. */ if (preen_subdev(devname, &cinfo, dp) != 0) { preen_addunit(dp, cinfo.dki_dname, NULL, NULL, cinfo.dki_unit); } } /* cleanup, if we fail, just add this composite device to the list */ out: if (setname != NULL) Free(setname); if (ep_valid != 0) { mde_perror(&status, ""); mdclrerror(&status); } metafreenamelist(nlp); }