Esempio n. 1
0
/*
 * Add wedges for a valid NetBSD disklabel.
 */
static void
addwedges(const mbr_args_t *a, const struct disklabel *lp)
{
	int error, i;

	for (i = 0; i < lp->d_npartitions; i++) {
		struct dkwedge_info dkw;
		const struct partition *p;
		const char *ptype;

		p = &lp->d_partitions[i];

		if (p->p_fstype == FS_UNUSED)
			continue;
		if ((ptype = bsdlabel_fstype_to_str(p->p_fstype)) == NULL) {
			/*
			 * XXX Should probably just add these...
			 * XXX maybe just have an empty ptype?
			 */
			aprint_verbose("%s: skipping partition %d, type %d\n",
			    a->pdk->dk_name, i, p->p_fstype);
			continue;
		}
		strcpy(dkw.dkw_ptype, ptype);

		strcpy(dkw.dkw_parent, a->pdk->dk_name);
		dkw.dkw_offset = p->p_offset;
		dkw.dkw_size = p->p_size;

		/*
		 * These get historical disk naming style
		 * wedge names.
		 */
		snprintf((char *)&dkw.dkw_wname, sizeof(dkw.dkw_wname),
		    "%s%c", a->pdk->dk_name, 'a' + i);

		error = dkwedge_add(&dkw);
		if (error == EEXIST)
			aprint_error("%s: wedge named '%s' already "
			    "exists, manual intervention required\n",
			    a->pdk->dk_name, dkw.dkw_wname);
		else if (error)
			aprint_error("%s: error %d adding partition "
			    "%d type %d\n", a->pdk->dk_name, error,
			    i, p->p_fstype);
	}
}
Esempio n. 2
0
/*
 * disk_ioctl --
 *	Generic disk ioctl handling.
 */
int
disk_ioctl(struct disk *dk, dev_t dev, u_long cmd, void *data, int flag,
    struct lwp *l)
{
	struct dkwedge_info *dkw;
	struct partinfo *pi;
	struct partition *dp;
#ifdef __HAVE_OLD_DISKLABEL
	struct disklabel newlabel;
#endif

	switch (cmd) {
	case DIOCGDISKINFO:
		if (dk->dk_info == NULL)
			return ENOTSUP;
		return prop_dictionary_copyout_ioctl(data, cmd, dk->dk_info);

	case DIOCGSECTORSIZE:
		*(u_int *)data = dk->dk_geom.dg_secsize;
		return 0;

	case DIOCGMEDIASIZE:
		*(off_t *)data = (off_t)dk->dk_geom.dg_secsize *
		    dk->dk_geom.dg_secperunit;
		return 0;
	default:
		break;
	}

	if (dev == NODEV)
		return EPASSTHROUGH;

