From b9f68a246d79b2d4b8150cf83d8d978118f0a27e Mon Sep 17 00:00:00 2001 From: Eygene Ryabinkin Date: Sat, 11 Jul 2009 14:53:11 +0400 Subject: [PATCH] bsdlabel: obtain slice offset from the disklabel itself Don't use offset from MBR that is obtained by the geom(4): not any system has MBR and so on ;)) Partition 'c' holds offset, so it is used -- this corresponds to the current kernel behaviour. Extra sanity checks are made to be sure that 'c' really encloses all other partitions. Signed-off-by: Eygene Ryabinkin --- sbin/bsdlabel/bsdlabel.c | 69 +++++++++++++++++++++++++++++++++------------ 1 files changed, 50 insertions(+), 19 deletions(-) diff --git a/sbin/bsdlabel/bsdlabel.c b/sbin/bsdlabel/bsdlabel.c index 1cb9995..37db8b5 100644 --- a/sbin/bsdlabel/bsdlabel.c +++ b/sbin/bsdlabel/bsdlabel.c @@ -93,6 +93,7 @@ static int getasciipartspec(char *, struct disklabel *, int, int); static int checklabel(struct disklabel *); static void usage(void); static struct disklabel *getvirginlabel(void); +static int deduce_slice_offset(struct disklabel *, off_t *); #define DEFEDITOR _PATH_VI #define DEFPARTITIONS 8 @@ -118,7 +119,8 @@ static int installboot; /* non-zero if we should install a boot program */ static int allfields; /* present all fields in edit */ static char const *xxboot; /* primary boot */ -static off_t mbroffset; +static off_t sliceoffset; + #ifndef LABELSECTOR #define LABELSECTOR -1 #endif @@ -344,6 +346,42 @@ makelabel(const char *type, struct disklabel *lp) bzero(lp->d_packname, sizeof(lp->d_packname)); } +/* + * Determine if the offset of the 'c' partition can be used + * as the start of the slice (for example, to convert absolute + * partition offsets to the relative ones). + * + * Check is simple: + * - partition 'c' must enclose all other partitions with non-zero + * sizes. + * + * Return values: + * - 0 if everything is OK; + * - one-based number of the first partition that has problems. + */ +static int +deduce_slice_offset(struct disklabel *lbl, off_t *offset) +{ + int i; + off_t c_offset = lbl->d_partitions[RAW_PART].p_offset; + off_t c_size = lbl->d_partitions[RAW_PART].p_size; + off_t p_offset = 0; + off_t p_size = 0; + + for (i = 0; i < lbl->d_npartitions; i++) { + p_size = lbl->d_partitions[i].p_size; + if (!p_size) + continue; + p_offset = lbl->d_partitions[i].p_offset; + if (p_offset < c_offset || + p_offset + p_size > c_offset + c_size) + return i + 1; + } + + *offset = c_offset; + return 0; +} + static void readboot(void) { @@ -401,9 +439,10 @@ writelabel(void) lp->d_checksum = dkcksum(lp); if (installboot) readboot(); + for (i = 0; i < lab.d_npartitions; i++) if (lab.d_partitions[i].p_size) - lab.d_partitions[i].p_offset += mbroffset; + lab.d_partitions[i].p_offset += sliceoffset; bsd_disklabel_le_enc(bootarea + labeloffset + labelsoffset * secsize, lp); if (alphacksum) { @@ -481,8 +520,6 @@ readlabel(int flag) { int f, i; int error; - struct gctl_req *grq; - char const *errstr; f = open(specname, O_RDONLY); if (f < 0) @@ -510,22 +547,16 @@ readlabel(int flag) if (is_file) return(0); - grq = gctl_get_handle(); - gctl_ro_param(grq, "verb", -1, "read mbroffset"); - gctl_ro_param(grq, "class", -1, "BSD"); - gctl_ro_param(grq, "geom", -1, pname); - gctl_rw_param(grq, "mbroffset", sizeof(mbroffset), &mbroffset); - errstr = gctl_issue(grq); - if (errstr != NULL) { - mbroffset = 0; - gctl_free(grq); - return (error); + + sliceoffset = 0; + i = deduce_slice_offset(&lab, &sliceoffset); + if (i != 0) { + warn("partition '%c' isn't fully enclosed by the partition 'c'", + (char)('a' + i - 1)); } - mbroffset /= lab.d_secsize; - if (lab.d_partitions[RAW_PART].p_offset == mbroffset) - for (i = 0; i < lab.d_npartitions; i++) - if (lab.d_partitions[i].p_size) - lab.d_partitions[i].p_offset -= mbroffset; + for (i = 0; i < lab.d_npartitions; i++) + if (lab.d_partitions[i].p_size) + lab.d_partitions[i].p_offset -= sliceoffset; return (error); } -- 1.6.3.1