static int read_label(struct biosdisk *d) { struct disklabel dflt_lbl; struct mbr_partition mbr[MBR_PART_COUNT]; struct partition *p; uint32_t sector; int i; int error; int typ; uint32_t ext_base, this_ext, next_ext; #ifdef COMPAT_386BSD_MBRPART int sector_386bsd = -1; #endif memset(&dflt_lbl, 0, sizeof(dflt_lbl)); dflt_lbl.d_npartitions = 8; d->boff = 0; if (d->ll.type != BIOSDISK_TYPE_HD) /* No label on floppy and CD */ return -1; /* * find NetBSD Partition in DOS partition table * XXX check magic??? */ ext_base = 0; next_ext = 0; for (;;) { this_ext = ext_base + next_ext; next_ext = 0; if (readsects(&d->ll, this_ext, 1, d->buf, 0)) { #ifdef DISK_DEBUG printf("error reading MBR sector %u\n", this_ext); #endif return EIO; } memcpy(&mbr, MBR_PARTS(d->buf), sizeof(mbr)); /* Look for NetBSD partition ID */ for (i = 0; i < MBR_PART_COUNT; i++) { typ = mbr[i].mbrp_type; if (typ == 0) continue; sector = this_ext + mbr[i].mbrp_start; #ifdef DISK_DEBUG printf("ptn type %d in sector %u\n", typ, sector); #endif if (typ == MBR_PTYPE_MINIX_14B) { if (!read_minix_subp(d, &dflt_lbl, this_ext, sector)) { /* Don't add "container" partition */ continue; } } if (typ == MBR_PTYPE_NETBSD) { error = check_label(d, sector); if (error >= 0) return error; } if (MBR_IS_EXTENDED(typ)) { next_ext = mbr[i].mbrp_start; continue; } #ifdef COMPAT_386BSD_MBRPART if (this_ext == 0 && typ == MBR_PTYPE_386BSD) sector_386bsd = sector; #endif if (this_ext != 0) { if (dflt_lbl.d_npartitions >= MAXPARTITIONS) continue; p = &dflt_lbl.d_partitions[dflt_lbl.d_npartitions++]; } else p = &dflt_lbl.d_partitions[i]; p->p_offset = sector; p->p_size = mbr[i].mbrp_size; p->p_fstype = xlat_mbr_fstype(typ); } if (next_ext == 0) break; if (ext_base == 0) { ext_base = next_ext; next_ext = 0; } } sector = 0; #ifdef COMPAT_386BSD_MBRPART if (sector_386bsd != -1) { printf("old BSD partition ID!\n"); sector = sector_386bsd; } #endif /* * One of two things: * 1. no MBR * 2. no NetBSD partition in MBR * * We simply default to "start of disk" in this case and * press on. */ error = check_label(d, sector); if (error >= 0) return error; /* * Nothing at start of disk, return info from mbr partitions. */ /* XXX fill it to make checksum match kernel one */ dflt_lbl.d_checksum = dkcksum(&dflt_lbl); ingest_label(d, &dflt_lbl); return 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); } } }
static int scan_mbr(mbr_args_t *a, int (*actn)(mbr_args_t *, mbr_partition_t *, int, uint)) { mbr_partition_t ptns[MBR_PART_COUNT]; mbr_partition_t *dp; struct mbr_sector *mbr; uint ext_base, this_ext, next_ext; int rval; int i; int j; #ifdef COMPAT_386BSD_MBRPART int dp_386bsd = -1; int ap_386bsd = -1; #endif ext_base = 0; this_ext = 0; for (;;) { if (read_sector(a, this_ext, 1)) { a->msg = "dos partition I/O error"; return SCAN_ERROR; } /* Note: Magic number is little-endian. */ mbr = (void *)a->bp->b_data; if (mbr->mbr_magic != htole16(MBR_MAGIC)) return SCAN_CONTINUE; /* Copy data out of buffer so action can use bp */ memcpy(ptns, &mbr->mbr_parts, sizeof ptns); /* Look for drivers and skip them */ if (ext_base == 0 && ptns[0].mbrp_type == MBR_PTYPE_DM6_DDO) { /* We've found a DM6 DDO partition type (used by * the Ontrack Disk Manager drivers). * * Ensure that there are no other partitions in the * MBR and jump to the real partition table (stored * in the first sector of the second track). */ bool ok = true; for (i = 1; i < MBR_PART_COUNT; i++) if (ptns[i].mbrp_type != MBR_PTYPE_UNUSED) ok = false; if (ok) { this_ext = le32toh(a->lp->d_secpercyl / a->lp->d_ntracks); continue; } } /* look for NetBSD partition */ next_ext = 0; dp = ptns; j = 0; for (i = 0; i < MBR_PART_COUNT; i++, dp++) { if (dp->mbrp_type == MBR_PTYPE_UNUSED) continue; /* Check end of partition is inside disk limits */ if ((uint64_t)ext_base + le32toh(dp->mbrp_start) + le32toh(dp->mbrp_size) > a->lp->d_secperunit) { /* This mbr doesn't look good.... */ a->msg = "mbr partition exceeds disk size"; /* ...but don't report this as an error (yet) */ return SCAN_CONTINUE; } a->found_mbr = 1; 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; ap_386bsd = j; } continue; } #endif rval = (*actn)(a, dp, j, this_ext); if (rval != SCAN_CONTINUE) return rval; j++; } 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], ap_386bsd, 0); #endif return SCAN_CONTINUE; }
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); }