	/* The following should be moved to dk_ioctl */
	switch (cmd) {
	case DIOCGDINFO:
		if (dk->dk_label == NULL)
			return EBUSY;
		memcpy(data, dk->dk_label, sizeof (*dk->dk_label));
		return 0;

#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDINFO:
		if (dk->dk_label == NULL)
			return EBUSY;
		memcpy(&newlabel, dk->dk_label, sizeof(newlabel));
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(data, &newlabel, sizeof(struct olddisklabel));
		return 0;
#endif

	case DIOCGPARTINFO:
		pi = data;
		memset(pi, 0, sizeof(*pi));
		pi->pi_secsize = dk->dk_geom.dg_secsize;
		pi->pi_bsize = BLKDEV_IOSIZE;

		if (DISKPART(dev) == RAW_PART) {
			pi->pi_size = dk->dk_geom.dg_secperunit;
			return 0;
		}

		if (dk->dk_label == NULL)
			return EBUSY;

		dp = &dk->dk_label->d_partitions[DISKPART(dev)];
		pi->pi_offset = dp->p_offset;
		pi->pi_size = dp->p_size;

		pi->pi_fstype = dp->p_fstype;
		pi->pi_frag = dp->p_frag;
		pi->pi_fsize = dp->p_fsize;
		pi->pi_cpg = dp->p_cpg;
		
		/*
		 * dholland 20130616: XXX this logic should not be
		 * here. It is here because the old buffer cache
		 * demands that all accesses to the same blocks need
		 * to be the same size; but it only works for FFS and
		 * nowadays I think it'll fail silently if the size
		 * info in the disklabel is wrong. (Or missing.) The
		 * buffer cache needs to be smarter; or failing that
		 * we need a reliable way here to get the right block
		 * size; or a reliable way to guarantee that (a) the
		 * fs is not mounted when we get here and (b) any
		 * buffers generated here will get purged when the fs
		 * does get mounted.
		 */
		if (dp->p_fstype == FS_BSDFFS &&
		    dp->p_frag != 0 && dp->p_fsize != 0)
			pi->pi_bsize = dp->p_frag * dp->p_fsize;
		return 0;

	case DIOCAWEDGE:
		if ((flag & FWRITE) == 0)
			return EBADF;

		dkw = data;
		strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent));
		return dkwedge_add(dkw);

	case DIOCDWEDGE:
		if ((flag & FWRITE) == 0)
			return EBADF;

		dkw = data;
		strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent));
		return dkwedge_del(dkw);

	case DIOCLWEDGES:
		return dkwedge_list(dk, data, l);

	case DIOCMWEDGES:
		if ((flag & FWRITE) == 0)
			return EBADF;

		dkwedge_discover(dk);
		return 0;

	default:
		return EPASSTHROUGH;
	}
}
Esempio n. 3
0
static int
dkwedge_discover_apple(struct disk *pdk, struct vnode *vp)
{
	size_t i;
	int error;
	void *buf;
	uint32_t blocksize, offset, rsize;
	struct apple_drvr_map *am;
	struct apple_part_map_entry *ae;
	struct apple_blockzeroblock ab;
	const char *ptype;

	buf = DKW_MALLOC(ASIZE);
	if ((error = dkwedge_read(pdk, vp, 0, buf, ASIZE)) != 0) {
		DPRINTF("%s: read @%u %d\n", __func__, 0, error);
		goto out;
	}

	am = buf;
	swap_apple_drvr_map(am);

	error = ESRCH;

	if (am->sbSig != APPLE_DRVR_MAP_MAGIC) {
		DPRINTF("%s: drvr magic %x != %x\n", __func__, am->sbSig,
		    APPLE_DRVR_MAP_MAGIC);
		goto out;
	}

	blocksize = am->sbBlockSize;

	rsize = 1 << (ilog2(MAX(sizeof(*ae), blocksize) - 1) + 1);
	if (ASIZE < rsize) {
		DPRINTF("%s: buffer too small %u < %u\n", __func__, ASIZE,
		    rsize);
		goto out;
	}

	ae = buf;
	for (offset = blocksize;; offset += rsize) {
		DPRINTF("%s: offset %x rsize %x\n", __func__, offset, rsize);
		if ((error = dkwedge_read(pdk, vp, offset / DEV_BSIZE, buf,
		    rsize)) != 0) {
			DPRINTF("%s: read @%u %d\n", __func__, offset,
			    error);
			goto out;
		}
		
		swap_apple_part_map_entry(ae);
		if (ae->pmSig != APPLE_PART_MAP_ENTRY_MAGIC) {
			DPRINTF("%s: part magic %x != %x\n", __func__,
			    ae->pmSig, APPLE_PART_MAP_ENTRY_MAGIC);
			break;
		}

		for (i = 0; i < __arraycount(map); i++)
			if (strcasecmp(map[i].name, ae->pmPartType) == 0)
				break;

		DPRINTF("%s: %s/%s PH=%u/%u LG=%u/%u\n", __func__,
		    ae->pmPartName, ae->pmPartType,
		    ae->pmPyPartStart, ae->pmPartBlkCnt,
		    ae->pmLgDataStart, ae->pmDataCnt);

		if (i == __arraycount(map))
			continue;

		ptype = map[i].type;
		memcpy(&ab, ae->pmBootArgs, sizeof(ab));
		swap_apple_blockzeroblock(&ab);
		if (ab.bzbMagic == APPLE_BZB_MAGIC) {
			if (ab.bzbType == APPLE_BZB_TYPESWAP)
				ptype = DKW_PTYPE_SWAP;
		}

		struct dkwedge_info dkw;

		strcpy(dkw.dkw_ptype, ptype);
		strcpy(dkw.dkw_parent, pdk->dk_name);
		dkw.dkw_offset = ae->pmPyPartStart;
		dkw.dkw_size = ae->pmPartBlkCnt;
		strlcpy(dkw.dkw_wname, ae->pmPartName, sizeof(dkw.dkw_wname));
		error = dkwedge_add(&dkw);
		if (error == EEXIST)
			aprint_error("%s: wedge named '%s' already "
			    "exists, manual intervention required\n",
			    pdk->dk_name, dkw.dkw_wname);
		else if (error)
			aprint_error("%s: error %d adding partition "
			    "%s type %s\n", pdk->dk_name, error,
			    ae->pmPartType, dkw.dkw_ptype);
	}

out:
	DKW_FREE(buf);
	DPRINTF("%s: return %d\n", __func__, error);
	return error;
}
int
dk_ioctl(struct dk_intf *di, struct dk_softc *dksc, dev_t dev,
	    u_long cmd, void *data, int flag, struct lwp *l)
{
	struct	disklabel *lp;
	struct	disk *dk;
#ifdef __HAVE_OLD_DISKLABEL
	struct	disklabel newlabel;
#endif
	int	error = 0;

	DPRINTF_FOLLOW(("dk_ioctl(%s, %p, 0x%"PRIx64", 0x%lx)\n",
	    di->di_dkname, dksc, dev, cmd));

	/* ensure that the pseudo disk is open for writes for these commands */
	switch (cmd) {
	case DIOCSDINFO:
	case DIOCWDINFO:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCSDINFO:
	case ODIOCWDINFO:
#endif
	case DIOCWLABEL:
	case DIOCAWEDGE:
	case DIOCDWEDGE:
		if ((flag & FWRITE) == 0)
			return EBADF;
	}

	/* ensure that the pseudo-disk is initialized for these */
	switch (cmd) {
#ifdef DIOCGSECTORSIZE
	case DIOCGSECTORSIZE:
	case DIOCGMEDIASIZE:
#endif
	case DIOCGDINFO:
	case DIOCSDINFO:
	case DIOCWDINFO:
	case DIOCGPART:
	case DIOCWLABEL:
	case DIOCGDEFLABEL:
	case DIOCAWEDGE:
	case DIOCDWEDGE:
	case DIOCLWEDGES:
	case DIOCCACHESYNC:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDINFO:
	case ODIOCSDINFO:
	case ODIOCWDINFO:
	case ODIOCGDEFLABEL:
#endif
		if ((dksc->sc_flags & DKF_INITED) == 0)
			return ENXIO;
	}

	switch (cmd) {
#ifdef DIOCGSECTORSIZE
	case DIOCGSECTORSIZE:
		*(u_int *)data = dksc->sc_dkdev.dk_geom.dg_secsize;
		return 0;
	case DIOCGMEDIASIZE:
		*(off_t *)data =
		    (off_t)dksc->sc_dkdev.dk_geom.dg_secsize *
		    dksc->sc_dkdev.dk_geom.dg_nsectors;
		return 0;
#endif

	case DIOCGDINFO:
		*(struct disklabel *)data = *(dksc->sc_dkdev.dk_label);
		break;

#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDINFO:
		newlabel = *(dksc->sc_dkdev.dk_label);
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(data, &newlabel, sizeof (struct olddisklabel));
		break;
#endif

	case DIOCGPART:
		((struct partinfo *)data)->disklab = dksc->sc_dkdev.dk_label;
		((struct partinfo *)data)->part =
		    &dksc->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
		break;

	case DIOCWDINFO:
	case DIOCSDINFO:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCWDINFO:
	case ODIOCSDINFO:
#endif
#ifdef __HAVE_OLD_DISKLABEL
		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
			memset(&newlabel, 0, sizeof newlabel);
			memcpy(&newlabel, data, sizeof (struct olddisklabel));
			lp = &newlabel;
		} else
#endif
		lp = (struct disklabel *)data;

		dk = &dksc->sc_dkdev;
		mutex_enter(&dk->dk_openlock);
		dksc->sc_flags |= DKF_LABELLING;

		error = setdisklabel(dksc->sc_dkdev.dk_label,
		    lp, 0, dksc->sc_dkdev.dk_cpulabel);
		if (error == 0) {
			if (cmd == DIOCWDINFO
#ifdef __HAVE_OLD_DISKLABEL
			    || cmd == ODIOCWDINFO
#endif
			   )
				error = writedisklabel(DKLABELDEV(dev),
				    di->di_strategy, dksc->sc_dkdev.dk_label,
				    dksc->sc_dkdev.dk_cpulabel);
		}

		dksc->sc_flags &= ~DKF_LABELLING;
		mutex_exit(&dk->dk_openlock);
		break;

	case DIOCWLABEL:
		if (*(int *)data != 0)
			dksc->sc_flags |= DKF_WLABEL;
		else
			dksc->sc_flags &= ~DKF_WLABEL;
		break;

	case DIOCGDEFLABEL:
		dk_getdefaultlabel(di, dksc, (struct disklabel *)data);
		break;

#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDEFLABEL:
		dk_getdefaultlabel(di, dksc, &newlabel);
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(data, &newlabel, sizeof (struct olddisklabel));
		break;
#endif

	case DIOCAWEDGE:
	    {
	    	struct dkwedge_info *dkw = (void *)data;

		if ((flag & FWRITE) == 0)
			return (EBADF);

		/* If the ioctl happens here, the parent is us. */
		strcpy(dkw->dkw_parent, dksc->sc_dkdev.dk_name);
		return (dkwedge_add(dkw));
	    }

	case DIOCDWEDGE:
	    {
	    	struct dkwedge_info *dkw = (void *)data;

		if ((flag & FWRITE) == 0)
			return (EBADF);

		/* If the ioctl happens here, the parent is us. */
		strcpy(dkw->dkw_parent, dksc->sc_dkdev.dk_name);
		return (dkwedge_del(dkw));
	    }

	case DIOCLWEDGES:
	    {
	    	struct dkwedge_list *dkwl = (void *)data;

		return (dkwedge_list(&dksc->sc_dkdev, dkwl, l));
	    }

	case DIOCGSTRATEGY:
	    {
		struct disk_strategy *dks = (void *)data;
		int s;

		s = splbio();
		strlcpy(dks->dks_name, bufq_getstrategyname(dksc->sc_bufq),
		    sizeof(dks->dks_name));
		splx(s);
		dks->dks_paramlen = 0;

		return 0;
	    }
	
	case DIOCSSTRATEGY:
	    {
		struct disk_strategy *dks = (void *)data;
		struct bufq_state *new;
		struct bufq_state *old;
		int s;

		if ((flag & FWRITE) == 0) {
			return EBADF;
		}
		if (dks->dks_param != NULL) {
			return EINVAL;
		}
		dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */
		error = bufq_alloc(&new, dks->dks_name,
		    BUFQ_EXACT|BUFQ_SORT_RAWBLOCK);
		if (error) {
			return error;
		}
		s = splbio();
		old = dksc->sc_bufq;
		bufq_move(new, old);
		dksc->sc_bufq = new;
		splx(s);
		bufq_free(old);

		return 0;
	    }

	default:
		error = ENOTTY;
	}

	return error;
}
Esempio n. 5
0
static void
getparts(mbr_args_t *a, uint32_t off, uint32_t extoff)
{
	struct dkwedge_info dkw;
	struct mbr_partition *dp;
	struct mbr_sector *mbr;
	const char *ptype;
	int i, error;

	error = dkwedge_read(a->pdk, a->vp, off, a->buf, a->secsize);
	if (error) {
		aprint_error("%s: unable to read MBR @ %u/%u, "
		    "error = %d\n", a->pdk->dk_name, off, a->secsize, a->error);
		a->error = error;
		return;
	}

	mbr = a->buf;
	if (mbr->mbr_magic != htole16(MBR_MAGIC))
		return;

	dp = mbr->mbr_parts;

	for (i = 0; i < MBR_PART_COUNT; i++) {
		/* Extended partitions are handled below. */
		if (dp[i].mbrp_type == 0 ||
		    MBR_IS_EXTENDED(dp[i].mbrp_type))
		    	continue;

		if ((ptype = mbr_ptype_to_str(dp[i].mbrp_type)) == NULL) {
			/*
			 * XXX Should probably just add these...
			 * XXX maybe just have an empty ptype?
			 */
			aprint_verbose("%s: skipping partition %d, "
			    "type 0x%02x\n", a->pdk->dk_name, i,
			    dp[i].mbrp_type);
			continue;
		}
		strcpy(dkw.dkw_ptype, ptype);

		strcpy(dkw.dkw_parent, a->pdk->dk_name);
		dkw.dkw_offset = le32toh(dp[i].mbrp_start);
		dkw.dkw_size = le32toh(dp[i].mbrp_size);

		/*
		 * These get historical disk naming style
		 * wedge names.  We start at 'e', and reserve
		 * 4 slots for each MBR we parse.
		 *
		 * XXX For FAT, we should extract the FAT volume
		 * XXX name.
		 */
		snprintf(dkw.dkw_wname, sizeof(dkw.dkw_wname),
		    "%s%c", a->pdk->dk_name,
		    'e' + (a->mbr_count * MBR_PART_COUNT) + i);

		error = dkwedge_add(&dkw);
		if (error == EEXIST)
			aprint_error("%s: wedge named '%s' already "
			    "exists, manual intervention required\n",
			    a->pdk->dk_name, dkw.dkw_wname);
		else if (error)
			aprint_error("%s: error %d adding partition "
			    "%d type 0x%02x\n", a->pdk->dk_name, error,
			    (a->mbr_count * MBR_PART_COUNT) + i,
			    dp[i].mbrp_type);
	}

	/* We've parsed one MBR. */
	a->mbr_count++;

	/* Recursively scan extended partitions. */
	for (i = 0; i < MBR_PART_COUNT; i++) {
		uint32_t poff;

		if (MBR_IS_EXTENDED(dp[i].mbrp_type)) {
			poff = le32toh(dp[i].mbrp_start) + extoff;
			getparts(a, poff, extoff ? extoff : poff);
		}
	}
}
Esempio n. 6
0
static int
dkwedge_discover_gpt(struct disk *pdk, struct vnode *vp)
{
	static const struct uuid ent_type_unused = GPT_ENT_TYPE_UNUSED;
	static const char gpt_hdr_sig[] = GPT_HDR_SIG;
	struct dkwedge_info dkw;
	void *buf;
	uint32_t secsize;
	struct gpt_hdr *hdr;
	struct gpt_ent *ent;
	uint32_t entries, entsz;
	daddr_t lba_start, lba_end, lba_table;
	uint32_t gpe_crc;
	int error;
	u_int i;
	size_t r, n;
	uint8_t *c;

	secsize = DEV_BSIZE << pdk->dk_blkshift;
	buf = malloc(secsize, M_DEVBUF, M_WAITOK);

	/*
	 * Note: We don't bother with a Legacy or Protective MBR
	 * here.  If a GPT is found, then the search stops, and
	 * the GPT is authoritative.
	 */

	/* Read in the GPT Header. */
	error = dkwedge_read(pdk, vp, GPT_HDR_BLKNO << pdk->dk_blkshift, buf, secsize);
	if (error)
		goto out;
	hdr = buf;

	/* Validate it. */
	if (memcmp(gpt_hdr_sig, hdr->hdr_sig, sizeof(hdr->hdr_sig)) != 0) {
		/* XXX Should check at end-of-disk. */
		error = ESRCH;
		goto out;
	}
	if (hdr->hdr_revision != htole32(GPT_HDR_REVISION)) {
		/* XXX Should check at end-of-disk. */
		error = ESRCH;
		goto out;
	}
	if (le32toh(hdr->hdr_size) > secsize) {
		/* XXX Should check at end-of-disk. */
		error = ESRCH;
		goto out;
	}
	if (gpt_verify_header_crc(hdr) == 0) {
		/* XXX Should check at end-of-disk. */
		error = ESRCH;
		goto out;
	}

	/* XXX Now that we found it, should we validate the backup? */

	{
		struct uuid disk_guid;
		char guid_str[UUID_STR_LEN];
		uuid_dec_le(hdr->hdr_guid, &disk_guid);
		uuid_snprintf(guid_str, sizeof(guid_str), &disk_guid);
		aprint_verbose("%s: GPT GUID: %s\n", pdk->dk_name, guid_str);
	}

	entries = le32toh(hdr->hdr_entries);
	entsz = roundup(le32toh(hdr->hdr_entsz), 8);
	if (entsz > roundup(sizeof(struct gpt_ent), 8)) {
		aprint_error("%s: bogus GPT entry size: %u\n",
		    pdk->dk_name, le32toh(hdr->hdr_entsz));
		error = EINVAL;
		goto out;
	}
	gpe_crc = le32toh(hdr->hdr_crc_table);

	/* XXX Clamp entries at 128 for now. */
	if (entries > 128) {
		aprint_error("%s: WARNING: clamping number of GPT entries to "
		    "128 (was %u)\n", pdk->dk_name, entries);
		entries = 128;
	}

	lba_start = le64toh(hdr->hdr_lba_start);
	lba_end = le64toh(hdr->hdr_lba_end);
	lba_table = le64toh(hdr->hdr_lba_table);
	if (lba_start < 0 || lba_end < 0 || lba_table < 0) {
		aprint_error("%s: GPT block numbers out of range\n",
		    pdk->dk_name);
		error = EINVAL;
		goto out;
	}

	free(buf, M_DEVBUF);
	buf = malloc(roundup(entries * entsz, secsize), M_DEVBUF, M_WAITOK);
	error = dkwedge_read(pdk, vp, lba_table << pdk->dk_blkshift, buf,
			     roundup(entries * entsz, secsize));
	if (error) {
		/* XXX Should check alternate location. */
		aprint_error("%s: unable to read GPT partition array, "
		    "error = %d\n", pdk->dk_name, error);
		goto out;
	}

	if (crc32(0, buf, entries * entsz) != gpe_crc) {
		/* XXX Should check alternate location. */
		aprint_error("%s: bad GPT partition array CRC\n",
		    pdk->dk_name);
		error = EINVAL;
		goto out;
	}

	/*
	 * Walk the partitions, adding a wedge for each type we know about.
	 */
	for (i = 0; i < entries; i++) {
		struct uuid ptype_guid, ent_guid;
		const char *ptype;
		int j;
		char ptype_guid_str[UUID_STR_LEN], ent_guid_str[UUID_STR_LEN];

		ent = (struct gpt_ent *)((char *)buf + (i * entsz));

		uuid_dec_le(ent->ent_type, &ptype_guid);
		if (memcmp(&ptype_guid, &ent_type_unused,
			   sizeof(ptype_guid)) == 0)
			continue;

		uuid_dec_le(ent->ent_guid, &ent_guid);

		uuid_snprintf(ptype_guid_str, sizeof(ptype_guid_str),
		    &ptype_guid);
		uuid_snprintf(ent_guid_str, sizeof(ent_guid_str),
		    &ent_guid);

		/* figure out the type */
		ptype = gpt_ptype_guid_to_str(&ptype_guid);
		strcpy(dkw.dkw_ptype, ptype);

		strcpy(dkw.dkw_parent, pdk->dk_name);
		dkw.dkw_offset = le64toh(ent->ent_lba_start);
		dkw.dkw_size = le64toh(ent->ent_lba_end) - dkw.dkw_offset + 1;

		/* XXX Make sure it falls within the disk's data area. */

		if (ent->ent_name[0] == 0x0000)
			strcpy(dkw.dkw_wname, ent_guid_str);
		else {
			c = dkw.dkw_wname;
			r = sizeof(dkw.dkw_wname) - 1;
			for (j = 0; ent->ent_name[j] != 0x0000; j++) {
				n = wput_utf8(c, r, le16toh(ent->ent_name[j]));
				if (n == 0)
					break;
				c += n; r -= n;
			}
			*c = '\0';
		}

		/*
		 * Try with the partition name first.  If that fails,
		 * use the GUID string.  If that fails, punt.
		 */
		if ((error = dkwedge_add(&dkw)) == EEXIST &&
		    strcmp(dkw.dkw_wname, ent_guid_str) != 0) {
			strcpy(dkw.dkw_wname, ent_guid_str);
			error = dkwedge_add(&dkw);
			if (!error)
				aprint_error("%s: wedge named '%s' already "
				    "existed, using '%s'\n", pdk->dk_name,
				    dkw.dkw_wname, /* XXX Unicode */
				    ent_guid_str);
		}
		if (error == EEXIST)
			aprint_error("%s: wedge named '%s' already exists, "
			    "manual intervention required\n", pdk->dk_name,
			    dkw.dkw_wname);
		else if (error)
			aprint_error("%s: error %d adding entry %u (%s), "
			    "type %s\n", pdk->dk_name, error, i, ent_guid_str,
			    ptype_guid_str);
	}
	error = 0;

 out:
	free(buf, M_DEVBUF);
	return (error);
}
Esempio n. 7
0
int
ofdisk_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
{
	struct ofdisk_softc *of =
		device_lookup_private(&ofdisk_cd, DISKUNIT(dev));
	int error;
#ifdef __HAVE_OLD_DISKLABEL
	struct disklabel newlabel;
#endif

	switch (cmd) {
	case DIOCGDINFO:
		*(struct disklabel *)data = *of->sc_dk.dk_label;
		return 0;
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDINFO:
		newlabel = *of->sc_dk.dk_label;
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(data, &newlabel, sizeof (struct olddisklabel));
		return 0;
#endif

	case DIOCGPART:
		((struct partinfo *)data)->disklab = of->sc_dk.dk_label;
		((struct partinfo *)data)->part =
			&of->sc_dk.dk_label->d_partitions[DISKPART(dev)];
		return 0;

	case DIOCWDINFO:
	case DIOCSDINFO:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCWDINFO:
	case ODIOCSDINFO:
#endif
	{
		struct disklabel *lp;

#ifdef __HAVE_OLD_DISKLABEL
		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
			memset(&newlabel, 0, sizeof newlabel);
			memcpy(&newlabel, data, sizeof (struct olddisklabel));
			lp = &newlabel;
		} else
#endif
		lp = (struct disklabel *)data;

		if ((flag & FWRITE) == 0)
			return EBADF;

		mutex_enter(&of->sc_dk.dk_openlock);

		error = setdisklabel(of->sc_dk.dk_label,
		    lp, /*of->sc_dk.dk_openmask */0,
		    of->sc_dk.dk_cpulabel);
		if (error == 0 && cmd == DIOCWDINFO
#ifdef __HAVE_OLD_DISKLABEL
		    || xfer == ODIOCWDINFO
#endif
		    )
			error = writedisklabel(MAKEDISKDEV(major(dev),
			    DISKUNIT(dev), RAW_PART), ofdisk_strategy,
			    of->sc_dk.dk_label, of->sc_dk.dk_cpulabel);

		mutex_exit(&of->sc_dk.dk_openlock);

		return error;
	}

	case DIOCGDEFLABEL:
		ofdisk_getdefaultlabel(of, (struct disklabel *)data);
		return 0;
#ifdef __HAVE_OLD_DISKLABEL
	case DIOCGDEFLABEL:
		ofdisk_getdefaultlabel(of, &newlabel);
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(data, &newlabel, sizeof (struct olddisklabel));
		return 0;
#endif

	case DIOCAWEDGE:
	    {
	    	struct dkwedge_info *dkw = (void *) data;

		if (OFDISK_FLOPPY_P(of))
			return (ENOTTY);

		if ((flag & FWRITE) == 0)
			return (EBADF);

		/* If the ioctl happens here, the parent is us. */
		strlcpy(dkw->dkw_parent, device_xname(of->sc_dev),
			sizeof(dkw->dkw_parent));
		return (dkwedge_add(dkw));
	    }

	case DIOCDWEDGE:
	    {
	    	struct dkwedge_info *dkw = (void *) data;

		if (OFDISK_FLOPPY_P(of))
			return (ENOTTY);

		if ((flag & FWRITE) == 0)
			return (EBADF);

		/* If the ioctl happens here, the parent is us. */
		strlcpy(dkw->dkw_parent, device_xname(of->sc_dev),
			sizeof(dkw->dkw_parent));
		return (dkwedge_del(dkw));
	    }

	case DIOCLWEDGES:
	    {
	    	struct dkwedge_list *dkwl = (void *) data;

		if (OFDISK_FLOPPY_P(of))
			return (ENOTTY);

		return (dkwedge_list(&of->sc_dk, dkwl, l));
	    }

	default:
		return ENOTTY;
	}
}
Esempio n. 8
0
/*
 * I/O controls.
 */
