Exemplo n.º 1
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;
}
Exemplo n.º 2
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);
		}
	}
}
Exemplo n.º 3
0
static int
scan_mbr(mbr_args_t *a, int (*actn)(mbr_args_t *, struct mbr_partition *,
				    int, u_int))
{
	struct mbr_partition ptns[MBR_PART_COUNT];
	struct mbr_partition *dp;
	struct mbr_sector *mbr;
	u_int ext_base, this_ext, next_ext;
	int i, rval;
#ifdef COMPAT_386BSD_MBRPART
	int dp_386bsd = -1;
#endif

	ext_base = 0;
	this_ext = 0;
	for (;;) {
		a->error = dkwedge_read(a->pdk, a->vp, this_ext, a->buf,
					DEV_BSIZE);
		if (a->error) {
			aprint_error("%s: unable to read MBR @ %u, "
			    "error = %d\n", a->pdk->dk_name, this_ext,
			    a->error);
			return (SCAN_ERROR);
		}

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

		/* Copy data out of buffer so action can use the buffer. */
		memcpy(ptns, &mbr->mbr_parts, sizeof(ptns));

		/* Looks for NetBSD partition. */
		next_ext = 0;
		dp = ptns;
		for (i = 0; i < MBR_PART_COUNT; i++, dp++) {
			if (dp->mbrp_type == 0)
				continue;
			if (MBR_IS_EXTENDED(dp->mbrp_type)) {
				next_ext = le32toh(dp->mbrp_start);
				continue;
			}
#ifdef COMPAT_386BSD_MBRPART
			if (dp->mbrp_type == MBR_PTYPE_386BSD) {
				/*
				 * If more than one matches, take last,
				 * as NetBSD install tool does.
				 */
				if (this_ext == 0)
					dp_386bsd = i;
				continue;
			}
#endif
			rval = (*actn)(a, dp, i, this_ext);
			if (rval != SCAN_CONTINUE)
				return (rval);
		}
		if (next_ext == 0)
			break;
		if (ext_base == 0) {
			ext_base = next_ext;
			next_ext = 0;
		}
		next_ext += ext_base;
		if (next_ext <= this_ext)
			break;
		this_ext = next_ext;
	}
#ifdef COMPAT_386BSD_MBRPART
	if (this_ext == 0 && dp_386bsd != -1)
		return ((*actn)(a, &ptns[dp_386bsd], dp_386bsd, 0));
#endif
	return (SCAN_CONTINUE);
}
Exemplo n.º 4
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);
}
Exemplo n.º 5
0
static int
validate_label(mbr_args_t *a, daddr_t label_sector, size_t label_offset)
{
	struct disklabel *lp;
	void *lp_lim;
	int error, swapped;
	uint16_t npartitions;

	error = dkwedge_read(a->pdk, a->vp, label_sector, a->buf, DEV_BSIZE);
	if (error) {
		aprint_error("%s: unable to read BSD disklabel @ %" PRId64
		    ", error = %d\n", a->pdk->dk_name, label_sector, error);
		a->error = error;
		return (SCAN_ERROR);
	}

	/*
	 * We ignore label_offset; this seems to have not been used
	 * consistently in the old code, requiring us to do the search
	 * in the sector.
	 */
	lp = a->buf;
	lp_lim = (char *)a->buf + DEV_BSIZE - DISKLABEL_MINSIZE;
	for (;; lp = (void *)((char *)lp + sizeof(uint32_t))) {
		if ((char *)lp > (char *)lp_lim)
			return (SCAN_CONTINUE);
		label_offset = (size_t)((char *)lp - (char *)a->buf);
		if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC) {
			if (lp->d_magic != bswap32(DISKMAGIC) ||
			    lp->d_magic2 != bswap32(DISKMAGIC))
				continue;
			/* Label is in the other byte order. */
			swapped = 1;
		} else
			swapped = 0;

		npartitions = (swapped) ? bswap16(lp->d_npartitions)
					: lp->d_npartitions;

		/* Validate label length. */
		if ((char *)lp + DISKLABEL_SIZE(npartitions) >
		    (char *)a->buf + DEV_BSIZE) {
			aprint_error("%s: BSD disklabel @ "
			    "%" PRId64 "+%zd has bogus partition count (%u)\n",
			    a->pdk->dk_name, label_sector, label_offset,
			    npartitions);
			continue;
		}

		/*
		 * We have validated the partition count.  Checksum it.
		 * Note that we purposefully checksum before swapping
		 * the byte order.
		 */
		if (dkcksum_sized(lp, npartitions) != 0) {
			aprint_error("%s: BSD disklabel @ %" PRId64
			    "+%zd has bad checksum\n", a->pdk->dk_name,
			    label_sector, label_offset);
			continue;
		}
		/* Put the disklabel in the right order. */
		if (swapped)
			swap_disklabel(lp);
		addwedges(a, lp);
		return (SCAN_FOUND);
	}
}