diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 1997-10-20 06:26:54 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 1997-10-20 06:26:54 +0000 |
commit | bd7eeb00c36f9c7bffd7f7ab1e59bf125aa6c1c8 (patch) | |
tree | 3a67bf6f40015357e406b5116f01265e8c18b7ee /sbin/disklabel | |
parent | 9abcb266ef23f93ccccc0826233cfbdf911e1a2b (diff) |
Suport the idea of an OpenBSD portion of the disk.
Allow user to abort commands via ^D at a prompt.
Normalize usage of sectors vs. blocks
Allow real numbers when specifying in b/k/m/g
Be smarter when suggesting offsets and sizes
Always add a 'c' partition
BUGS: not all functions make sure they are operating within the OpenBSD part
Diffstat (limited to 'sbin/disklabel')
-rw-r--r-- | sbin/disklabel/editor.c | 791 |
1 files changed, 639 insertions, 152 deletions
diff --git a/sbin/disklabel/editor.c b/sbin/disklabel/editor.c index 422c70c0806..cea43ae91ea 100644 --- a/sbin/disklabel/editor.c +++ b/sbin/disklabel/editor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: editor.c,v 1.19 1997/10/18 12:07:57 deraadt Exp $ */ +/* $OpenBSD: editor.c,v 1.20 1997/10/20 06:26:53 millert Exp $ */ /* * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> @@ -31,7 +31,7 @@ */ #ifndef lint -static char rcsid[] = "$OpenBSD: editor.c,v 1.19 1997/10/18 12:07:57 deraadt Exp $"; +static char rcsid[] = "$OpenBSD: editor.c,v 1.20 1997/10/20 06:26:53 millert Exp $"; #endif /* not lint */ #include <sys/types.h> @@ -53,6 +53,12 @@ static char rcsid[] = "$OpenBSD: editor.c,v 1.19 1997/10/18 12:07:57 deraadt Exp #define DO_CONVERSIONS 0x00000001 #define DO_ROUNDING 0x00000002 +/* structure to describe a portion of a disk */ +struct diskchunk { + u_int32_t start; + u_int32_t stop; +}; + void edit_parms __P((struct disklabel *, u_int32_t *)); int editor __P((struct disklabel *, int)); void editor_add __P((struct disklabel *, u_int32_t *, char *)); @@ -64,10 +70,16 @@ char *getstring __P((struct disklabel *, char *, char *, char *)); u_int32_t getuint __P((struct disklabel *, int, char *, char *, u_int32_t, u_int32_t, int)); int has_overlap __P((struct disklabel *, u_int32_t *, int)); void make_contiguous __P((struct disklabel *)); -u_int32_t next_offset __P((struct disklabel *)); +u_int32_t next_offset __P((struct disklabel *, struct partition *)); int partition_cmp __P((const void *, const void *)); struct partition **sort_partitions __P((struct disklabel *, u_int16_t *)); void getdisktype __P((struct disklabel *, char *)); +void find_bounds __P((struct disklabel *)); +void set_bounds __P((struct disklabel *)); +struct diskchunk *free_chunks __P((struct disklabel *)); + +static u_int32_t starting_sector; +static u_int32_t ending_sector; /* from disklabel.c */ int checklabel __P((struct disklabel *)); @@ -88,29 +100,48 @@ editor(lp, f) int f; { struct disklabel lastlabel, tmplabel, label = *lp; - u_int32_t freeblocks; + struct partition *pp; + u_int32_t freesectors; FILE *fp; char buf[BUFSIZ], *cmd, *arg; int i; - /* Set freeblocks based on initial label */ - freeblocks = label.d_secperunit; - for (i = 0; i < label.d_npartitions; i++) - if (label.d_partitions[i].p_fstype != FS_UNUSED && - label.d_partitions[i].p_fstype != FS_BOOT && - label.d_partitions[i].p_size > 0) - freeblocks -= label.d_partitions[i].p_size; + /* Don't allow disk type of "unknown" */ + getdisktype(&label, "You need to specify a disk type for this disk."); + + /* How big is the OpenBSD portion of the disk? */ + find_bounds(&label); - puts("Initial label editor (enter '?' for help at any prompt)"); - if (has_overlap(&label, &freeblocks, 1)) + /* Set freesectors based on bounds and initial label */ + freesectors = ending_sector - starting_sector; + for (i = 0; i < label.d_npartitions; i++) { + pp = &label.d_partitions[i]; + if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT && + pp->p_size > 0 && pp->p_offset + pp->p_size <= ending_sector) + freesectors -= pp->p_size; + } + + /* Make sure there is no partition overlap. */ + if (has_overlap(&label, &freesectors, 1)) errx(1, "can't run when there is partition overlap."); - getdisktype(&label, "You need to specify a disk type for this disk."); + /* If we don't have a 'c' partition, create one. */ + pp = &label.d_partitions[2]; + if (label.d_npartitions < 3 || pp->p_size == 0) { + puts("No 'c' partition found, adding one that spans the disk."); + if (label.d_npartitions < 3) + label.d_npartitions = 3; + pp->p_offset = 0; + pp->p_size = label.d_secperunit; + pp->p_fstype = FS_UNUSED; + pp->p_fsize = pp->p_frag = pp->p_cpg = 0; + } #ifdef CYLCHECK puts("This platform requires that partition offsets/sizes be on cylinder boundaries.\nPartition offsets/sizes will be rounded to the nearest cylinder automatically."); #endif + puts("\nInitial label editor (enter '?' for help at any prompt)"); lastlabel = label; for (;;) { fputs("> ", stdout); @@ -134,6 +165,7 @@ editor(lp, f) puts("\tM - show entire OpenBSD man page for disklabel."); puts("\te - edit drive parameters."); puts("\ta [part] - add new partition."); + puts("\tb - set OpenBSD disk boundaries."); puts("\tc [part] - change partition size."); puts("\td [part] - delete partition."); puts("\tm [part] - modify existing partition."); @@ -143,13 +175,21 @@ editor(lp, f) puts("\tq - quit and save changes."); puts("\tx - exit without saving changes."); puts("\t? - this message."); - puts("Numeric parameters may use suffixes to indicate units:\n\t'b' for bytes, 'c' for cylinders, 'k' for kilobytes, 'm' for megabytes,\n\t'g' for gigabytes or no suffix for blocks (usually 512 bytes).\n\tNon-block units will be rounded to the nearest cylinder."); + puts("Numeric parameters may use suffixes to indicate units:\n\t'b' for bytes, 'c' for cylinders, 'k' for kilobytes, 'm' for megabytes,\n\t'g' for gigabytes or no suffix for sectors (usually 512 bytes).\n\tNon-sector units will be rounded to the nearest cylinder."); break; case 'a': tmplabel = lastlabel; lastlabel = label; - editor_add(&label, &freeblocks, arg); + editor_add(&label, &freesectors, arg); + if (memcmp(&label, &lastlabel, sizeof(label)) == 0) + lastlabel = tmplabel; + break; + + case 'b': + tmplabel = lastlabel; + lastlabel = label; + set_bounds(&label); if (memcmp(&label, &lastlabel, sizeof(label)) == 0) lastlabel = tmplabel; break; @@ -157,7 +197,7 @@ editor(lp, f) case 'c': tmplabel = lastlabel; lastlabel = label; - editor_change(&label, &freeblocks, arg); + editor_change(&label, &freesectors, arg); if (memcmp(&label, &lastlabel, sizeof(label)) == 0) lastlabel = tmplabel; break; @@ -165,7 +205,7 @@ editor(lp, f) case 'd': tmplabel = lastlabel; lastlabel = label; - editor_delete(&label, &freeblocks, arg); + editor_delete(&label, &freesectors, arg); if (memcmp(&label, &lastlabel, sizeof(label)) == 0) lastlabel = tmplabel; break; @@ -173,13 +213,13 @@ editor(lp, f) case 'm': tmplabel = lastlabel; lastlabel = label; - editor_modify(&label, &freeblocks, arg); + editor_modify(&label, &freesectors, arg); if (memcmp(&label, &lastlabel, sizeof(label)) == 0) lastlabel = tmplabel; break; case 'p': - editor_display(&label, &freeblocks, arg ? *arg : 0); + editor_display(&label, &freesectors, arg ? *arg : 0); break; case 'M': @@ -205,8 +245,8 @@ editor(lp, f) arg = getstring(lp, "Save changes?", "Save changes you have made to the label?", "n"); - } while (tolower(*arg) != 'y' && tolower(*arg) != 'n'); - if (tolower(*arg) == 'y') { + } while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n'); + if (arg && tolower(*arg) == 'y') { *lp = label; if (writelabel(f, bootarea, lp) == 0) return(0); @@ -220,7 +260,7 @@ editor(lp, f) arg = getstring(lp, "Filename", "Name of the file to save label into.", NULL); - if (*arg == '\0') + if (arg == NULL && *arg == '\0') break; } if ((fp = fopen(arg, "w")) == NULL) { @@ -263,7 +303,7 @@ editor(lp, f) case 'e': tmplabel = lastlabel; lastlabel = label; - edit_parms(&label, &freeblocks); + edit_parms(&label, &freesectors); if (memcmp(&label, &lastlabel, sizeof(label)) == 0) lastlabel = tmplabel; break; @@ -284,10 +324,11 @@ editor_add(lp, freep, p) u_int32_t *freep; char *p; { - struct partition origpart, *pp; + struct partition *pp; + struct diskchunk *chunks; char buf[BUFSIZ]; int i, partno; - u_int32_t ui; + u_int32_t ui, old_offset, old_size; /* XXX - prompt user to steal space from another partition instead */ if (*freep == 0) { @@ -304,7 +345,7 @@ editor_add(lp, freep, p) "Partition must be between 'a' and '%c'.\n", 'a' + MAXPARTITIONS - 1); return; - } else if (lp->d_partitions[partno].p_fstype != FS_UNUSED || + } else if (lp->d_partitions[partno].p_fstype != FS_UNUSED && lp->d_partitions[partno].p_size != 0) { fprintf(stderr, "Partition '%c' exists. Delete it first.\n", @@ -327,59 +368,45 @@ editor_add(lp, freep, p) for (;;) { p = getstring(lp, "partition", "The letter of the new partition, a - p.", p); + if (p == NULL) + return; partno = p[0] - 'a'; - if (partno >= 0 && partno < MAXPARTITIONS) + if (lp->d_partitions[partno].p_fstype != FS_UNUSED && + lp->d_partitions[partno].p_size != 0) { + fprintf(stderr, + "Partition '%c' already exists.\n", p[0]); + } else if (partno >= 0 && partno < MAXPARTITIONS) break; fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 'a' + MAXPARTITIONS - 1); } } - /* Increase d_npartitions and set defaults if necesary */ - pp = &lp->d_partitions[partno]; - if (partno >= lp->d_npartitions || pp->p_fstype == FS_UNUSED) { - if (partno >= lp->d_npartitions) - lp->d_npartitions = partno + 1; - memset(pp, 0, sizeof(*pp)); - pp->p_offset = next_offset(lp); - pp->p_size = *freep; - if (partno == 1) - pp->p_fstype = FS_SWAP; - else - pp->p_fstype = FS_BSDFFS; - pp->p_fsize = 1024; - pp->p_frag = 8; - pp->p_cpg = 16; - } - origpart = *pp; - /* Get fstype */ - if (pp->p_fstype < FSMAXTYPES) { - p = getstring(lp, "FS type", - "Filesystem type (usually 4.2BSD or swap)", - fstypenames[pp->p_fstype]); - for (i = 0; i < FSMAXTYPES; i++) { - if (!strcasecmp(p, fstypenames[i])) { - pp->p_fstype = i; - break; - } - } - if (i >= FSMAXTYPES) { - printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p); - pp->p_fstype = FS_OTHER; - } - } else { - for (;;) { - ui = getuint(lp, partno, "FS type (decimal)", - "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", - pp->p_fstype, pp->p_fstype, 0); - if (ui == UINT_MAX) - fputs("Invalid entry\n", stderr); - else - break; - } - pp->p_fstype = ui; + /* Increase d_npartitions if necesary */ + if (partno >= lp->d_npartitions) + lp->d_npartitions = partno + 1; + + /* Set defaults */ + pp = &lp->d_partitions[partno]; + if (partno >= lp->d_npartitions) + lp->d_npartitions = partno + 1; + memset(pp, 0, sizeof(*pp)); + pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS; + pp->p_fsize = 1024; + pp->p_frag = 8; + pp->p_cpg = 16; + pp->p_size = *freep; + pp->p_offset = next_offset(lp, pp); /* must be computed last */ +#ifdef DOSLABEL + /* Don't clobber the MBR */ + if (pp->p_offset == 0) { + pp->p_offset = 32; + pp->p_size -= 32; } +#endif + old_offset = pp->p_offset; + old_size = pp->p_size; getoff1: /* Get offset */ @@ -388,47 +415,128 @@ getoff1: "Starting sector for this partition.", pp->p_offset, pp->p_offset, DO_CONVERSIONS | (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + pp->p_size = 0; /* effective delete */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); + else if (ui < starting_sector) + fprintf(stderr, "The OpenBSD portion of the disk starts" + " at sector %u, you tried to add a partition at %u\n" + , starting_sector, ui); + else if (ui >= ending_sector) + fprintf(stderr, "The OpenBSD portion of the disk ends " + "at sector %u, you tried to add a partition at %u\n", + ending_sector, ui); else break; } pp->p_offset = ui; + /* Recompute recommended size based on new offset */ + ui = pp->p_fstype; + pp->p_fstype = FS_UNUSED; + chunks = free_chunks(lp); + for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { + if (pp->p_offset >= chunks[i].start && + pp->p_offset < chunks[i].stop) { + pp->p_size = chunks[i].stop - pp->p_offset; + break; + } + } + pp->p_fstype = ui; + /* Get size */ for (;;) { ui = getuint(lp, partno, "size", "Size of the partition.", pp->p_size, *freep, DO_CONVERSIONS | - (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); - if (ui + pp->p_offset > lp->d_partitions[2].p_size + - lp->d_partitions[2].p_offset) - fputs("Partition must not extend past 'c'\n", stderr); + ((pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_SWAP) ? + DO_ROUNDING : 0)); + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + pp->p_size = 0; /* effective delete */ + return; + } else if (ui == UINT_MAX) + fputs("Invalid entry\n", stderr); else if (ui > *freep) /* XXX - prompt user to steal space from another partition */ - fprintf(stderr,"Sorry, there are only %u blocks left\n", + fprintf(stderr,"Sorry, there are only %u sectors left\n", *freep); + else if (pp->p_offset + ui > ending_sector) + fprintf(stderr, "The OpenBSD portion of the disk ends " + "at sector %u, you tried to add a partition ending " + "at sector %u\n", + ending_sector, pp->p_offset + ui); else break; } +#ifdef DOSLABEL + if (pp->p_offset == 32 && ui % lp->d_secpercyl == 0) { + ui -= 32; + puts("Adjusting size by 32 to maintain cylinder boundaries"); + } +#endif pp->p_size = ui; if (pp->p_size == 0) return; - /* Check for overlap and restore if not resolved */ + /* Check for overlap */ if (has_overlap(lp, freep, 0)) { puts("\nPlease re-enter an offset and size"); - pp->p_offset = origpart.p_offset; - pp->p_size = origpart.p_size; + pp->p_offset = old_offset; + pp->p_size = old_size; goto getoff1; /* Yeah, I know... */ } + /* Get fstype */ + if (pp->p_fstype < FSMAXTYPES) { + p = getstring(lp, "FS type", + "Filesystem type (usually 4.2BSD or swap)", + fstypenames[pp->p_fstype]); + if (p == NULL) { + fputs("Command aborted\n", stderr); + pp->p_size = 0; /* effective delete */ + return; + } + for (i = 0; i < FSMAXTYPES; i++) { + if (!strcasecmp(p, fstypenames[i])) { + pp->p_fstype = i; + break; + } + } + if (i >= FSMAXTYPES) { + printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p); + pp->p_fstype = FS_OTHER; + } + } else { + for (;;) { + ui = getuint(lp, partno, "FS type (decimal)", + "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", + pp->p_fstype, pp->p_fstype, 0); + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + pp->p_size = 0; /* effective delete */ + return; + } if (ui == UINT_MAX) + fputs("Invalid entry\n", stderr); + else + break; + } + pp->p_fstype = ui; + } + if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) { /* get fsize */ for (;;) { ui = getuint(lp, partno, "fragment size", "Size of fs block fragments. Usually 1024 or 512.", pp->p_fsize, pp->p_fsize, 0); - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + pp->p_size = 0; /* effective delete */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); else break; @@ -446,7 +554,11 @@ getoff1: 0); /* sanity checks */ - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + pp->p_size = 0; /* effective delete */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); else if (ui < getpagesize()) fprintf(stderr, @@ -467,7 +579,11 @@ getoff1: ui = getuint(lp, partno, "cpg", "Number of filesystem cylinders per group. Usually 16 or 8.", pp->p_cpg, pp->p_cpg, 0); - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + pp->p_size = 0; /* effective delete */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); else break; @@ -475,9 +591,11 @@ getoff1: pp->p_cpg = ui; } } - /* Update free block count and make sure things stay contiguous. */ + /* Update free sector count and make sure things stay contiguous. */ *freep -= pp->p_size; - make_contiguous(lp); + if (pp->p_size + pp->p_offset > ending_sector || + has_overlap(lp, freep, -1)) + make_contiguous(lp); } /* @@ -498,6 +616,10 @@ editor_modify(lp, freep, p) p = getstring(lp, "partition to modify", "The letter of the partition to modify, a - p.", NULL); } + if (p == NULL) { + fputs("Command aborted\n", stderr); + return; + } partno = p[0] - 'a'; pp = &lp->d_partitions[partno]; origpart = lp->d_partitions[partno]; @@ -516,6 +638,11 @@ editor_modify(lp, freep, p) p = getstring(lp, "FS type", "Filesystem type (usually 4.2BSD or swap)", fstypenames[pp->p_fstype]); + if (p == NULL) { + fputs("Command aborted\n", stderr); + pp->p_size = 0; /* effective delete */ + return; + } for (ui = 0; ui < FSMAXTYPES; ui++) { if (!strcasecmp(p, fstypenames[ui])) { pp->p_fstype = ui; @@ -531,7 +658,11 @@ editor_modify(lp, freep, p) ui = getuint(lp, partno, "FS type (decimal)", "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", pp->p_fstype, pp->p_fstype, 0); - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + pp->p_size = 0; /* effective delete */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); else break; @@ -547,7 +678,7 @@ editor_modify(lp, freep, p) (origpart.p_fstype == FS_UNUSED || origpart.p_fstype == FS_BOOT)) { if (pp->p_size > *freep) { fprintf(stderr, - "Warning, need %u blocks but there are only %u " + "Warning, need %u sectors but there are only %u " "free. Setting size to %u.\n", pp->p_size, *freep, *freep); pp->p_fstype = *freep; @@ -563,9 +694,17 @@ getoff2: "Starting sector for this partition.", pp->p_offset, pp->p_offset, DO_CONVERSIONS | (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + *pp = origpart; /* undo changes */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); - else + else if (partno != 2 && ui + ui < starting_sector) { + fprintf(stderr, "The OpenBSD portion of the disk starts" + " at sector %u, you tried to start at %u\n", + starting_sector, ui); + } else break; } pp->p_offset = ui; @@ -579,13 +718,13 @@ getoff2: if (ui == pp->p_size) break; /* no change */ - if (ui == UINT_MAX) { + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + *pp = origpart; /* undo changes */ + return; + } else if (ui == UINT_MAX) { fputs("Invalid entry\n", stderr); continue; - } else if (partno != 2 && ui + pp->p_offset > - lp->d_partitions[2].p_size + lp->d_partitions[2].p_offset) { - fputs("Partition must not extend past 'c'\n", stderr); - continue; } else if (partno == 2 && ui + pp->p_offset > lp->d_secperunit) { fputs("'c' partition may not be larger than the disk\n", stderr); @@ -599,7 +738,7 @@ getoff2: if (ui > pp->p_size + *freep) /* XXX - prompt user to steal space from another partition */ fprintf(stderr, - "Size may not be larger than %u blocks\n", + "Size may not be larger than %u sectors\n", pp->p_size + *freep); else { *freep += pp->p_size - ui; @@ -625,7 +764,11 @@ getoff2: ui = getuint(lp, partno, "fragment size", "Size of fs block fragments. Usually 1024 or 512.", pp->p_fsize, 1024, 0); - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + *pp = origpart; /* undo changes */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); else break; @@ -642,7 +785,11 @@ getoff2: 0); /* sanity check */ - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + *pp = origpart; /* undo changes */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); else if (ui % pp->p_fsize != 0) puts("Error: block size must be a multiple of the fragment size."); @@ -661,7 +808,11 @@ getoff2: "Number of filesystem cylinders per group." " Usually 16 or 8.", pp->p_cpg, pp->p_cpg, 0); - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + *pp = origpart; /* undo changes */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); else break; @@ -671,7 +822,9 @@ getoff2: } /* Make sure things stay contiguous. */ - make_contiguous(lp); + if (pp->p_size + pp->p_offset > ending_sector || + has_overlap(lp, freep, -1)) + make_contiguous(lp); } /* @@ -689,6 +842,10 @@ editor_delete(lp, freep, p) p = getstring(lp, "partition to delete", "The letter of the partition to delete, a - p.", NULL); } + if (p == NULL) { + fputs("Command aborted\n", stderr); + return; + } c = p[0] - 'a'; if (c < 0 || c >= lp->d_npartitions) fprintf(stderr, "Partition must be between 'a' and '%c'.\n", @@ -698,8 +855,13 @@ editor_delete(lp, freep, p) fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + c); else if (c == 2) fputs("You may not delete the 'c' partition.\n", stderr); + else if (lp->d_partitions[c].p_offset >= ending_sector || + lp->d_partitions[c].p_offset < starting_sector) + fprintf(stderr, "The OpenBSD portion of the disk ends at sector" + " %u.\nYou can't remove a partition outside the OpenBSD " + "part of the disk.\n", ending_sector); else { - /* Update free block count. */ + /* Update free sector count. */ if (lp->d_partitions[c].p_fstype != FS_UNUSED && lp->d_partitions[c].p_fstype != FS_BOOT && lp->d_partitions[c].p_size != 0) @@ -708,9 +870,6 @@ editor_delete(lp, freep, p) /* Really delete it (as opposed to just setting to "unused") */ (void)memset(&lp->d_partitions[c], 0, sizeof(lp->d_partitions[c])); - - /* Fill in the gap we just made */ - make_contiguous(lp); } } @@ -745,30 +904,64 @@ editor_display(lp, freep, unit) /* * Find the next reasonable starting offset and returns it. - * Assumes there is a least one free block left (returns 0 if not). + * Assumes there is a least one free sector left (returns 0 if not). */ u_int32_t -next_offset(lp) +next_offset(lp, pp) struct disklabel *lp; + struct partition *pp; { struct partition **spp; + struct diskchunk *chunks; u_int16_t npartitions; - u_int32_t new_offset = 0; - int i; + u_int32_t new_offset, new_size; + int i, good_offset; /* Get a sorted list of the partitions */ - spp = sort_partitions(lp, &npartitions); - + if ((spp = sort_partitions(lp, &npartitions)) == NULL) + return(0); + + new_offset = starting_sector; for (i = 0; i < npartitions; i++ ) { + /* Skip the partition for which we are finding an offset */ + if (pp == spp[i]) + continue; + /* * Is new_offset inside this partition? If so, - * make it the next block after the partition ends. + * make it the next sector after the partition ends. */ - if (new_offset >= spp[i]->p_offset && - new_offset < spp[i]->p_offset + spp[i]->p_size) + if ((new_offset >= spp[i]->p_offset && + new_offset < spp[i]->p_offset + spp[i]->p_size) || + (new_offset + pp->p_size >= spp[i]->p_offset && new_offset + + pp->p_size <= spp[i]->p_offset + spp[i]->p_size)) new_offset = spp[i]->p_offset + spp[i]->p_size; } + /* Did we find a suitable offset? */ + for (good_offset = 1, i = 0; i < npartitions; i++ ) { + if (new_offset + pp->p_size >= spp[i]->p_offset && + new_offset + pp->p_size <= spp[i]->p_offset + spp[i]->p_size) { + /* Nope */ + good_offset = 0; + break; + } + } + + /* Specified size is too big, find something that fits */ + if (!good_offset) { + chunks = free_chunks(lp); + new_size = 0; + for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { + if (chunks[i].stop - chunks[i].start > new_size) { + new_size = chunks[i].stop - chunks[i].start; + new_offset = chunks[i].start; + } + } + /* XXX - if new_size is 0 here then there was no space at all */ + pp->p_size = new_size; + } + (void)free(spp); return(new_offset); } @@ -789,6 +982,10 @@ editor_change(lp, freep, p) p = getstring(lp, "partition to change size", "The letter of the partition to change size, a - p.", NULL); } + if (p == NULL) { + fputs("Command aborted\n", stderr); + return; + } partno = p[0] - 'a'; if (partno < 0 || partno >= lp->d_npartitions) { fprintf(stderr, "Partition must be between 'a' and '%c'.\n", @@ -808,7 +1005,10 @@ editor_change(lp, freep, p) lp->d_partitions[partno].p_size, lp->d_partitions[partno].p_size + *freep, DO_CONVERSIONS | (lp->d_partitions[partno].p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); - if (newsize == UINT_MAX) { + if (newsize == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + return; + } else if (newsize == UINT_MAX) { fputs("Invalid entry\n", stderr); return; } else if (newsize == lp->d_partitions[partno].p_size) @@ -829,11 +1029,7 @@ editor_change(lp, freep, p) *freep += lp->d_partitions[partno].p_size - newsize; } } else { - if (partno != 2 && newsize + lp->d_partitions[partno].p_offset > - lp->d_partitions[2].p_size) { - fputs("Partition must not extend past 'c'\n", stderr); - return; - } else if (partno == 2 && newsize + + if (partno == 2 && newsize + lp->d_partitions[partno].p_offset > lp->d_secperunit) { fputs("'c' partition may not be larger than the disk\n", stderr); @@ -841,7 +1037,9 @@ editor_change(lp, freep, p) } } lp->d_partitions[partno].p_size = newsize; - make_contiguous(lp); + if (newsize + lp->d_partitions[partno].p_offset > ending_sector || + has_overlap(lp, freep, -1)) + make_contiguous(lp); } void @@ -853,13 +1051,19 @@ make_contiguous(lp) int i; /* Get a sorted list of the partitions */ - spp = sort_partitions(lp, &npartitions); + if ((spp = sort_partitions(lp, &npartitions)) == NULL) + return; /* * Make everything contiguous but don't muck with start of the first one + * or partitions not in the BSD part of the label. */ - for (i = 1; i < npartitions; i++) - spp[i]->p_offset = spp[i - 1]->p_offset + spp[i - 1]->p_size; + for (i = 1; i < npartitions; i++) { + if (spp[i]->p_offset >= starting_sector || + spp[i]->p_offset < ending_sector) + spp[i]->p_offset = + spp[i - 1]->p_offset + spp[i - 1]->p_size; + } (void)free(spp); } @@ -894,8 +1098,11 @@ getstring(lp, prompt, helpstring, oval) fflush(stdout); rewind(stdin); if (fgets(buf, sizeof(buf), stdin) == NULL) { - putchar('\n'); buf[0] = '\0'; + if (feof(stdin)) { + putchar('\n'); + return(NULL); + } } n = strlen(buf); if (n > 0 && buf[n-1] == '\n') @@ -929,7 +1136,7 @@ getuint(lp, partno, prompt, helpstring, oval, maxval, flags) u_int32_t rval = oval; size_t n; int mult = 1; - u_long ul; + double d; buf[0] = '\0'; do { @@ -937,8 +1144,11 @@ getuint(lp, partno, prompt, helpstring, oval, maxval, flags) fflush(stdout); rewind(stdin); if (fgets(buf, sizeof(buf), stdin) == NULL) { - putchar('\n'); buf[0] = '\0'; + if (feof(stdin)) { + putchar('\n'); + return(UINT_MAX - 1); + } } n = strlen(buf); if (n > 0 && buf[n-1] == '\n') @@ -953,7 +1163,7 @@ getuint(lp, partno, prompt, helpstring, oval, maxval, flags) /* deal with units */ if (buf[0] != '\0' && n > 0) { if ((flags & DO_CONVERSIONS)) { - switch (buf[n-1]) { + switch (tolower(buf[n-1])) { case 'c': mult = lp->d_secpercyl; @@ -976,8 +1186,7 @@ getuint(lp, partno, prompt, helpstring, oval, maxval, flags) buf[--n] = '\0'; break; } - } else - mult = 1; + } /* Did they give us an operator? */ p = &buf[0]; @@ -985,23 +1194,22 @@ getuint(lp, partno, prompt, helpstring, oval, maxval, flags) operator = *p++; endptr = p; - if (mult > 0) - ul = strtoul(p, &endptr, 10) * mult; - else - /* Negative mult means divide (ooh, fancy) */ - ul = strtoul(p, &endptr, 10) / (-mult); - - /* Sanity check the return val */ - if (ul == ULONG_MAX || ul >= UINT_MAX) { - errno = ERANGE; /* too big */ - rval = UINT_MAX; - } else if (*endptr != '\0') { + errno = 0; + d = strtod(p, &endptr); + if (errno == ERANGE) + rval = UINT_MAX; /* too big/small */ + else if (*endptr != '\0') { errno = EINVAL; /* non-numbers in str */ rval = UINT_MAX; } else { - rval = ul; + /* XXX - should check for overflow */ + if (mult > 0) + rval = d * mult; + else + /* Negative mult means divide (fancy) */ + rval = d / (-mult); - /* Apply the operator (XXX - check for oflow) */ + /* Apply the operator */ if (operator == '+') rval += oval; else if (operator == '-') @@ -1020,8 +1228,8 @@ getuint(lp, partno, prompt, helpstring, oval, maxval, flags) printf("Rounding to nearest cylinder: %u\n", rval); } #else - /* Round to nearest cylinder unless given in blocks */ - if (mult > 1) { + /* Round to nearest cylinder unless given in sectors */ + if (mult != 1) { cyls = (u_int32_t)((rval / (double)lp->d_secpercyl) + 0.5); if (rval != cyls * lp->d_secpercyl) { @@ -1064,6 +1272,12 @@ has_overlap(lp, freep, resolve) for (j = i + 1; j < npartitions; j++) { /* `if last_sec_in_part + 1 > first_sec_in_next_part' */ if (spp[i]->p_offset + spp[i]->p_size > spp[j]->p_offset) { + /* Don't print, just return */ + if (resolve == -1) { + (void)free(spp); + return(1); + } + /* Overlap! Convert to real part numbers. */ i = ((char *)spp[i] - (char *)lp->d_partitions) / sizeof(**spp); @@ -1076,7 +1290,7 @@ has_overlap(lp, freep, resolve) display_partition(stdout, lp, j, 0); /* Did they ask us to resolve it ourselves? */ - if (!resolve) { + if (resolve != 1) { (void)free(spp); return(1); } @@ -1111,6 +1325,7 @@ edit_parms(lp, freep) { char *p; u_int32_t ui; + struct disklabel oldlabel = *lp; printf("Changing device parameters for %s:\n", specname); @@ -1119,6 +1334,10 @@ edit_parms(lp, freep) p = getstring(lp, "disk type", "What kind of disk is this? Usually SCSI, ST506, or " "floppy (use ST506 for IDE).", dktypenames[lp->d_type]); + if (p == NULL) { + fputs("Command aborted\n", stderr); + return; + } for (ui = 1; ui < DKMAXTYPES && strcasecmp(p, dktypenames[ui]); ui++) ; @@ -1141,6 +1360,11 @@ edit_parms(lp, freep) p = getstring(lp, "label name", "15 char string that describes this label, usually the disk name.", lp->d_packname); + if (p == NULL) { + fputs("Command aborted\n", stderr); + *lp = oldlabel; /* undo damage */ + return; + } strncpy(lp->d_packname, p, sizeof(lp->d_packname) - 1); lp->d_packname[sizeof(lp->d_packname) - 1] = '\0'; @@ -1149,7 +1373,11 @@ edit_parms(lp, freep) ui = getuint(lp, 0, "sectors/track", "The Numer of sectors per track.", lp->d_nsectors, lp->d_nsectors, 0); - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + *lp = oldlabel; /* undo damage */ + return; + } if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); else break; @@ -1161,7 +1389,11 @@ edit_parms(lp, freep) ui = getuint(lp, 0, "tracks/cylinder", "The number of tracks per cylinder.", lp->d_ntracks, lp->d_ntracks, 0); - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + *lp = oldlabel; /* undo damage */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); else break; @@ -1173,7 +1405,11 @@ edit_parms(lp, freep) ui = getuint(lp, 0, "sectors/cylinder", "The number of sectors per cylinder (Usually sectors/track " "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl, 0); - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + *lp = oldlabel; /* undo damage */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); else break; @@ -1185,7 +1421,11 @@ edit_parms(lp, freep) ui = getuint(lp, 0, "number of cylinders", "The total number of cylinders on the disk.", lp->d_ncylinders, lp->d_ncylinders, 0); - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + *lp = oldlabel; /* undo damage */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); else break; @@ -1199,14 +1439,20 @@ edit_parms(lp, freep) lp->d_secperunit ? lp->d_secperunit : lp->d_ncylinders * lp->d_ncylinders, lp->d_ncylinders * lp->d_ncylinders, 0); - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + *lp = oldlabel; /* undo damage */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); - else if (ui > lp->d_secperunit) { + else if (ui > lp->d_secperunit && + ending_sector == lp->d_secperunit) { /* grow free count */ *freep += ui - lp->d_secperunit; puts("You may want to increase the 'c' partition."); break; - } else if (ui < lp->d_secperunit) { + } else if (ui < lp->d_secperunit && + ending_sector == lp->d_secperunit) { /* shrink free count */ if (lp->d_secperunit - ui > *freep) fprintf(stderr, @@ -1220,6 +1466,9 @@ edit_parms(lp, freep) } else break; } + /* Adjust ending_sector if necesary. */ + if (ending_sector > ui) + ending_sector = ui; lp->d_secperunit = ui; /* rpm */ @@ -1227,7 +1476,11 @@ edit_parms(lp, freep) ui = getuint(lp, 0, "rpm", "The rotational speed of the disk in revolutions per minute.", lp->d_rpm, lp->d_rpm, 0); - if (ui == UINT_MAX) + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + *lp = oldlabel; /* undo damage */ + return; + } else if (ui == UINT_MAX) fputs("Invalid entry\n", stderr); else break; @@ -1251,6 +1504,10 @@ sort_partitions(lp, npart) lp->d_partitions[i].p_size != 0) npartitions++; } + if (npartitions == 0) { + *npart = 0; + return(NULL); + } /* Create an array of pointers to the partition data */ if ((spp = malloc(sizeof(struct partition *) * npartitions)) == NULL) @@ -1300,6 +1557,8 @@ getdisktype(lp, banner) s = getstring(lp, "Disk type", "What kind of disk is this? Usually SCSI, ST506, or floppy (use ST506 for IDE).", "SCSI"); + if (s == NULL) + continue; for (i = 1; i < DKMAXTYPES; i++) if (strcasecmp(s, dktypenames[i]) == 0) { lp->d_type = i; @@ -1317,3 +1576,231 @@ getdisktype(lp, banner) } } } + +/* + * Get beginning and ending sectors of the OpenBSD portion of the disk + * from the user. + */ +void +set_bounds(lp) + struct disklabel *lp; +{ + u_int32_t ui, start_temp; + + /* Starting sector */ + do { + ui = getuint(lp, 0, "Starting sector", + "The start of the OpenBSD portion of the disk.", + starting_sector, lp->d_secperunit, 0); + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + return; + } + } while (ui >= lp->d_secperunit); + start_temp = ui; + + /* Ending sector */ + do { + ui = getuint(lp, 0, "Ending sector", + "The end of the OpenBSD portion of the disk.", + ending_sector, lp->d_secperunit, 0); + if (ui == UINT_MAX - 1) { + fputs("Command aborted\n", stderr); + return; + } + } while (ui > lp->d_secperunit); + ending_sector = ui; + starting_sector = start_temp; +} + +/* + * Find the possible/likely start/stop of the OpenBSD portion of the disk. + * Sets starting_sector and ending_sector globals. + * XXX - assumes first OpenBSD partition is 4.2/swap or unused space. + */ +void +find_bounds(lp) + struct disklabel *lp; +{ + u_int16_t npartitions; + struct partition **spp; + struct diskchunk chunks[2 * MAXPARTITIONS + 1]; + int i, j, numchunks, ourchunk = -1; + + /* Sort the partitions based on offset */ + spp = sort_partitions(lp, &npartitions); + + /* If there are no partitions, we get it all. */ + if (spp == NULL) { + starting_sector = 0; + ending_sector = lp->d_secperunit; + puts("OpenBSD will use the entire disk."); + return; + } + + /* Find chunks of free space */ + numchunks = 0; + if (spp && spp[0]->p_offset > 0) { + chunks[0].start = 0; + chunks[0].stop = spp[0]->p_offset; + numchunks++; + } + for (i = 0; i < npartitions; i++) { + if (i + 1 < npartitions) { + if (spp[i]->p_offset + spp[i]->p_size < spp[i+1]->p_offset) { + chunks[numchunks].start = + spp[i]->p_offset + spp[i]->p_size; + chunks[numchunks].stop = spp[i+1]->p_offset; + numchunks++; + } + } else { + /* Last partition */ + if (spp[i]->p_offset + spp[i]->p_size < lp->d_secperunit) { + + chunks[numchunks].start = + spp[i]->p_offset + spp[i]->p_size; + chunks[numchunks].stop = lp->d_secperunit; + numchunks++; + } + } + } + + /* Now find the OpenBSD partitions and add them in to "chunks" */ + for (i = 0; i < npartitions; i++) { + if (spp[i]->p_fstype == FS_BSDFFS || spp[i]->p_fstype == FS_SWAP) { + /* Look for a consecutive chunk to add to */ + for (j = 0; j < numchunks; j++) { + if (chunks[j].stop == spp[i]->p_offset) { + chunks[j].stop += spp[i]->p_size; + if (ourchunk == -1) + ourchunk = j + 1; + break; + } else if (chunks[j].start == + spp[i]->p_offset + spp[i]->p_size) { + chunks[j].start -= spp[i]->p_size; + if (ourchunk == -1) + ourchunk = j + 1; + break; + } + } + + /* Else add a new one */ + if (j >= numchunks) { + chunks[numchunks].start = spp[i]->p_offset; + chunks[numchunks].stop = + spp[i]->p_offset + spp[i]->p_size; + numchunks++; + if (ourchunk == -1) + ourchunk = numchunks; + } + } + } + + /* If we ended up with consecutive chunks, collapse them. */ + check_chunks: + for (i = 0; i < numchunks; i++) { + for (j = 0; j < numchunks; j++) { + if (j == i) + continue; + if (chunks[i].stop == chunks[j].start) { + /* Collapse i and j */ + chunks[i].stop += + chunks[j].stop - chunks[j].start; + for (i = j; i < numchunks - 1; i++) + chunks[i] = chunks[i+1]; + numchunks--; + goto check_chunks; + } + } + } + + /* + * Prompt user to choose which one for OpenBSD (if more than one) + * Note: we assume that the first chunk with BSD partitions is ours. + */ + if (numchunks > 1) { + printf("# size offset fstype [fsize bsize cpg]\n"); + for (i = 0; i < lp->d_npartitions; i++) + display_partition(stdout, lp, i, 0); + puts("Several chunks of unused or BSD space exist, which one is for OpenBSD?"); + if (ourchunk != -1) + printf("It looks like the OpenBSD portion is chunk " + "number %d\n", ourchunk); + else + ourchunk = 1; + + for (i = 0; i < numchunks; i++) { + printf("%6d: start = %d, stop = %d\n", i + 1, + chunks[i].start, chunks[i].stop); + } + do { + ourchunk = getuint(lp, 0, "Choose one", + "The portion of the disk you will use for OpenBSD.", + ourchunk, numchunks, 0); + } while (ourchunk < 1 || ourchunk > numchunks); + } + ourchunk--; + + starting_sector = chunks[ourchunk].start; + ending_sector = chunks[ourchunk].stop; + printf("Treating sectors %u-%u as the OpenBSD portion of the disk.\n", + starting_sector, ending_sector); + + (void)free(spp); +} + +/* + * Return a list of the "chunks" of free space available + */ +struct diskchunk * +free_chunks(lp) + struct disklabel *lp; +{ + u_int16_t npartitions; + struct partition **spp; + static struct diskchunk chunks[MAXPARTITIONS + 2]; + int i, numchunks; + + /* Sort the partitions based on offset */ + spp = sort_partitions(lp, &npartitions); + + /* If there are no partitions, it's all free. */ + if (spp == NULL) { + chunks[0].start = 0; + chunks[0].stop = ending_sector; + chunks[1].start = chunks[1].stop = 0; + return(chunks); + } + + /* Find chunks of free space */ + numchunks = 0; + if (spp && spp[0]->p_offset > 0) { + chunks[0].start = 0; + chunks[0].stop = spp[0]->p_offset; + numchunks++; + } + for (i = 0; i < npartitions; i++) { + if (i + 1 < npartitions) { + if (spp[i]->p_offset + spp[i]->p_size < spp[i+1]->p_offset) { + chunks[numchunks].start = + spp[i]->p_offset + spp[i]->p_size; + chunks[numchunks].stop = spp[i+1]->p_offset; + numchunks++; + } + } else { + /* Last partition */ + if (spp[i]->p_offset + spp[i]->p_size < lp->d_secperunit) { + + chunks[numchunks].start = + spp[i]->p_offset + spp[i]->p_size; + chunks[numchunks].stop = lp->d_secperunit; + numchunks++; + } + } + } + + /* Terminate and return */ + chunks[numchunks].start = chunks[numchunks].stop = 0; + (void)free(spp); + return(chunks); +} |