int
raioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
{
	struct disklabel *lp, *tp;
	struct ra_softc *ra = mscp_device_lookup(dev);
	int error = 0;
#ifdef __HAVE_OLD_DISKLABEL
	struct disklabel newlabel;
#endif

	lp = ra->ra_disk.dk_label;

	switch (cmd) {

	case DIOCGDINFO:
		memcpy(data, lp, sizeof (struct disklabel));
		break;
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDINFO:
		memcpy(&newlabel, lp, sizeof newlabel);
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(data, &newlabel, sizeof (struct olddisklabel));
		break;
#endif

	case DIOCGPART:
		((struct partinfo *)data)->disklab = lp;
		((struct partinfo *)data)->part =
		    &lp->d_partitions[DISKPART(dev)];
		break;

	case DIOCWDINFO:
	case DIOCSDINFO:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCWDINFO:
	case ODIOCSDINFO:
		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
			memset(&newlabel, 0, sizeof newlabel);
			memcpy(&newlabel, data, sizeof (struct olddisklabel));
			tp = &newlabel;
		} else
#endif
		tp = (struct disklabel *)data;

		if ((flag & FWRITE) == 0)
			error = EBADF;
		else {
			mutex_enter(&ra->ra_disk.dk_openlock);
			error = setdisklabel(lp, tp, 0, 0);
			if ((error == 0) && (cmd == DIOCWDINFO
#ifdef __HAVE_OLD_DISKLABEL
			    || cmd == ODIOCWDINFO
#endif
			    )) {
				ra->ra_wlabel = 1;
				error = writedisklabel(dev, rastrategy, lp,0);
				ra->ra_wlabel = 0;
			}
			mutex_exit(&ra->ra_disk.dk_openlock);
		}
		break;

	case DIOCWLABEL:
		if ((flag & FWRITE) == 0)
			error = EBADF;
		else
			ra->ra_wlabel = 1;
		break;

	case DIOCGDEFLABEL:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDEFLABEL:
		if (cmd == ODIOCGDEFLABEL)
			tp = &newlabel;
		else
#endif
		tp = (struct disklabel *)data;
		memset(tp, 0, sizeof(struct disklabel));
		tp->d_secsize = lp->d_secsize;
		tp->d_nsectors = lp->d_nsectors;
		tp->d_ntracks = lp->d_ntracks;
		tp->d_ncylinders = lp->d_ncylinders;
		tp->d_secpercyl = lp->d_secpercyl;
		tp->d_secperunit = lp->d_secperunit;
		tp->d_type = DTYPE_MSCP;
		tp->d_rpm = 3600;
		rrmakelabel(tp, ra->ra_mediaid);
#ifdef __HAVE_OLD_DISKLABEL
		if (cmd == ODIOCGDEFLABEL) {
			if (tp->d_npartitions > OLDMAXPARTITIONS)
				return ENOTTY;
			memcpy(data, tp, sizeof (struct olddisklabel));
		}
#endif
		break;

	case DIOCAWEDGE:
	    {
	    	struct dkwedge_info *dkw = (void *) data;

		if ((flag & FWRITE) == 0)
			return (EBADF);

		/* If the ioctl happens here, the parent is us. */
		strlcpy(dkw->dkw_parent, device_xname(ra->ra_dev),
			sizeof(dkw->dkw_parent));
		return (dkwedge_add(dkw));
	    }

	case DIOCDWEDGE:
	    {
	    	struct dkwedge_info *dkw = (void *) data;

		if ((flag & FWRITE) == 0)
			return (EBADF);

		/* If the ioctl happens here, the parent is us. */
		strlcpy(dkw->dkw_parent, device_xname(ra->ra_dev),
			sizeof(dkw->dkw_parent));
		return (dkwedge_del(dkw));
	    }

	case DIOCLWEDGES:
	    {
	    	struct dkwedge_list *dkwl = (void *) data;

		return (dkwedge_list(&ra->ra_disk, dkwl, l));
	    }

	default:
		error = ENOTTY;
		break;
	}
	return (error);
}
Esempio n. 9
0
/* ARGSUSED */
static int
vndioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
{
	bool force;
	int unit = vndunit(dev);
	struct vnd_softc *vnd;
	struct vnd_ioctl *vio;
	struct vattr vattr;
	struct pathbuf *pb;
	struct nameidata nd;
	int error, part, pmask;
	uint64_t geomsize;
	int fflags;
#ifdef __HAVE_OLD_DISKLABEL
	struct disklabel newlabel;
#endif
	struct dkwedge_info *dkw;
	struct dkwedge_list *dkwl;

#ifdef DEBUG
	if (vnddebug & VDB_FOLLOW)
		printf("vndioctl(0x%"PRIx64", 0x%lx, %p, 0x%x, %p): unit %d\n",
		    dev, cmd, data, flag, l->l_proc, unit);
#endif
	vnd = device_lookup_private(&vnd_cd, unit);
	if (vnd == NULL &&
#ifdef COMPAT_30
	    cmd != VNDIOCGET30 &&
#endif
#ifdef COMPAT_50
	    cmd != VNDIOCGET50 &&
#endif
	    cmd != VNDIOCGET)
		return ENXIO;
	vio = (struct vnd_ioctl *)data;

	/* Must be open for writes for these commands... */
	switch (cmd) {
	case VNDIOCSET:
	case VNDIOCCLR:
#ifdef COMPAT_50
	case VNDIOCSET50:
	case VNDIOCCLR50:
#endif
	case DIOCSDINFO:
	case DIOCWDINFO:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCSDINFO:
	case ODIOCWDINFO:
#endif
	case DIOCKLABEL:
	case DIOCWLABEL:
		if ((flag & FWRITE) == 0)
			return EBADF;
	}

	/* Must be initialized for these... */
	switch (cmd) {
	case VNDIOCCLR:
#ifdef VNDIOCCLR50
	case VNDIOCCLR50:
#endif
	case DIOCGDINFO:
	case DIOCSDINFO:
	case DIOCWDINFO:
	case DIOCGPART:
	case DIOCKLABEL:
	case DIOCWLABEL:
	case DIOCGDEFLABEL:
	case DIOCCACHESYNC:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDINFO:
	case ODIOCSDINFO:
	case ODIOCWDINFO:
	case ODIOCGDEFLABEL:
#endif
		if ((vnd->sc_flags & VNF_INITED) == 0)
			return ENXIO;
	}

	switch (cmd) {
#ifdef VNDIOCSET50
	case VNDIOCSET50:
#endif
	case VNDIOCSET:
		if (vnd->sc_flags & VNF_INITED)
			return EBUSY;

		if ((error = vndlock(vnd)) != 0)
			return error;

		fflags = FREAD;
		if ((vio->vnd_flags & VNDIOF_READONLY) == 0)
			fflags |= FWRITE;
		error = pathbuf_copyin(vio->vnd_file, &pb);
		if (error) {
			goto unlock_and_exit;
		}
		NDINIT(&nd, LOOKUP, FOLLOW, pb);
		if ((error = vn_open(&nd, fflags, 0)) != 0) {
			pathbuf_destroy(pb);
			goto unlock_and_exit;
		}
		KASSERT(l);
		error = VOP_GETATTR(nd.ni_vp, &vattr, l->l_cred);
		if (!error && nd.ni_vp->v_type != VREG)
			error = EOPNOTSUPP;
		if (!error && vattr.va_bytes < vattr.va_size)
			/* File is definitely sparse, use vn_rdwr() */
			vnd->sc_flags |= VNF_USE_VN_RDWR;
		if (error) {
			VOP_UNLOCK(nd.ni_vp);
			goto close_and_exit;
		}

		/* If using a compressed file, initialize its info */
		/* (or abort with an error if kernel has no compression) */
		if (vio->vnd_flags & VNF_COMP) {
#ifdef VND_COMPRESSION
			struct vnd_comp_header *ch;
			int i;
			u_int32_t comp_size;
			u_int32_t comp_maxsize;
 
			/* allocate space for compresed file header */
			ch = malloc(sizeof(struct vnd_comp_header),
			M_TEMP, M_WAITOK);
 
			/* read compressed file header */
			error = vn_rdwr(UIO_READ, nd.ni_vp, (void *)ch,
			  sizeof(struct vnd_comp_header), 0, UIO_SYSSPACE,
			  IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL);
			if (error) {
				free(ch, M_TEMP);
				VOP_UNLOCK(nd.ni_vp);
				goto close_and_exit;
			}
 
			/* save some header info */
			vnd->sc_comp_blksz = ntohl(ch->block_size);
			/* note last offset is the file byte size */
			vnd->sc_comp_numoffs = ntohl(ch->num_blocks)+1;
			free(ch, M_TEMP);
			if (vnd->sc_comp_blksz == 0 ||
			    vnd->sc_comp_blksz % DEV_BSIZE !=0) {
				VOP_UNLOCK(nd.ni_vp);
				error = EINVAL;
				goto close_and_exit;
			}
			if (sizeof(struct vnd_comp_header) +
			  sizeof(u_int64_t) * vnd->sc_comp_numoffs >
			  vattr.va_size) {
				VOP_UNLOCK(nd.ni_vp);
				error = EINVAL;
				goto close_and_exit;
			}
 
			/* set decompressed file size */
			vattr.va_size =
			    ((u_quad_t)vnd->sc_comp_numoffs - 1) *
			     (u_quad_t)vnd->sc_comp_blksz;
 
			/* allocate space for all the compressed offsets */
			vnd->sc_comp_offsets =
			malloc(sizeof(u_int64_t) * vnd->sc_comp_numoffs,
			M_DEVBUF, M_WAITOK);
 
			/* read in the offsets */
			error = vn_rdwr(UIO_READ, nd.ni_vp,
			  (void *)vnd->sc_comp_offsets,
			  sizeof(u_int64_t) * vnd->sc_comp_numoffs,
			  sizeof(struct vnd_comp_header), UIO_SYSSPACE,
			  IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL);
			if (error) {
				VOP_UNLOCK(nd.ni_vp);
				goto close_and_exit;
			}
			/*
			 * find largest block size (used for allocation limit).
			 * Also convert offset to native byte order.
			 */
			comp_maxsize = 0;
			for (i = 0; i < vnd->sc_comp_numoffs - 1; i++) {
				vnd->sc_comp_offsets[i] =
				  be64toh(vnd->sc_comp_offsets[i]);
				comp_size = be64toh(vnd->sc_comp_offsets[i + 1])
				  - vnd->sc_comp_offsets[i];
				if (comp_size > comp_maxsize)
					comp_maxsize = comp_size;
			}
			vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1] =
			  be64toh(vnd->sc_comp_offsets[vnd->sc_comp_numoffs - 1]);
 
			/* create compressed data buffer */
			vnd->sc_comp_buff = malloc(comp_maxsize,
			  M_DEVBUF, M_WAITOK);
 
			/* create decompressed buffer */
			vnd->sc_comp_decombuf = malloc(vnd->sc_comp_blksz,
			  M_DEVBUF, M_WAITOK);
			vnd->sc_comp_buffblk = -1;
 
			/* Initialize decompress stream */
			memset(&vnd->sc_comp_stream, 0, sizeof(z_stream));
			vnd->sc_comp_stream.zalloc = vnd_alloc;
			vnd->sc_comp_stream.zfree = vnd_free;
			error = inflateInit2(&vnd->sc_comp_stream, MAX_WBITS);
			if (error) {
				if (vnd->sc_comp_stream.msg)
					printf("vnd%d: compressed file, %s\n",
					  unit, vnd->sc_comp_stream.msg);
				VOP_UNLOCK(nd.ni_vp);
				error = EINVAL;
				goto close_and_exit;
			}
 
			vnd->sc_flags |= VNF_COMP | VNF_READONLY;
#else /* !VND_COMPRESSION */
			VOP_UNLOCK(nd.ni_vp);
			error = EOPNOTSUPP;
			goto close_and_exit;
#endif /* VND_COMPRESSION */
		}
 
		VOP_UNLOCK(nd.ni_vp);
		vnd->sc_vp = nd.ni_vp;
		vnd->sc_size = btodb(vattr.va_size);	/* note truncation */

		/*
		 * Use pseudo-geometry specified.  If none was provided,
		 * use "standard" Adaptec fictitious geometry.
		 */
		if (vio->vnd_flags & VNDIOF_HASGEOM) {

			memcpy(&vnd->sc_geom, &vio->vnd_geom,
			    sizeof(vio->vnd_geom));

			/*
			 * Sanity-check the sector size.
			 * XXX Don't allow secsize < DEV_BSIZE.	 Should
			 * XXX we?
			 */
			if (vnd->sc_geom.vng_secsize < DEV_BSIZE ||
			    (vnd->sc_geom.vng_secsize % DEV_BSIZE) != 0 ||
			    vnd->sc_geom.vng_ncylinders == 0 ||
			    (vnd->sc_geom.vng_ntracks *
			     vnd->sc_geom.vng_nsectors) == 0) {
				error = EINVAL;
				goto close_and_exit;
			}

			/*
			 * Compute the size (in DEV_BSIZE blocks) specified
			 * by the geometry.
			 */
			geomsize = (vnd->sc_geom.vng_nsectors *
			    vnd->sc_geom.vng_ntracks *
			    vnd->sc_geom.vng_ncylinders) *
			    (vnd->sc_geom.vng_secsize / DEV_BSIZE);

			/*
			 * Sanity-check the size against the specified
			 * geometry.
			 */
			if (vnd->sc_size < geomsize) {
				error = EINVAL;
				goto close_and_exit;
			}
		} else if (vnd->sc_size >= (32 * 64)) {
			/*
			 * Size must be at least 2048 DEV_BSIZE blocks
			 * (1M) in order to use this geometry.
			 */
			vnd->sc_geom.vng_secsize = DEV_BSIZE;
			vnd->sc_geom.vng_nsectors = 32;
			vnd->sc_geom.vng_ntracks = 64;
			vnd->sc_geom.vng_ncylinders = vnd->sc_size / (64 * 32);
		} else {
			vnd->sc_geom.vng_secsize = DEV_BSIZE;
			vnd->sc_geom.vng_nsectors = 1;
			vnd->sc_geom.vng_ntracks = 1;
			vnd->sc_geom.vng_ncylinders = vnd->sc_size;
		}

		vnd_set_geometry(vnd);

		if (vio->vnd_flags & VNDIOF_READONLY) {
			vnd->sc_flags |= VNF_READONLY;
		}

		if ((error = vndsetcred(vnd, l->l_cred)) != 0)
			goto close_and_exit;

		vndthrottle(vnd, vnd->sc_vp);
		vio->vnd_osize = dbtob(vnd->sc_size);
#ifdef VNDIOCSET50
		if (cmd != VNDIOCSET50)
#endif
			vio->vnd_size = dbtob(vnd->sc_size);
		vnd->sc_flags |= VNF_INITED;

		/* create the kernel thread, wait for it to be up */
		error = kthread_create(PRI_NONE, 0, NULL, vndthread, vnd,
		    &vnd->sc_kthread, "%s", device_xname(vnd->sc_dev));
		if (error)
			goto close_and_exit;
		while ((vnd->sc_flags & VNF_KTHREAD) == 0) {
			tsleep(&vnd->sc_kthread, PRIBIO, "vndthr", 0);
		}
#ifdef DEBUG
		if (vnddebug & VDB_INIT)
			printf("vndioctl: SET vp %p size 0x%lx %d/%d/%d/%d\n",
			    vnd->sc_vp, (unsigned long) vnd->sc_size,
			    vnd->sc_geom.vng_secsize,
			    vnd->sc_geom.vng_nsectors,
			    vnd->sc_geom.vng_ntracks,
			    vnd->sc_geom.vng_ncylinders);
#endif

		/* Attach the disk. */
		disk_attach(&vnd->sc_dkdev);
		disk_blocksize(&vnd->sc_dkdev, vnd->sc_geom.vng_secsize);

		/* Initialize the xfer and buffer pools. */
		pool_init(&vnd->sc_vxpool, sizeof(struct vndxfer), 0,
		    0, 0, "vndxpl", NULL, IPL_BIO);

		vndunlock(vnd);

		pathbuf_destroy(pb);

		/* Discover wedges on this disk */
		dkwedge_discover(&vnd->sc_dkdev);

		break;

close_and_exit:
		(void) vn_close(nd.ni_vp, fflags, l->l_cred);
		pathbuf_destroy(pb);
unlock_and_exit:
#ifdef VND_COMPRESSION
		/* free any allocated memory (for compressed file) */
		if (vnd->sc_comp_offsets) {
			free(vnd->sc_comp_offsets, M_DEVBUF);
			vnd->sc_comp_offsets = NULL;
		}
		if (vnd->sc_comp_buff) {
			free(vnd->sc_comp_buff, M_DEVBUF);
			vnd->sc_comp_buff = NULL;
		}
		if (vnd->sc_comp_decombuf) {
			free(vnd->sc_comp_decombuf, M_DEVBUF);
			vnd->sc_comp_decombuf = NULL;
		}
#endif /* VND_COMPRESSION */
		vndunlock(vnd);
		return error;

#ifdef VNDIOCCLR50
	case VNDIOCCLR50:
#endif
	case VNDIOCCLR:
		part = DISKPART(dev);
		pmask = (1 << part);
		force = (vio->vnd_flags & VNDIOF_FORCE) != 0;

		if ((error = vnddoclear(vnd, pmask, minor(dev), force)) != 0)
			return error;

		break;

#ifdef COMPAT_30
	case VNDIOCGET30: {
		struct vnd_user30 *vnu;
		struct vattr va;
		vnu = (struct vnd_user30 *)data;
		KASSERT(l);
		switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) {
		case 0:
			vnu->vnu_dev = va.va_fsid;
			vnu->vnu_ino = va.va_fileid;
			break;
		case -1:
			/* unused is not an error */
			vnu->vnu_dev = 0;
			vnu->vnu_ino = 0;
			break;
		default:
			return error;
		}
		break;
	}
