diff --git a/sbin/bsdlabel/bsdlabel.c b/sbin/bsdlabel/bsdlabel.c index 3d12834f6030..366d5ec2c5c4 100644 --- a/sbin/bsdlabel/bsdlabel.c +++ b/sbin/bsdlabel/bsdlabel.c @@ -1074,7 +1074,8 @@ checklabel(struct disklabel *lp) struct partition *pp; int i, errors = 0; char part; - u_long total_size, total_percent, current_offset; + u_long base_offset, needed, total_size, total_percent, current_offset; + long free_space; int seen_default_offset; int hog_part; int j; @@ -1201,9 +1202,25 @@ checklabel(struct disklabel *lp) } } } + + /* Find out the total free space, excluding the boot block area. */ + base_offset = BBSIZE / secsize; + free_space = 0; + for (i = 0; i < lp->d_npartitions; i++) { + pp = &lp->d_partitions[i]; + if (!part_set[i] || i == RAW_PART || + part_size_type[i] == '%' || part_size_type[i] == '*') + continue; + if (pp->p_offset > base_offset) + free_space += pp->p_offset - base_offset; + if (pp->p_offset + pp->p_size > base_offset) + base_offset = pp->p_offset + pp->p_size; + } + if (base_offset < lp->d_secperunit) + free_space += lp->d_secperunit - base_offset; + /* handle % partitions - note %'s don't need to add up to 100! */ if (total_percent != 0) { - long free_space = lp->d_secperunit - total_size; if (total_percent > 100) { fprintf(stderr,"total percentage %lu is greater than 100\n", total_percent); @@ -1232,12 +1249,52 @@ checklabel(struct disklabel *lp) } /* give anything remaining to the hog partition */ if (hog_part != -1) { - lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size; - total_size = lp->d_secperunit; + /* + * Find the range of offsets usable by '*' partitions around + * the hog partition and how much space they need. + */ + needed = 0; + base_offset = BBSIZE / secsize; + for (i = hog_part - 1; i >= 0; i--) { + pp = &lp->d_partitions[i]; + if (!part_set[i] || i == RAW_PART) + continue; + if (part_offset_type[i] == '*') { + needed += pp->p_size; + continue; + } + base_offset = pp->p_offset + pp->p_size; + break; + } + current_offset = lp->d_secperunit; + for (i = lp->d_npartitions - 1; i > hog_part; i--) { + pp = &lp->d_partitions[i]; + if (!part_set[i] || i == RAW_PART) + continue; + if (part_offset_type[i] == '*') { + needed += pp->p_size; + continue; + } + current_offset = pp->p_offset; + } + + if (current_offset - base_offset <= needed) { + fprintf(stderr, "Cannot find space for partition %c\n", + hog_part + 'a'); + fprintf(stderr, + "Need more than %lu sectors between %lu and %lu\n", + needed, base_offset, current_offset); + errors++; + lp->d_partitions[hog_part].p_size = 0; + } else { + lp->d_partitions[hog_part].p_size = current_offset - + base_offset - needed; + total_size += lp->d_partitions[hog_part].p_size; + } } /* Now set the offsets for each partition */ - current_offset = 0; /* in sectors */ + current_offset = BBSIZE / secsize; /* in sectors */ seen_default_offset = 0; for (i = 0; i < lp->d_npartitions; i++) { part = 'a' + i;