#endif

#ifdef COMPAT_50
	case VNDIOCGET50: {
		struct vnd_user50 *vnu;
		struct vattr va;
		vnu = (struct vnd_user50 *)data;
		KASSERT(l);
		switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) {
		case 0:
			vnu->vnu_dev = va.va_fsid;
			vnu->vnu_ino = va.va_fileid;
			break;
		case -1:
			/* unused is not an error */
			vnu->vnu_dev = 0;
			vnu->vnu_ino = 0;
			break;
		default:
			return error;
		}
		break;
	}
#endif

	case VNDIOCGET: {
		struct vnd_user *vnu;
		struct vattr va;
		vnu = (struct vnd_user *)data;
		KASSERT(l);
		switch (error = vnd_cget(l, unit, &vnu->vnu_unit, &va)) {
		case 0:
			vnu->vnu_dev = va.va_fsid;
			vnu->vnu_ino = va.va_fileid;
			break;
		case -1:
			/* unused is not an error */
			vnu->vnu_dev = 0;
			vnu->vnu_ino = 0;
			break;
		default:
			return error;
		}
		break;
	}

	case DIOCGDINFO:
		*(struct disklabel *)data = *(vnd->sc_dkdev.dk_label);
		break;

#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDINFO:
		newlabel = *(vnd->sc_dkdev.dk_label);
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(data, &newlabel, sizeof (struct olddisklabel));
		break;
#endif

	case DIOCGPART:
		((struct partinfo *)data)->disklab = vnd->sc_dkdev.dk_label;
		((struct partinfo *)data)->part =
		    &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
		break;

	case DIOCWDINFO:
	case DIOCSDINFO:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCWDINFO:
	case ODIOCSDINFO:
#endif
	{
		struct disklabel *lp;

		if ((error = vndlock(vnd)) != 0)
			return error;

		vnd->sc_flags |= VNF_LABELLING;

#ifdef __HAVE_OLD_DISKLABEL
		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
			memset(&newlabel, 0, sizeof newlabel);
			memcpy(&newlabel, data, sizeof (struct olddisklabel));
			lp = &newlabel;
		} else
#endif
		lp = (struct disklabel *)data;

		error = setdisklabel(vnd->sc_dkdev.dk_label,
		    lp, 0, vnd->sc_dkdev.dk_cpulabel);
		if (error == 0) {
			if (cmd == DIOCWDINFO
#ifdef __HAVE_OLD_DISKLABEL
			    || cmd == ODIOCWDINFO
#endif
			   )
				error = writedisklabel(VNDLABELDEV(dev),
				    vndstrategy, vnd->sc_dkdev.dk_label,
				    vnd->sc_dkdev.dk_cpulabel);
		}

		vnd->sc_flags &= ~VNF_LABELLING;

		vndunlock(vnd);

		if (error)
			return error;
		break;
	}

	case DIOCKLABEL:
		if (*(int *)data != 0)
			vnd->sc_flags |= VNF_KLABEL;
		else
			vnd->sc_flags &= ~VNF_KLABEL;
		break;

	case DIOCWLABEL:
		if (*(int *)data != 0)
			vnd->sc_flags |= VNF_WLABEL;
		else
			vnd->sc_flags &= ~VNF_WLABEL;
		break;

	case DIOCGDEFLABEL:
		vndgetdefaultlabel(vnd, (struct disklabel *)data);
		break;

#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDEFLABEL:
		vndgetdefaultlabel(vnd, &newlabel);
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(data, &newlabel, sizeof (struct olddisklabel));
		break;
#endif

	case DIOCCACHESYNC:
		vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
		error = VOP_FSYNC(vnd->sc_vp, vnd->sc_cred,
		    FSYNC_WAIT | FSYNC_DATAONLY | FSYNC_CACHE, 0, 0);
		VOP_UNLOCK(vnd->sc_vp);
		return error;

	case DIOCAWEDGE:
		dkw = (void *) data;

		if ((flag & FWRITE) == 0)
			return EBADF;

		/* If the ioctl happens here, the parent is us. */
		strlcpy(dkw->dkw_parent, device_xname(vnd->sc_dev),
		    sizeof(dkw->dkw_parent));
		return dkwedge_add(dkw);

	case DIOCDWEDGE:
		dkw = (void *) data;

		if ((flag & FWRITE) == 0)
			return EBADF;

		/* If the ioctl happens here, the parent is us. */
		strlcpy(dkw->dkw_parent, device_xname(vnd->sc_dev),
		    sizeof(dkw->dkw_parent));
		return dkwedge_del(dkw);

	case DIOCLWEDGES:
		dkwl = (void *) data;

		return dkwedge_list(&vnd->sc_dkdev, dkwl, l);

	default:
		return ENOTTY;
	}

	return 0;
}
Esempio n. 10
0
/*
 * disk_ioctl --
 *	Generic disk ioctl handling.
 */
int
disk_ioctl(struct disk *dk, dev_t dev, u_long cmd, void *data, int flag,
    struct lwp *l)
{
	struct dkwedge_info *dkw;
	struct partinfo *pt;
#ifdef __HAVE_OLD_DISKLABEL
	struct disklabel newlabel;
#endif

	switch (cmd) {
	case DIOCGDISKINFO:
		if (dk->dk_info == NULL)
			return ENOTSUP;
		return prop_dictionary_copyout_ioctl(data, cmd, dk->dk_info);

	case DIOCGSECTORSIZE:
		*(u_int *)data = dk->dk_geom.dg_secsize;
		return 0;

	case DIOCGMEDIASIZE:
		*(off_t *)data = (off_t)dk->dk_geom.dg_secsize *
		    dk->dk_geom.dg_secperunit;
		return 0;
	default:
		break;
	}

	if (dev == NODEV)
		return EPASSTHROUGH;

	/* The following should be moved to dk_ioctl */
	switch (cmd) {
	case DIOCGDINFO:
		memcpy(data, dk->dk_label, sizeof (*dk->dk_label));
		return 0;

#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDINFO:
		memcpy(&newlabel, dk->dk_label, sizeof(newlabel));
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(data, &newlabel, sizeof(struct olddisklabel));
		return 0;
#endif

	case DIOCGPART:
		if (dk->dk_label == NULL)
			return EBUSY;
		pt = data;
		pt->disklab = dk->dk_label;
		pt->part = &dk->dk_label->d_partitions[DISKPART(dev)];
		return 0;

	case DIOCAWEDGE:
		if ((flag & FWRITE) == 0)
			return EBADF;

		dkw = data;
		strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent));
		return dkwedge_add(dkw);

	case DIOCDWEDGE:
		if ((flag & FWRITE) == 0)
			return EBADF;

		dkw = data;
		strlcpy(dkw->dkw_parent, dk->dk_name, sizeof(dkw->dkw_parent));
		return dkwedge_del(dkw);

	case DIOCLWEDGES:
		return dkwedge_list(dk, data, l);

	case DIOCMWEDGES:
		if ((flag & FWRITE) == 0)
			return EBADF;

		dkwedge_discover(dk);
		return 0;

	default:
		return EPASSTHROUGH;
	}
}