1*617e6e4aSmillert /* $OpenBSD: editor.c,v 1.43 1998/08/06 18:07:40 millert Exp $ */ 26fe57b42Smillert 36fe57b42Smillert /* 4*617e6e4aSmillert * Copyright (c) 1997-1998 Todd C. Miller <Todd.Miller@courtesan.com> 56fe57b42Smillert * All rights reserved. 66fe57b42Smillert * 76fe57b42Smillert * Redistribution and use in source and binary forms, with or without 86fe57b42Smillert * modification, are permitted provided that the following conditions 96fe57b42Smillert * are met: 106fe57b42Smillert * 1. Redistributions of source code must retain the above copyright 116fe57b42Smillert * notice, this list of conditions and the following disclaimer. 126fe57b42Smillert * 2. Redistributions in binary form must reproduce the above copyright 136fe57b42Smillert * notice, this list of conditions and the following disclaimer in the 146fe57b42Smillert * documentation and/or other materials provided with the distribution. 159141dda3Smillert * 3. The name of the author may not be used to endorse or promote products 166fe57b42Smillert * derived from this software without specific prior written permission. 176fe57b42Smillert * 186fe57b42Smillert * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 196fe57b42Smillert * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 206fe57b42Smillert * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 216fe57b42Smillert * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 226fe57b42Smillert * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 236fe57b42Smillert * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 246fe57b42Smillert * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 256fe57b42Smillert * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 266fe57b42Smillert * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 276fe57b42Smillert * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 286fe57b42Smillert */ 296fe57b42Smillert 306fe57b42Smillert #ifndef lint 31*617e6e4aSmillert static char rcsid[] = "$OpenBSD: editor.c,v 1.43 1998/08/06 18:07:40 millert Exp $"; 326fe57b42Smillert #endif /* not lint */ 336fe57b42Smillert 346fe57b42Smillert #include <sys/types.h> 356fe57b42Smillert #include <sys/param.h> 366fe57b42Smillert #define DKTYPENAMES 376fe57b42Smillert #include <sys/disklabel.h> 386fe57b42Smillert 396fe57b42Smillert #include <ufs/ffs/fs.h> 406fe57b42Smillert 416fe57b42Smillert #include <ctype.h> 426fe57b42Smillert #include <err.h> 436fe57b42Smillert #include <errno.h> 446fe57b42Smillert #include <string.h> 45803ff7d5Smillert #include <libgen.h> 466fe57b42Smillert #include <stdio.h> 476fe57b42Smillert #include <stdlib.h> 486fe57b42Smillert #include <unistd.h> 496fe57b42Smillert 504793b14cSmillert #include "pathnames.h" 514793b14cSmillert 526fe57b42Smillert /* flags for getuint() */ 536fe57b42Smillert #define DO_CONVERSIONS 0x00000001 546fe57b42Smillert #define DO_ROUNDING 0x00000002 556fe57b42Smillert 56f98aebd4Smillert #ifndef NUMBOOT 57f98aebd4Smillert #define NUMBOOT 0 58f98aebd4Smillert #endif 59f98aebd4Smillert 6096a888c6Smillert /* structure to describe a portion of a disk */ 6196a888c6Smillert struct diskchunk { 6296a888c6Smillert u_int32_t start; 6396a888c6Smillert u_int32_t stop; 6496a888c6Smillert }; 6596a888c6Smillert 666fe57b42Smillert void edit_parms __P((struct disklabel *, u_int32_t *)); 67803ff7d5Smillert int editor __P((struct disklabel *, int, char *)); 686fe57b42Smillert void editor_add __P((struct disklabel *, u_int32_t *, char *)); 696fe57b42Smillert void editor_change __P((struct disklabel *, u_int32_t *, char *)); 70c0bdc608Smillert void editor_countfree __P((struct disklabel *, u_int32_t *)); 71*617e6e4aSmillert void editor_delete __P((struct disklabel *, u_int32_t *, char *)); 72*617e6e4aSmillert void editor_display __P((struct disklabel *, u_int32_t *, char)); 73*617e6e4aSmillert void editor_help __P((char *)); 74*617e6e4aSmillert void editor_modify __P((struct disklabel *, u_int32_t *, char *)); 756fe57b42Smillert char *getstring __P((struct disklabel *, char *, char *, char *)); 766fe57b42Smillert u_int32_t getuint __P((struct disklabel *, int, char *, char *, u_int32_t, u_int32_t, int)); 776fe57b42Smillert int has_overlap __P((struct disklabel *, u_int32_t *, int)); 786fe57b42Smillert void make_contiguous __P((struct disklabel *)); 7996a888c6Smillert u_int32_t next_offset __P((struct disklabel *, struct partition *)); 806fe57b42Smillert int partition_cmp __P((const void *, const void *)); 81a7e61405Smillert struct partition **sort_partitions __P((struct disklabel *, u_int16_t *)); 82803ff7d5Smillert void getdisktype __P((struct disklabel *, char *, char *)); 8396a888c6Smillert void find_bounds __P((struct disklabel *)); 84e8e8bdb7Sart void set_bounds __P((struct disklabel *, u_int32_t *)); 8596a888c6Smillert struct diskchunk *free_chunks __P((struct disklabel *)); 8696a888c6Smillert 8796a888c6Smillert static u_int32_t starting_sector; 8896a888c6Smillert static u_int32_t ending_sector; 896fe57b42Smillert 906fe57b42Smillert /* from disklabel.c */ 916fe57b42Smillert int checklabel __P((struct disklabel *)); 926fe57b42Smillert void display __P((FILE *, struct disklabel *)); 93af98caf3Sderaadt void display_partition __P((FILE *, struct disklabel *, int, char, int)); 94af98caf3Sderaadt int width_partition __P((struct disklabel *, int)); 95af98caf3Sderaadt 966fe57b42Smillert struct disklabel *readlabel __P((int)); 976fe57b42Smillert struct disklabel *makebootarea __P((char *, struct disklabel *, int)); 986fe57b42Smillert int writelabel __P((int, char *, struct disklabel *)); 996fe57b42Smillert extern char *bootarea, *specname; 10069220492Smillert extern int donothing; 1014793b14cSmillert #ifdef DOSLABEL 1024793b14cSmillert struct dos_partition *dosdp; /* DOS partition, if found */ 1034793b14cSmillert #endif 1046fe57b42Smillert 1056fe57b42Smillert /* 1066fe57b42Smillert * Simple partition editor. Primarily intended for new labels. 1076fe57b42Smillert */ 1086fe57b42Smillert int 109803ff7d5Smillert editor(lp, f, dev) 1106fe57b42Smillert struct disklabel *lp; 1116fe57b42Smillert int f; 112803ff7d5Smillert char *dev; 1136fe57b42Smillert { 1146fe57b42Smillert struct disklabel lastlabel, tmplabel, label = *lp; 11596a888c6Smillert struct partition *pp; 11696a888c6Smillert u_int32_t freesectors; 1176fe57b42Smillert FILE *fp; 1186fe57b42Smillert char buf[BUFSIZ], *cmd, *arg; 1196fe57b42Smillert 12096a888c6Smillert /* Don't allow disk type of "unknown" */ 121803ff7d5Smillert getdisktype(&label, "You need to specify a type for this disk.", dev); 1226fe57b42Smillert 12396a888c6Smillert /* How big is the OpenBSD portion of the disk? */ 12496a888c6Smillert find_bounds(&label); 12596a888c6Smillert 12696a888c6Smillert /* Set freesectors based on bounds and initial label */ 127c0bdc608Smillert editor_countfree(&label, &freesectors); 12896a888c6Smillert 12996a888c6Smillert /* Make sure there is no partition overlap. */ 13096a888c6Smillert if (has_overlap(&label, &freesectors, 1)) 1316fe57b42Smillert errx(1, "can't run when there is partition overlap."); 1326fe57b42Smillert 13396a888c6Smillert /* If we don't have a 'c' partition, create one. */ 13496a888c6Smillert pp = &label.d_partitions[2]; 13596a888c6Smillert if (label.d_npartitions < 3 || pp->p_size == 0) { 13696a888c6Smillert puts("No 'c' partition found, adding one that spans the disk."); 13796a888c6Smillert if (label.d_npartitions < 3) 13896a888c6Smillert label.d_npartitions = 3; 13996a888c6Smillert pp->p_offset = 0; 14096a888c6Smillert pp->p_size = label.d_secperunit; 14196a888c6Smillert pp->p_fstype = FS_UNUSED; 14296a888c6Smillert pp->p_fsize = pp->p_frag = pp->p_cpg = 0; 14396a888c6Smillert } 1440f820bbbSmillert 1456fe57b42Smillert #ifdef CYLCHECK 1466fe57b42Smillert puts("This platform requires that partition offsets/sizes be on cylinder boundaries.\nPartition offsets/sizes will be rounded to the nearest cylinder automatically."); 1476fe57b42Smillert #endif 1486fe57b42Smillert 14955403f76Smillert /* Set d_bbsize and d_sbsize as neccesary */ 15055403f76Smillert if (strcmp(label.d_packname, "fictitious") == 0) { 15155403f76Smillert if (label.d_bbsize == 0) 15255403f76Smillert label.d_bbsize = BBSIZE; 15355403f76Smillert if (label.d_sbsize == 0) 15455403f76Smillert label.d_sbsize = SBSIZE; 15555403f76Smillert } 156f98aebd4Smillert 157440b1d70Smillert /* Interleave must be >= 1 */ 158440b1d70Smillert if (label.d_interleave == 0) 159440b1d70Smillert label.d_interleave = 1; 160440b1d70Smillert 16196a888c6Smillert puts("\nInitial label editor (enter '?' for help at any prompt)"); 1626fe57b42Smillert lastlabel = label; 1636fe57b42Smillert for (;;) { 1646fe57b42Smillert fputs("> ", stdout); 1656fe57b42Smillert fflush(stdout); 1666fe57b42Smillert rewind(stdin); 1676e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1686e0becc5Smillert putchar('\n'); 1696e0becc5Smillert buf[0] = 'q'; 1706e0becc5Smillert buf[1] = '\0'; 1716e0becc5Smillert } 172260513deSmillert if ((cmd = strtok(buf, " \t\r\n")) == NULL) 173260513deSmillert continue; 174260513deSmillert arg = strtok(NULL, " \t\r\n"); 1756fe57b42Smillert 1766fe57b42Smillert switch (*cmd) { 1776fe57b42Smillert 1786fe57b42Smillert case '?': 179ea37abd3Sderaadt case 'h': 180*617e6e4aSmillert editor_help(arg ? arg : ""); 1816fe57b42Smillert break; 1826fe57b42Smillert 1836fe57b42Smillert case 'a': 1846fe57b42Smillert tmplabel = lastlabel; 1856fe57b42Smillert lastlabel = label; 18696a888c6Smillert editor_add(&label, &freesectors, arg); 18796a888c6Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 18896a888c6Smillert lastlabel = tmplabel; 18996a888c6Smillert break; 19096a888c6Smillert 19196a888c6Smillert case 'b': 19296a888c6Smillert tmplabel = lastlabel; 19396a888c6Smillert lastlabel = label; 194e8e8bdb7Sart set_bounds(&label, &freesectors); 1956fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 1966fe57b42Smillert lastlabel = tmplabel; 1976fe57b42Smillert break; 1986fe57b42Smillert 1996fe57b42Smillert case 'c': 2006fe57b42Smillert tmplabel = lastlabel; 2016fe57b42Smillert lastlabel = label; 20296a888c6Smillert editor_change(&label, &freesectors, arg); 2036fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2046fe57b42Smillert lastlabel = tmplabel; 2056fe57b42Smillert break; 2066fe57b42Smillert 2076fe57b42Smillert case 'd': 2086fe57b42Smillert tmplabel = lastlabel; 2096fe57b42Smillert lastlabel = label; 21096a888c6Smillert editor_delete(&label, &freesectors, arg); 2116fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2126fe57b42Smillert lastlabel = tmplabel; 2136fe57b42Smillert break; 2146fe57b42Smillert 2156fe57b42Smillert case 'm': 2166fe57b42Smillert tmplabel = lastlabel; 2176fe57b42Smillert lastlabel = label; 21896a888c6Smillert editor_modify(&label, &freesectors, arg); 2196fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2206fe57b42Smillert lastlabel = tmplabel; 2216fe57b42Smillert break; 2226fe57b42Smillert 2236fe57b42Smillert case 'p': 22496a888c6Smillert editor_display(&label, &freesectors, arg ? *arg : 0); 2256fe57b42Smillert break; 2266fe57b42Smillert 2275d12b01bSderaadt case 'M': 2284793b14cSmillert fp = popen(_PATH_LESS, "w"); 2295d12b01bSderaadt if (fp) { 2305d12b01bSderaadt extern char manpage[]; 2315d12b01bSderaadt 2325d12b01bSderaadt (void) fwrite(manpage, strlen(manpage), 1, fp); 2335d12b01bSderaadt pclose(fp); 2345d12b01bSderaadt } 2355d12b01bSderaadt break; 2365d12b01bSderaadt 2376fe57b42Smillert case 'q': 23869220492Smillert if (donothing) { 23969220492Smillert puts("In no change mode, not writing label."); 24069220492Smillert return(1); 24169220492Smillert } 2426fe57b42Smillert if (memcmp(lp, &label, sizeof(label)) == 0) { 2436fe57b42Smillert puts("No changes."); 2446fe57b42Smillert return(1); 2456fe57b42Smillert } 2466fe57b42Smillert do { 2476fe57b42Smillert arg = getstring(lp, "Save changes?", 2486fe57b42Smillert "Save changes you have made to the label?", 2496fe57b42Smillert "n"); 25096a888c6Smillert } while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n'); 25196a888c6Smillert if (arg && tolower(*arg) == 'y') { 2526fe57b42Smillert *lp = label; 2536fe57b42Smillert if (writelabel(f, bootarea, lp) == 0) 2546fe57b42Smillert return(0); 2556fe57b42Smillert } 2566fe57b42Smillert return(1); 2576fe57b42Smillert /* NOTREACHED */ 2586fe57b42Smillert break; 2596fe57b42Smillert 260c0bdc608Smillert case 'r': 261c0bdc608Smillert /* Recalculate free space */ 262c0bdc608Smillert editor_countfree(&label, &freesectors); 263c0bdc608Smillert puts("Recalculated free space."); 264c0bdc608Smillert break; 265c0bdc608Smillert 2666fe57b42Smillert case 's': 2676fe57b42Smillert if (arg == NULL) { 268260513deSmillert arg = getstring(lp, "Filename", 2696fe57b42Smillert "Name of the file to save label into.", 2706fe57b42Smillert NULL); 27196a888c6Smillert if (arg == NULL && *arg == '\0') 2726fe57b42Smillert break; 2736fe57b42Smillert } 2746fe57b42Smillert if ((fp = fopen(arg, "w")) == NULL) { 2756fe57b42Smillert warn("cannot open %s", arg); 2766fe57b42Smillert } else { 2776fe57b42Smillert display(fp, &label); 2786fe57b42Smillert (void)fclose(fp); 2796fe57b42Smillert } 2806fe57b42Smillert break; 2816fe57b42Smillert 2826fe57b42Smillert case 'u': 2836fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) { 2846fe57b42Smillert puts("Nothing to undo!"); 2856fe57b42Smillert } else { 2866fe57b42Smillert tmplabel = label; 2876fe57b42Smillert label = lastlabel; 2886fe57b42Smillert lastlabel = tmplabel; 289c0bdc608Smillert /* Recalculate free space */ 290c0bdc608Smillert editor_countfree(&label, &freesectors); 2916fe57b42Smillert puts("Last change undone."); 2926fe57b42Smillert } 2936fe57b42Smillert break; 2946fe57b42Smillert 295040947cfSmillert case 'w': 296040947cfSmillert if (donothing) 297040947cfSmillert puts("In no change mode, not writing label."); 298040947cfSmillert else if (memcmp(lp, &label, sizeof(label)) == 0) 299040947cfSmillert puts("No changes."); 300040947cfSmillert else if (writelabel(f, bootarea, &label) != 0) 301040947cfSmillert warnx("unable to write label"); 3025af08e9cSmillert else 3035af08e9cSmillert *lp = label; 304040947cfSmillert break; 305040947cfSmillert 3066fe57b42Smillert case 'x': 3076fe57b42Smillert return(1); 3086fe57b42Smillert break; 3096fe57b42Smillert 3106fe57b42Smillert case '\n': 3116fe57b42Smillert break; 3126fe57b42Smillert 3136fe57b42Smillert case 'e': 3146fe57b42Smillert tmplabel = lastlabel; 3156fe57b42Smillert lastlabel = label; 31696a888c6Smillert edit_parms(&label, &freesectors); 3176fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 3186fe57b42Smillert lastlabel = tmplabel; 3196fe57b42Smillert break; 3206fe57b42Smillert 3216fe57b42Smillert default: 3226fe57b42Smillert printf("Unknown option: %c ('?' for help)\n", *cmd); 3236fe57b42Smillert break; 3246fe57b42Smillert } 3256fe57b42Smillert } 3266fe57b42Smillert } 3276fe57b42Smillert 3286fe57b42Smillert /* 3296fe57b42Smillert * Add a new partition. 3306fe57b42Smillert */ 3316fe57b42Smillert void 3326fe57b42Smillert editor_add(lp, freep, p) 3336fe57b42Smillert struct disklabel *lp; 3346fe57b42Smillert u_int32_t *freep; 3356fe57b42Smillert char *p; 3366fe57b42Smillert { 33796a888c6Smillert struct partition *pp; 33896a888c6Smillert struct diskchunk *chunks; 3396fe57b42Smillert char buf[BUFSIZ]; 3406fe57b42Smillert int i, partno; 34196a888c6Smillert u_int32_t ui, old_offset, old_size; 3426fe57b42Smillert 3436fe57b42Smillert /* XXX - prompt user to steal space from another partition instead */ 3446fe57b42Smillert if (*freep == 0) { 3456fe57b42Smillert fputs("No space left, you need to shrink a partition\n", 3466fe57b42Smillert stderr); 3476fe57b42Smillert return; 3486fe57b42Smillert } 3496fe57b42Smillert 3506fe57b42Smillert /* XXX - make more like other editor_* */ 3516fe57b42Smillert if (p != NULL) { 3526fe57b42Smillert partno = p[0] - 'a'; 353e6ab932bSmillert if (partno < 0 || partno == 2 || partno >= MAXPARTITIONS) { 3546fe57b42Smillert fprintf(stderr, 355e6ab932bSmillert "Partition must be between 'a' and '%c' " 356e6ab932bSmillert "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1); 3576fe57b42Smillert return; 35896a888c6Smillert } else if (lp->d_partitions[partno].p_fstype != FS_UNUSED && 359f6299b35Sderaadt lp->d_partitions[partno].p_size != 0) { 360f6299b35Sderaadt fprintf(stderr, 361f6299b35Sderaadt "Partition '%c' exists. Delete it first.\n", 362f6299b35Sderaadt p[0]); 363f6299b35Sderaadt return; 3646fe57b42Smillert } 3656fe57b42Smillert } else { 3669c5f1350Smillert /* Find first unused partition that is not 'c' */ 3676fe57b42Smillert for (partno = 0; partno < MAXPARTITIONS; partno++, p++) { 3689c5f1350Smillert if (lp->d_partitions[partno].p_size == 0 && partno != 2) 3696fe57b42Smillert break; 3706fe57b42Smillert } 3716fe57b42Smillert if (partno < MAXPARTITIONS) { 3726fe57b42Smillert buf[0] = partno + 'a'; 3736fe57b42Smillert buf[1] = '\0'; 3746fe57b42Smillert p = &buf[0]; 3756fe57b42Smillert } else 3766fe57b42Smillert p = NULL; 3776fe57b42Smillert for (;;) { 3786fe57b42Smillert p = getstring(lp, "partition", 3796fe57b42Smillert "The letter of the new partition, a - p.", p); 38096a888c6Smillert if (p == NULL) 38196a888c6Smillert return; 3826fe57b42Smillert partno = p[0] - 'a'; 38396a888c6Smillert if (lp->d_partitions[partno].p_fstype != FS_UNUSED && 38496a888c6Smillert lp->d_partitions[partno].p_size != 0) { 38596a888c6Smillert fprintf(stderr, 38696a888c6Smillert "Partition '%c' already exists.\n", p[0]); 38796a888c6Smillert } else if (partno >= 0 && partno < MAXPARTITIONS) 3886fe57b42Smillert break; 3896fe57b42Smillert fprintf(stderr, 3906fe57b42Smillert "Partition must be between 'a' and '%c'.\n", 3916fe57b42Smillert 'a' + MAXPARTITIONS - 1); 3926fe57b42Smillert } 3936fe57b42Smillert } 39496a888c6Smillert 39596a888c6Smillert /* Increase d_npartitions if necesary */ 39696a888c6Smillert if (partno >= lp->d_npartitions) 39796a888c6Smillert lp->d_npartitions = partno + 1; 39896a888c6Smillert 39996a888c6Smillert /* Set defaults */ 4006fe57b42Smillert pp = &lp->d_partitions[partno]; 4016fe57b42Smillert if (partno >= lp->d_npartitions) 4026fe57b42Smillert lp->d_npartitions = partno + 1; 4036fe57b42Smillert memset(pp, 0, sizeof(*pp)); 40496a888c6Smillert pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS; 4056fe57b42Smillert pp->p_fsize = 1024; 4066fe57b42Smillert pp->p_frag = 8; 4076fe57b42Smillert pp->p_cpg = 16; 40896a888c6Smillert pp->p_size = *freep; 40996a888c6Smillert pp->p_offset = next_offset(lp, pp); /* must be computed last */ 410f98aebd4Smillert #if NUMBOOT == 1 411f98aebd4Smillert /* Don't clobber boot blocks */ 412f98aebd4Smillert if (pp->p_offset == 0) { 4138dddfaa0Smillert pp->p_offset = lp->d_secpercyl; 4148dddfaa0Smillert pp->p_size -= lp->d_secpercyl; 415f98aebd4Smillert } 416f98aebd4Smillert #endif 41796a888c6Smillert old_offset = pp->p_offset; 41896a888c6Smillert old_size = pp->p_size; 41996a888c6Smillert 42096a888c6Smillert getoff1: 42196a888c6Smillert /* Get offset */ 42296a888c6Smillert for (;;) { 42396a888c6Smillert ui = getuint(lp, partno, "offset", 42496a888c6Smillert "Starting sector for this partition.", pp->p_offset, 42596a888c6Smillert pp->p_offset, DO_CONVERSIONS | 42696a888c6Smillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 42796a888c6Smillert if (ui == UINT_MAX - 1) { 42896a888c6Smillert fputs("Command aborted\n", stderr); 42996a888c6Smillert pp->p_size = 0; /* effective delete */ 43096a888c6Smillert return; 43196a888c6Smillert } else if (ui == UINT_MAX) 43296a888c6Smillert fputs("Invalid entry\n", stderr); 43396a888c6Smillert else if (ui < starting_sector) 43496a888c6Smillert fprintf(stderr, "The OpenBSD portion of the disk starts" 435f98aebd4Smillert " at sector %u, you tried to add a partition at %u." 436f98aebd4Smillert " You can use the 'b' command to change the size " 437f98aebd4Smillert "of the OpenBSD portion.\n" , starting_sector, ui); 43896a888c6Smillert else if (ui >= ending_sector) 43996a888c6Smillert fprintf(stderr, "The OpenBSD portion of the disk ends " 440f98aebd4Smillert "at sector %u, you tried to add a partition at %u." 441f98aebd4Smillert " You can use the 'b' command to change the size " 442f98aebd4Smillert "of the OpenBSD portion.\n", ending_sector, ui); 44396a888c6Smillert else 44496a888c6Smillert break; 44596a888c6Smillert } 44696a888c6Smillert pp->p_offset = ui; 44796a888c6Smillert 44896a888c6Smillert /* Recompute recommended size based on new offset */ 44996a888c6Smillert ui = pp->p_fstype; 45096a888c6Smillert pp->p_fstype = FS_UNUSED; 45196a888c6Smillert chunks = free_chunks(lp); 45296a888c6Smillert for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 45396a888c6Smillert if (pp->p_offset >= chunks[i].start && 45496a888c6Smillert pp->p_offset < chunks[i].stop) { 45596a888c6Smillert pp->p_size = chunks[i].stop - pp->p_offset; 45696a888c6Smillert break; 45796a888c6Smillert } 45896a888c6Smillert } 45996a888c6Smillert pp->p_fstype = ui; 46096a888c6Smillert 46196a888c6Smillert /* Get size */ 46296a888c6Smillert for (;;) { 46396a888c6Smillert ui = getuint(lp, partno, "size", "Size of the partition.", 46496a888c6Smillert pp->p_size, *freep, DO_CONVERSIONS | 46596a888c6Smillert ((pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_SWAP) ? 46696a888c6Smillert DO_ROUNDING : 0)); 46796a888c6Smillert if (ui == UINT_MAX - 1) { 46896a888c6Smillert fputs("Command aborted\n", stderr); 46996a888c6Smillert pp->p_size = 0; /* effective delete */ 47096a888c6Smillert return; 47196a888c6Smillert } else if (ui == UINT_MAX) 47296a888c6Smillert fputs("Invalid entry\n", stderr); 47396a888c6Smillert else if (ui > *freep) 47496a888c6Smillert /* XXX - prompt user to steal space from another partition */ 47596a888c6Smillert fprintf(stderr,"Sorry, there are only %u sectors left\n", 47696a888c6Smillert *freep); 47796a888c6Smillert else if (pp->p_offset + ui > ending_sector) 47896a888c6Smillert fprintf(stderr, "The OpenBSD portion of the disk ends " 47996a888c6Smillert "at sector %u, you tried to add a partition ending " 480f98aebd4Smillert "at sector %u. You can use the 'b' command to " 481f98aebd4Smillert "change the size of the OpenBSD portion.\n", 48296a888c6Smillert ending_sector, pp->p_offset + ui); 48396a888c6Smillert else 48496a888c6Smillert break; 48596a888c6Smillert } 48696a888c6Smillert pp->p_size = ui; 48796a888c6Smillert if (pp->p_size == 0) 48896a888c6Smillert return; 48996a888c6Smillert 49096a888c6Smillert /* Check for overlap */ 49196a888c6Smillert if (has_overlap(lp, freep, 0)) { 4924793b14cSmillert printf("\nPlease re-enter an offset and size for partition " 4934793b14cSmillert "%c.\n", 'a' + partno); 49496a888c6Smillert pp->p_offset = old_offset; 49596a888c6Smillert pp->p_size = old_size; 49696a888c6Smillert goto getoff1; /* Yeah, I know... */ 49796a888c6Smillert } 4986fe57b42Smillert 4996fe57b42Smillert /* Get fstype */ 5006fe57b42Smillert if (pp->p_fstype < FSMAXTYPES) { 5016fe57b42Smillert p = getstring(lp, "FS type", 5026fe57b42Smillert "Filesystem type (usually 4.2BSD or swap)", 5036fe57b42Smillert fstypenames[pp->p_fstype]); 50496a888c6Smillert if (p == NULL) { 50596a888c6Smillert fputs("Command aborted\n", stderr); 50696a888c6Smillert pp->p_size = 0; /* effective delete */ 50796a888c6Smillert return; 50896a888c6Smillert } 5096fe57b42Smillert for (i = 0; i < FSMAXTYPES; i++) { 5106fe57b42Smillert if (!strcasecmp(p, fstypenames[i])) { 5116fe57b42Smillert pp->p_fstype = i; 5126fe57b42Smillert break; 5136fe57b42Smillert } 5146fe57b42Smillert } 5156fe57b42Smillert if (i >= FSMAXTYPES) { 5166fe57b42Smillert printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p); 5176fe57b42Smillert pp->p_fstype = FS_OTHER; 5186fe57b42Smillert } 5196fe57b42Smillert } else { 5206fe57b42Smillert for (;;) { 5216fe57b42Smillert ui = getuint(lp, partno, "FS type (decimal)", 5226fe57b42Smillert "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", 5236fe57b42Smillert pp->p_fstype, pp->p_fstype, 0); 52496a888c6Smillert if (ui == UINT_MAX - 1) { 52596a888c6Smillert fputs("Command aborted\n", stderr); 52696a888c6Smillert pp->p_size = 0; /* effective delete */ 52796a888c6Smillert return; 52896a888c6Smillert } if (ui == UINT_MAX) 5296fe57b42Smillert fputs("Invalid entry\n", stderr); 5306fe57b42Smillert else 5316fe57b42Smillert break; 5326fe57b42Smillert } 5336fe57b42Smillert pp->p_fstype = ui; 5346fe57b42Smillert } 5356fe57b42Smillert 5366fe57b42Smillert if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) { 5376fe57b42Smillert /* get fsize */ 5386fe57b42Smillert for (;;) { 5396fe57b42Smillert ui = getuint(lp, partno, "fragment size", 5406fe57b42Smillert "Size of fs block fragments. Usually 1024 or 512.", 5416fe57b42Smillert pp->p_fsize, pp->p_fsize, 0); 54296a888c6Smillert if (ui == UINT_MAX - 1) { 54396a888c6Smillert fputs("Command aborted\n", stderr); 54496a888c6Smillert pp->p_size = 0; /* effective delete */ 54596a888c6Smillert return; 54696a888c6Smillert } else if (ui == UINT_MAX) 5476fe57b42Smillert fputs("Invalid entry\n", stderr); 5486fe57b42Smillert else 5496fe57b42Smillert break; 5506fe57b42Smillert } 5516fe57b42Smillert pp->p_fsize = ui; 5526fe57b42Smillert if (pp->p_fsize == 0) 5536fe57b42Smillert puts("Zero fragment size implies zero block size"); 5546fe57b42Smillert 5556fe57b42Smillert /* get bsize */ 5566fe57b42Smillert /* XXX - do before frag size? */ 5576fe57b42Smillert for (; pp->p_fsize > 0;) { 5586fe57b42Smillert ui = getuint(lp, partno, "block size", 5596fe57b42Smillert "Size of filesystem blocks. Usually 8192 or 4096.", 5606fe57b42Smillert pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag, 5616fe57b42Smillert 0); 5626fe57b42Smillert 5636fe57b42Smillert /* sanity checks */ 56496a888c6Smillert if (ui == UINT_MAX - 1) { 56596a888c6Smillert fputs("Command aborted\n", stderr); 56696a888c6Smillert pp->p_size = 0; /* effective delete */ 56796a888c6Smillert return; 56896a888c6Smillert } else if (ui == UINT_MAX) 5696fe57b42Smillert fputs("Invalid entry\n", stderr); 5706fe57b42Smillert else if (ui < getpagesize()) 5716fe57b42Smillert fprintf(stderr, 5726fe57b42Smillert "Error: block size must be at least as big " 5736fe57b42Smillert "as page size (%d).\n", getpagesize()); 5746fe57b42Smillert else if (ui % pp->p_fsize != 0) 5756fe57b42Smillert fputs("Error: block size must be a multiple of the fragment size.\n", stderr); 5766fe57b42Smillert else if (ui / pp->p_fsize < 1) 5776fe57b42Smillert fputs("Error: block size must be at least as big as fragment size.\n", stderr); 5786fe57b42Smillert else 5796fe57b42Smillert break; 5806fe57b42Smillert } 5816fe57b42Smillert pp->p_frag = ui / pp->p_fsize; 5826fe57b42Smillert 5836fe57b42Smillert if (pp->p_fstype == FS_BSDFFS) { 5846fe57b42Smillert /* get cpg */ 5856fe57b42Smillert for (;;) { 5866fe57b42Smillert ui = getuint(lp, partno, "cpg", 5876fe57b42Smillert "Number of filesystem cylinders per group. Usually 16 or 8.", 5886fe57b42Smillert pp->p_cpg, pp->p_cpg, 0); 58996a888c6Smillert if (ui == UINT_MAX - 1) { 59096a888c6Smillert fputs("Command aborted\n", stderr); 59196a888c6Smillert pp->p_size = 0; /* effective delete */ 59296a888c6Smillert return; 59396a888c6Smillert } else if (ui == UINT_MAX) 5946fe57b42Smillert fputs("Invalid entry\n", stderr); 5956fe57b42Smillert else 5966fe57b42Smillert break; 5976fe57b42Smillert } 5986fe57b42Smillert pp->p_cpg = ui; 5996fe57b42Smillert } 6006fe57b42Smillert } 60196a888c6Smillert /* Update free sector count and make sure things stay contiguous. */ 6026fe57b42Smillert *freep -= pp->p_size; 60396a888c6Smillert if (pp->p_size + pp->p_offset > ending_sector || 60496a888c6Smillert has_overlap(lp, freep, -1)) 6056fe57b42Smillert make_contiguous(lp); 6066fe57b42Smillert } 6076fe57b42Smillert 6086fe57b42Smillert /* 6096fe57b42Smillert * Change an existing partition. 6106fe57b42Smillert */ 6116fe57b42Smillert void 6126fe57b42Smillert editor_modify(lp, freep, p) 6136fe57b42Smillert struct disklabel *lp; 6146fe57b42Smillert u_int32_t *freep; 6156fe57b42Smillert char *p; 6166fe57b42Smillert { 6176fe57b42Smillert struct partition origpart, *pp; 6186fe57b42Smillert u_int32_t ui; 6196fe57b42Smillert int partno; 6206fe57b42Smillert 6216fe57b42Smillert /* Change which partition? */ 6226fe57b42Smillert if (p == NULL) { 6236fe57b42Smillert p = getstring(lp, "partition to modify", 6246fe57b42Smillert "The letter of the partition to modify, a - p.", NULL); 6256fe57b42Smillert } 62696a888c6Smillert if (p == NULL) { 62796a888c6Smillert fputs("Command aborted\n", stderr); 62896a888c6Smillert return; 62996a888c6Smillert } 6306fe57b42Smillert partno = p[0] - 'a'; 6316fe57b42Smillert pp = &lp->d_partitions[partno]; 6326fe57b42Smillert origpart = lp->d_partitions[partno]; 6336fe57b42Smillert if (partno < 0 || partno >= lp->d_npartitions) { 6346fe57b42Smillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 6356fe57b42Smillert 'a' + lp->d_npartitions - 1); 6366fe57b42Smillert return; 6376fe57b42Smillert } else if (partno >= lp->d_npartitions || 6386fe57b42Smillert (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) { 6396fe57b42Smillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno); 6406fe57b42Smillert return; 6416fe57b42Smillert } 6426fe57b42Smillert 6436fe57b42Smillert /* Get filesystem type */ 6446fe57b42Smillert if (pp->p_fstype < FSMAXTYPES) { 6456fe57b42Smillert p = getstring(lp, "FS type", 6466fe57b42Smillert "Filesystem type (usually 4.2BSD or swap)", 6476fe57b42Smillert fstypenames[pp->p_fstype]); 64896a888c6Smillert if (p == NULL) { 64996a888c6Smillert fputs("Command aborted\n", stderr); 65096a888c6Smillert pp->p_size = 0; /* effective delete */ 65196a888c6Smillert return; 65296a888c6Smillert } 6536fe57b42Smillert for (ui = 0; ui < FSMAXTYPES; ui++) { 6546fe57b42Smillert if (!strcasecmp(p, fstypenames[ui])) { 6556fe57b42Smillert pp->p_fstype = ui; 6566fe57b42Smillert break; 6576fe57b42Smillert } 6586fe57b42Smillert } 6596fe57b42Smillert if (ui >= FSMAXTYPES) { 6606fe57b42Smillert printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p); 6616fe57b42Smillert pp->p_fstype = FS_OTHER; 6626fe57b42Smillert } 6636fe57b42Smillert } else { 6646fe57b42Smillert for (;;) { 6656fe57b42Smillert ui = getuint(lp, partno, "FS type (decimal)", 6666fe57b42Smillert "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", 6676fe57b42Smillert pp->p_fstype, pp->p_fstype, 0); 66896a888c6Smillert if (ui == UINT_MAX - 1) { 66996a888c6Smillert fputs("Command aborted\n", stderr); 67096a888c6Smillert pp->p_size = 0; /* effective delete */ 67196a888c6Smillert return; 67296a888c6Smillert } else if (ui == UINT_MAX) 6736fe57b42Smillert fputs("Invalid entry\n", stderr); 6746fe57b42Smillert else 6756fe57b42Smillert break; 6766fe57b42Smillert } 6776fe57b42Smillert pp->p_fstype = ui; 6786fe57b42Smillert } 6796fe57b42Smillert 6806fe57b42Smillert /* Did they disable/enable the partition? */ 681229f463eSmillert if ((pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) && 682229f463eSmillert origpart.p_fstype != FS_UNUSED && origpart.p_fstype != FS_BOOT) 6836fe57b42Smillert *freep += origpart.p_size; 684229f463eSmillert else if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT && 685229f463eSmillert (origpart.p_fstype == FS_UNUSED || origpart.p_fstype == FS_BOOT)) { 6866fe57b42Smillert if (pp->p_size > *freep) { 6876fe57b42Smillert fprintf(stderr, 68896a888c6Smillert "Warning, need %u sectors but there are only %u " 6896fe57b42Smillert "free. Setting size to %u.\n", pp->p_size, *freep, 6906fe57b42Smillert *freep); 6916fe57b42Smillert pp->p_fstype = *freep; 6926fe57b42Smillert *freep = 0; 6936fe57b42Smillert } else 6946fe57b42Smillert *freep -= pp->p_size; /* have enough space */ 6956fe57b42Smillert } 6966fe57b42Smillert 6976fe57b42Smillert getoff2: 6986fe57b42Smillert /* Get offset */ 6996fe57b42Smillert for (;;) { 7006fe57b42Smillert ui = getuint(lp, partno, "offset", 7016fe57b42Smillert "Starting sector for this partition.", pp->p_offset, 7026fe57b42Smillert pp->p_offset, DO_CONVERSIONS | 7036fe57b42Smillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 70496a888c6Smillert if (ui == UINT_MAX - 1) { 70596a888c6Smillert fputs("Command aborted\n", stderr); 70696a888c6Smillert *pp = origpart; /* undo changes */ 70796a888c6Smillert return; 70896a888c6Smillert } else if (ui == UINT_MAX) 7096fe57b42Smillert fputs("Invalid entry\n", stderr); 71096a888c6Smillert else if (partno != 2 && ui + ui < starting_sector) { 71196a888c6Smillert fprintf(stderr, "The OpenBSD portion of the disk starts" 712f98aebd4Smillert " at sector %u, you tried to start at %u." 713f98aebd4Smillert " You can use the 'b' command to change the size " 714f98aebd4Smillert "of the OpenBSD portion.\n", starting_sector, ui); 71596a888c6Smillert } else 7166fe57b42Smillert break; 7176fe57b42Smillert } 7186fe57b42Smillert pp->p_offset = ui; 7196fe57b42Smillert 7206fe57b42Smillert /* Get size */ 7216fe57b42Smillert /* XXX - this loop sucks */ 7226fe57b42Smillert for (;;) { 7236fe57b42Smillert ui = getuint(lp, partno, "size", "Size of the partition.", 7246fe57b42Smillert pp->p_size, *freep, 1); 7256fe57b42Smillert 7266fe57b42Smillert if (ui == pp->p_size) 7276fe57b42Smillert break; /* no change */ 7286fe57b42Smillert 72996a888c6Smillert if (ui == UINT_MAX - 1) { 73096a888c6Smillert fputs("Command aborted\n", stderr); 73196a888c6Smillert *pp = origpart; /* undo changes */ 73296a888c6Smillert return; 73396a888c6Smillert } else if (ui == UINT_MAX) { 7346fe57b42Smillert fputs("Invalid entry\n", stderr); 7356fe57b42Smillert continue; 7366fe57b42Smillert } else if (partno == 2 && ui + pp->p_offset > lp->d_secperunit) { 7376fe57b42Smillert fputs("'c' partition may not be larger than the disk\n", 7386fe57b42Smillert stderr); 7396fe57b42Smillert continue; 7406fe57b42Smillert } 7416fe57b42Smillert 742229f463eSmillert if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) { 7436fe57b42Smillert pp->p_size = ui; /* don't care what's free */ 7446fe57b42Smillert break; 7456fe57b42Smillert } else { 7466fe57b42Smillert if (ui > pp->p_size + *freep) 7476fe57b42Smillert /* XXX - prompt user to steal space from another partition */ 7486fe57b42Smillert fprintf(stderr, 74996a888c6Smillert "Size may not be larger than %u sectors\n", 7506fe57b42Smillert pp->p_size + *freep); 7516fe57b42Smillert else { 7526fe57b42Smillert *freep += pp->p_size - ui; 7536fe57b42Smillert pp->p_size = ui; 7546fe57b42Smillert break; 7556fe57b42Smillert } 7566fe57b42Smillert } 7576fe57b42Smillert } 758f98aebd4Smillert /* XXX - if (ui % lp->d_secpercyl == 0) make ui + offset on cyl bound */ 759f98aebd4Smillert pp->p_size = ui; 7606fe57b42Smillert if (pp->p_size == 0) 7616fe57b42Smillert return; 7626fe57b42Smillert 7636fe57b42Smillert /* Check for overlap and restore if not resolved */ 7646fe57b42Smillert if (has_overlap(lp, freep, 0)) { 7656fe57b42Smillert puts("\nPlease re-enter an offset and size"); 7666fe57b42Smillert pp->p_offset = origpart.p_offset; 7676fe57b42Smillert pp->p_size = origpart.p_size; 7686fe57b42Smillert goto getoff2; /* Yeah, I know... */ 7696fe57b42Smillert } 7706fe57b42Smillert 7716fe57b42Smillert if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) { 7726fe57b42Smillert /* get fsize */ 7736fe57b42Smillert for (;;) { 7746fe57b42Smillert ui = getuint(lp, partno, "fragment size", 7756fe57b42Smillert "Size of fs block fragments. Usually 1024 or 512.", 77637bb54cbSmillert pp->p_fsize ? pp->p_fsize : 1024, 1024, 0); 77796a888c6Smillert if (ui == UINT_MAX - 1) { 77896a888c6Smillert fputs("Command aborted\n", stderr); 77996a888c6Smillert *pp = origpart; /* undo changes */ 78096a888c6Smillert return; 78196a888c6Smillert } else if (ui == UINT_MAX) 7826fe57b42Smillert fputs("Invalid entry\n", stderr); 7836fe57b42Smillert else 7846fe57b42Smillert break; 7856fe57b42Smillert } 7866fe57b42Smillert pp->p_fsize = ui; 7876fe57b42Smillert if (pp->p_fsize == 0) 7886fe57b42Smillert puts("Zero fragment size implies zero block size"); 7896fe57b42Smillert 7906fe57b42Smillert /* get bsize */ 7916fe57b42Smillert for (; pp->p_fsize > 0;) { 7926fe57b42Smillert ui = getuint(lp, partno, "block size", 7936fe57b42Smillert "Size of filesystem blocks. Usually 8192 or 4096.", 79437bb54cbSmillert pp->p_frag ? pp->p_fsize * pp->p_frag : 8192, 79537bb54cbSmillert 8192, 0); 7966fe57b42Smillert 7976fe57b42Smillert /* sanity check */ 79896a888c6Smillert if (ui == UINT_MAX - 1) { 79996a888c6Smillert fputs("Command aborted\n", stderr); 80096a888c6Smillert *pp = origpart; /* undo changes */ 80196a888c6Smillert return; 80296a888c6Smillert } else if (ui == UINT_MAX) 8036fe57b42Smillert fputs("Invalid entry\n", stderr); 8046fe57b42Smillert else if (ui % pp->p_fsize != 0) 8056fe57b42Smillert puts("Error: block size must be a multiple of the fragment size."); 8066fe57b42Smillert else if (ui / pp->p_fsize < 1) 8076fe57b42Smillert puts("Error: block size must be at least as big as fragment size."); 8086fe57b42Smillert else { 8096fe57b42Smillert pp->p_frag = ui / pp->p_fsize; 8106fe57b42Smillert break; 8116fe57b42Smillert } 8126fe57b42Smillert } 8136fe57b42Smillert 8146fe57b42Smillert if (pp->p_fstype == FS_BSDFFS) { 8156fe57b42Smillert /* get cpg */ 8166fe57b42Smillert for (;;) { 8176fe57b42Smillert ui = getuint(lp, partno, "cpg", 8186fe57b42Smillert "Number of filesystem cylinders per group." 81937bb54cbSmillert " Usually 16 or 8.", 82037bb54cbSmillert pp->p_cpg ? pp->p_cpg : 16, 16, 0); 82196a888c6Smillert if (ui == UINT_MAX - 1) { 82296a888c6Smillert fputs("Command aborted\n", stderr); 82396a888c6Smillert *pp = origpart; /* undo changes */ 82496a888c6Smillert return; 82596a888c6Smillert } else if (ui == UINT_MAX) 8266fe57b42Smillert fputs("Invalid entry\n", stderr); 8276fe57b42Smillert else 8286fe57b42Smillert break; 8296fe57b42Smillert } 8306fe57b42Smillert pp->p_cpg = ui; 8316fe57b42Smillert } 8326fe57b42Smillert } 8336fe57b42Smillert 8346fe57b42Smillert /* Make sure things stay contiguous. */ 83596a888c6Smillert if (pp->p_size + pp->p_offset > ending_sector || 83696a888c6Smillert has_overlap(lp, freep, -1)) 8376fe57b42Smillert make_contiguous(lp); 8386fe57b42Smillert } 8396fe57b42Smillert 8406fe57b42Smillert /* 8416fe57b42Smillert * Delete an existing partition. 8426fe57b42Smillert */ 8436fe57b42Smillert void 8446fe57b42Smillert editor_delete(lp, freep, p) 8456fe57b42Smillert struct disklabel *lp; 8466fe57b42Smillert u_int32_t *freep; 8476fe57b42Smillert char *p; 8486fe57b42Smillert { 8496fe57b42Smillert int c; 8506fe57b42Smillert 8516fe57b42Smillert if (p == NULL) { 8526fe57b42Smillert p = getstring(lp, "partition to delete", 8536fe57b42Smillert "The letter of the partition to delete, a - p.", NULL); 8546fe57b42Smillert } 85596a888c6Smillert if (p == NULL) { 85696a888c6Smillert fputs("Command aborted\n", stderr); 85796a888c6Smillert return; 85896a888c6Smillert } 8596fe57b42Smillert c = p[0] - 'a'; 8606fe57b42Smillert if (c < 0 || c >= lp->d_npartitions) 8616fe57b42Smillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 8626fe57b42Smillert 'a' + lp->d_npartitions - 1); 8636fe57b42Smillert else if (c >= lp->d_npartitions || (lp->d_partitions[c].p_fstype == 8646fe57b42Smillert FS_UNUSED && lp->d_partitions[c].p_size == 0)) 8656fe57b42Smillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + c); 8666fe57b42Smillert else if (c == 2) 867*617e6e4aSmillert fputs( 868*617e6e4aSmillert "You may not delete the 'c' partition. The 'c' partition must exist and\n" 869*617e6e4aSmillert "should span the entire disk. By default it is of type 'unused' and so\n" 870*617e6e4aSmillert "does not take up any space.\n", stderr); 87196a888c6Smillert else if (lp->d_partitions[c].p_offset >= ending_sector || 87296a888c6Smillert lp->d_partitions[c].p_offset < starting_sector) 87396a888c6Smillert fprintf(stderr, "The OpenBSD portion of the disk ends at sector" 87496a888c6Smillert " %u.\nYou can't remove a partition outside the OpenBSD " 875f98aebd4Smillert "part of the disk. You can use the 'b' command to change " 876f98aebd4Smillert "the size of the OpenBSD portion.\n", ending_sector); 8776fe57b42Smillert else { 87896a888c6Smillert /* Update free sector count. */ 8796fe57b42Smillert if (lp->d_partitions[c].p_fstype != FS_UNUSED && 880229f463eSmillert lp->d_partitions[c].p_fstype != FS_BOOT && 8816fe57b42Smillert lp->d_partitions[c].p_size != 0) 8826fe57b42Smillert *freep += lp->d_partitions[c].p_size; 8836fe57b42Smillert 8846fe57b42Smillert /* Really delete it (as opposed to just setting to "unused") */ 8856fe57b42Smillert (void)memset(&lp->d_partitions[c], 0, 8866fe57b42Smillert sizeof(lp->d_partitions[c])); 8876fe57b42Smillert } 8886fe57b42Smillert } 8896fe57b42Smillert 8906fe57b42Smillert /* 8916fe57b42Smillert * Simplified display() for use with the builtin editor. 8926fe57b42Smillert */ 8936fe57b42Smillert void 8946fe57b42Smillert editor_display(lp, freep, unit) 8956fe57b42Smillert struct disklabel *lp; 8966fe57b42Smillert u_int32_t *freep; 8976fe57b42Smillert char unit; 8986fe57b42Smillert { 8996fe57b42Smillert int i; 900af98caf3Sderaadt int width; 9016fe57b42Smillert 9026fe57b42Smillert printf("device: %s\n", specname); 9030f820bbbSmillert printf("type: %s\n", dktypenames[lp->d_type]); 9046fe57b42Smillert printf("disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename); 9056fe57b42Smillert printf("label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname); 9066fe57b42Smillert printf("bytes/sector: %ld\n", (long)lp->d_secsize); 9076fe57b42Smillert printf("sectors/track: %ld\n", (long)lp->d_nsectors); 9086fe57b42Smillert printf("tracks/cylinder: %ld\n", (long)lp->d_ntracks); 9096fe57b42Smillert printf("sectors/cylinder: %ld\n", (long)lp->d_secpercyl); 9106fe57b42Smillert printf("cylinders: %ld\n", (long)lp->d_ncylinders); 9116fe57b42Smillert printf("total sectors: %ld\n", (long)lp->d_secperunit); 9126fe57b42Smillert printf("free sectors: %u\n", *freep); 9136fe57b42Smillert printf("rpm: %ld\n", (long)lp->d_rpm); 9146fe57b42Smillert printf("\n%d partitions:\n", lp->d_npartitions); 915af98caf3Sderaadt width = width_partition(lp, unit); 916af98caf3Sderaadt printf("# %*.*s %*.*s fstype [fsize bsize cpg]\n", 917af98caf3Sderaadt width, width, "size", width, width, "offset"); 9186fe57b42Smillert for (i = 0; i < lp->d_npartitions; i++) 919af98caf3Sderaadt display_partition(stdout, lp, i, unit, width); 9206fe57b42Smillert } 9216fe57b42Smillert 9226fe57b42Smillert /* 9236fe57b42Smillert * Find the next reasonable starting offset and returns it. 92496a888c6Smillert * Assumes there is a least one free sector left (returns 0 if not). 9256fe57b42Smillert */ 9266fe57b42Smillert u_int32_t 92796a888c6Smillert next_offset(lp, pp) 9286fe57b42Smillert struct disklabel *lp; 92996a888c6Smillert struct partition *pp; 9306fe57b42Smillert { 931f0b4d0a9Smillert struct partition **spp; 93296a888c6Smillert struct diskchunk *chunks; 933f0b4d0a9Smillert u_int16_t npartitions; 93496a888c6Smillert u_int32_t new_offset, new_size; 93596a888c6Smillert int i, good_offset; 9366fe57b42Smillert 937a7e61405Smillert /* Get a sorted list of the partitions */ 93896a888c6Smillert if ((spp = sort_partitions(lp, &npartitions)) == NULL) 93996a888c6Smillert return(0); 940f0b4d0a9Smillert 94196a888c6Smillert new_offset = starting_sector; 942f0b4d0a9Smillert for (i = 0; i < npartitions; i++ ) { 94396a888c6Smillert /* Skip the partition for which we are finding an offset */ 94496a888c6Smillert if (pp == spp[i]) 94596a888c6Smillert continue; 94696a888c6Smillert 9476fe57b42Smillert /* 9486fe57b42Smillert * Is new_offset inside this partition? If so, 94996a888c6Smillert * make it the next sector after the partition ends. 9506fe57b42Smillert */ 9514793b14cSmillert if (spp[i]->p_offset + spp[i]->p_size < ending_sector && 9524793b14cSmillert ((new_offset >= spp[i]->p_offset && 95396a888c6Smillert new_offset < spp[i]->p_offset + spp[i]->p_size) || 95496a888c6Smillert (new_offset + pp->p_size >= spp[i]->p_offset && new_offset 9554793b14cSmillert + pp->p_size <= spp[i]->p_offset + spp[i]->p_size))) 956f0b4d0a9Smillert new_offset = spp[i]->p_offset + spp[i]->p_size; 9576fe57b42Smillert } 9586fe57b42Smillert 95996a888c6Smillert /* Did we find a suitable offset? */ 96096a888c6Smillert for (good_offset = 1, i = 0; i < npartitions; i++ ) { 96196a888c6Smillert if (new_offset + pp->p_size >= spp[i]->p_offset && 96296a888c6Smillert new_offset + pp->p_size <= spp[i]->p_offset + spp[i]->p_size) { 96396a888c6Smillert /* Nope */ 96496a888c6Smillert good_offset = 0; 96596a888c6Smillert break; 96696a888c6Smillert } 96796a888c6Smillert } 96896a888c6Smillert 96996a888c6Smillert /* Specified size is too big, find something that fits */ 97096a888c6Smillert if (!good_offset) { 97196a888c6Smillert chunks = free_chunks(lp); 97296a888c6Smillert new_size = 0; 97396a888c6Smillert for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 97496a888c6Smillert if (chunks[i].stop - chunks[i].start > new_size) { 97596a888c6Smillert new_size = chunks[i].stop - chunks[i].start; 97696a888c6Smillert new_offset = chunks[i].start; 97796a888c6Smillert } 97896a888c6Smillert } 9794793b14cSmillert /* XXX - should do something intelligent if new_size == 0 */ 98096a888c6Smillert pp->p_size = new_size; 98196a888c6Smillert } 98296a888c6Smillert 983f0b4d0a9Smillert (void)free(spp); 9846fe57b42Smillert return(new_offset); 9856fe57b42Smillert } 9866fe57b42Smillert 9876fe57b42Smillert /* 9886fe57b42Smillert * Change the size of an existing partition. 9896fe57b42Smillert */ 9906fe57b42Smillert void 9916fe57b42Smillert editor_change(lp, freep, p) 9926fe57b42Smillert struct disklabel *lp; 9936fe57b42Smillert u_int32_t *freep; 9946fe57b42Smillert char *p; 9956fe57b42Smillert { 9966fe57b42Smillert int partno; 9976fe57b42Smillert u_int32_t newsize; 9986fe57b42Smillert 9996fe57b42Smillert if (p == NULL) { 10006fe57b42Smillert p = getstring(lp, "partition to change size", 10016fe57b42Smillert "The letter of the partition to change size, a - p.", NULL); 10026fe57b42Smillert } 100396a888c6Smillert if (p == NULL) { 100496a888c6Smillert fputs("Command aborted\n", stderr); 100596a888c6Smillert return; 100696a888c6Smillert } 10076fe57b42Smillert partno = p[0] - 'a'; 10086fe57b42Smillert if (partno < 0 || partno >= lp->d_npartitions) { 10096fe57b42Smillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 10106fe57b42Smillert 'a' + lp->d_npartitions - 1); 10116fe57b42Smillert return; 10126fe57b42Smillert } else if (partno >= lp->d_npartitions || 1013229f463eSmillert lp->d_partitions[partno].p_size == 0) { 10146fe57b42Smillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno); 10156fe57b42Smillert return; 10166fe57b42Smillert } 10176fe57b42Smillert 10186fe57b42Smillert printf("Partition %c is currently %u sectors in size (%u free).\n", 10196fe57b42Smillert partno + 'a', lp->d_partitions[partno].p_size, *freep); 1020229f463eSmillert /* XXX - make maxsize lp->d_secperunit if FS_UNUSED/FS_BOOT? */ 10216fe57b42Smillert newsize = getuint(lp, partno, "new size", "Size of the partition. " 10226fe57b42Smillert "You may also say +/- amount for a relative change.", 10236fe57b42Smillert lp->d_partitions[partno].p_size, 10246fe57b42Smillert lp->d_partitions[partno].p_size + *freep, DO_CONVERSIONS | 10256fe57b42Smillert (lp->d_partitions[partno].p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 102696a888c6Smillert if (newsize == UINT_MAX - 1) { 102796a888c6Smillert fputs("Command aborted\n", stderr); 102896a888c6Smillert return; 102996a888c6Smillert } else if (newsize == UINT_MAX) { 10306fe57b42Smillert fputs("Invalid entry\n", stderr); 10316fe57b42Smillert return; 10326fe57b42Smillert } else if (newsize == lp->d_partitions[partno].p_size) 10336fe57b42Smillert return; 10346fe57b42Smillert 1035229f463eSmillert if (lp->d_partitions[partno].p_fstype != FS_UNUSED && 1036229f463eSmillert lp->d_partitions[partno].p_fstype != FS_BOOT) { 10376fe57b42Smillert if (newsize > lp->d_partitions[partno].p_size) { 10386fe57b42Smillert if (newsize - lp->d_partitions[partno].p_size > *freep) { 10396fe57b42Smillert fprintf(stderr, 10406fe57b42Smillert "Only %u sectors free, you asked for %u\n", 10416fe57b42Smillert *freep, 10426fe57b42Smillert newsize - lp->d_partitions[partno].p_size); 10436fe57b42Smillert return; 10446fe57b42Smillert } 10456fe57b42Smillert *freep -= newsize - lp->d_partitions[partno].p_size; 10466fe57b42Smillert } else if (newsize < lp->d_partitions[partno].p_size) { 10476fe57b42Smillert *freep += lp->d_partitions[partno].p_size - newsize; 10486fe57b42Smillert } 10496fe57b42Smillert } else { 105096a888c6Smillert if (partno == 2 && newsize + 10516fe57b42Smillert lp->d_partitions[partno].p_offset > lp->d_secperunit) { 10526fe57b42Smillert fputs("'c' partition may not be larger than the disk\n", 10536fe57b42Smillert stderr); 10546fe57b42Smillert return; 10556fe57b42Smillert } 10566fe57b42Smillert } 10576fe57b42Smillert lp->d_partitions[partno].p_size = newsize; 105896a888c6Smillert if (newsize + lp->d_partitions[partno].p_offset > ending_sector || 105996a888c6Smillert has_overlap(lp, freep, -1)) 10606fe57b42Smillert make_contiguous(lp); 10616fe57b42Smillert } 10626fe57b42Smillert 10636fe57b42Smillert void 10646fe57b42Smillert make_contiguous(lp) 10656fe57b42Smillert struct disklabel *lp; 10666fe57b42Smillert { 10676fe57b42Smillert struct partition **spp; 10686fe57b42Smillert u_int16_t npartitions; 10696fe57b42Smillert int i; 10706fe57b42Smillert 1071a7e61405Smillert /* Get a sorted list of the partitions */ 107296a888c6Smillert if ((spp = sort_partitions(lp, &npartitions)) == NULL) 107396a888c6Smillert return; 10746fe57b42Smillert 10756fe57b42Smillert /* 1076a7e61405Smillert * Make everything contiguous but don't muck with start of the first one 107796a888c6Smillert * or partitions not in the BSD part of the label. 10786fe57b42Smillert */ 107996a888c6Smillert for (i = 1; i < npartitions; i++) { 108096a888c6Smillert if (spp[i]->p_offset >= starting_sector || 108196a888c6Smillert spp[i]->p_offset < ending_sector) 108296a888c6Smillert spp[i]->p_offset = 108396a888c6Smillert spp[i - 1]->p_offset + spp[i - 1]->p_size; 108496a888c6Smillert } 1085f0b4d0a9Smillert 1086f0b4d0a9Smillert (void)free(spp); 10876fe57b42Smillert } 10886fe57b42Smillert 10896fe57b42Smillert /* 10906fe57b42Smillert * Sort the partitions based on starting offset. 10916fe57b42Smillert * This assumes there can be no overlap. 10926fe57b42Smillert */ 10936fe57b42Smillert int 10946fe57b42Smillert partition_cmp(e1, e2) 10956fe57b42Smillert const void *e1, *e2; 10966fe57b42Smillert { 10976fe57b42Smillert struct partition *p1 = *(struct partition **)e1; 10986fe57b42Smillert struct partition *p2 = *(struct partition **)e2; 10996fe57b42Smillert 11006fe57b42Smillert return((int)(p1->p_offset - p2->p_offset)); 11016fe57b42Smillert } 11026fe57b42Smillert 11036fe57b42Smillert char * 11046fe57b42Smillert getstring(lp, prompt, helpstring, oval) 11056fe57b42Smillert struct disklabel *lp; 11066fe57b42Smillert char *prompt; 11076fe57b42Smillert char *helpstring; 11086fe57b42Smillert char *oval; 11096fe57b42Smillert { 11106fe57b42Smillert static char buf[BUFSIZ]; 11116fe57b42Smillert int n; 11126fe57b42Smillert 11136fe57b42Smillert buf[0] = '\0'; 11146fe57b42Smillert do { 11156fe57b42Smillert printf("%s: [%s] ", prompt, oval ? oval : ""); 11166fe57b42Smillert fflush(stdout); 11176fe57b42Smillert rewind(stdin); 11186e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1119260513deSmillert buf[0] = '\0'; 112096a888c6Smillert if (feof(stdin)) { 112196a888c6Smillert putchar('\n'); 112296a888c6Smillert return(NULL); 112396a888c6Smillert } 11246e0becc5Smillert } 11256fe57b42Smillert n = strlen(buf); 11266fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 11276fe57b42Smillert buf[--n] = '\0'; 11286fe57b42Smillert if (buf[0] == '?') 11296fe57b42Smillert puts(helpstring); 11306fe57b42Smillert else if (oval != NULL && buf[0] == '\0') { 11316fe57b42Smillert (void)strncpy(buf, oval, sizeof(buf) - 1); 11326fe57b42Smillert buf[sizeof(buf) - 1] = '\0'; 11336fe57b42Smillert } 11346fe57b42Smillert } while (buf[0] == '?'); 11356fe57b42Smillert 11366fe57b42Smillert return(&buf[0]); 11376fe57b42Smillert } 11386fe57b42Smillert 11396fe57b42Smillert /* 11406fe57b42Smillert * Returns UINT_MAX on error 11416fe57b42Smillert * XXX - there are way too many parameters here. Use inline helper functions 11426fe57b42Smillert */ 11436fe57b42Smillert u_int32_t 11446fe57b42Smillert getuint(lp, partno, prompt, helpstring, oval, maxval, flags) 11456fe57b42Smillert struct disklabel *lp; 11466fe57b42Smillert int partno; 11476fe57b42Smillert char *prompt; 11486fe57b42Smillert char *helpstring; 11496fe57b42Smillert u_int32_t oval; 11506fe57b42Smillert u_int32_t maxval; /* XXX - used inconsistently */ 11516fe57b42Smillert int flags; 11526fe57b42Smillert { 11536fe57b42Smillert char buf[BUFSIZ], *endptr, *p, operator = '\0'; 11546fe57b42Smillert u_int32_t rval = oval; 11556fe57b42Smillert size_t n; 11566fe57b42Smillert int mult = 1; 115796a888c6Smillert double d; 11586fe57b42Smillert 11596fe57b42Smillert buf[0] = '\0'; 11606fe57b42Smillert do { 11616fe57b42Smillert printf("%s: [%u] ", prompt, oval); 11626fe57b42Smillert fflush(stdout); 11636fe57b42Smillert rewind(stdin); 11646e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 11656e0becc5Smillert buf[0] = '\0'; 116696a888c6Smillert if (feof(stdin)) { 116796a888c6Smillert putchar('\n'); 116896a888c6Smillert return(UINT_MAX - 1); 116996a888c6Smillert } 11706e0becc5Smillert } 11716fe57b42Smillert n = strlen(buf); 11726fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 11736fe57b42Smillert buf[--n] = '\0'; 11746fe57b42Smillert if (buf[0] == '?') 11756fe57b42Smillert puts(helpstring); 11766fe57b42Smillert } while (buf[0] == '?'); 11776fe57b42Smillert 11786fe57b42Smillert if (buf[0] == '*' && buf[1] == '\0') { 11796fe57b42Smillert rval = maxval; 11806fe57b42Smillert } else { 11816fe57b42Smillert /* deal with units */ 11826fe57b42Smillert if (buf[0] != '\0' && n > 0) { 11836fe57b42Smillert if ((flags & DO_CONVERSIONS)) { 118496a888c6Smillert switch (tolower(buf[n-1])) { 11856fe57b42Smillert 11866fe57b42Smillert case 'c': 11876fe57b42Smillert mult = lp->d_secpercyl; 11886fe57b42Smillert buf[--n] = '\0'; 11896fe57b42Smillert break; 11906fe57b42Smillert case 'b': 11916fe57b42Smillert mult = -lp->d_secsize; 11926fe57b42Smillert buf[--n] = '\0'; 11936fe57b42Smillert break; 11946fe57b42Smillert case 'k': 11956fe57b42Smillert mult = 1024 / lp->d_secsize; 11966fe57b42Smillert buf[--n] = '\0'; 11976fe57b42Smillert break; 11986fe57b42Smillert case 'm': 11996fe57b42Smillert mult = 1048576 / lp->d_secsize; 12006fe57b42Smillert buf[--n] = '\0'; 12016fe57b42Smillert break; 12021a51a1eeSmillert case 'g': 12031a51a1eeSmillert mult = 1073741824 / lp->d_secsize; 12041a51a1eeSmillert buf[--n] = '\0'; 12051a51a1eeSmillert break; 12066fe57b42Smillert } 120796a888c6Smillert } 12086fe57b42Smillert 12096fe57b42Smillert /* Did they give us an operator? */ 12106fe57b42Smillert p = &buf[0]; 12116fe57b42Smillert if (*p == '+' || *p == '-') 12126fe57b42Smillert operator = *p++; 12136fe57b42Smillert 12146fe57b42Smillert endptr = p; 121596a888c6Smillert errno = 0; 121696a888c6Smillert d = strtod(p, &endptr); 121796a888c6Smillert if (errno == ERANGE) 121896a888c6Smillert rval = UINT_MAX; /* too big/small */ 121996a888c6Smillert else if (*endptr != '\0') { 12206fe57b42Smillert errno = EINVAL; /* non-numbers in str */ 12216fe57b42Smillert rval = UINT_MAX; 12226fe57b42Smillert } else { 122396a888c6Smillert /* XXX - should check for overflow */ 122496a888c6Smillert if (mult > 0) 122596a888c6Smillert rval = d * mult; 122696a888c6Smillert else 122796a888c6Smillert /* Negative mult means divide (fancy) */ 122896a888c6Smillert rval = d / (-mult); 12296fe57b42Smillert 123096a888c6Smillert /* Apply the operator */ 12316fe57b42Smillert if (operator == '+') 12326fe57b42Smillert rval += oval; 12336fe57b42Smillert else if (operator == '-') 12346fe57b42Smillert rval = oval - rval; 12356fe57b42Smillert } 12366fe57b42Smillert } 12376fe57b42Smillert } 12386fe57b42Smillert if ((flags & DO_ROUNDING) && rval < UINT_MAX) { 12396fe57b42Smillert u_int32_t cyls; 1240260513deSmillert /* XXX - should use maxsize and round down if too big */ 12416fe57b42Smillert #ifdef CYLCHECK 12426fe57b42Smillert /* Always round to nearest cylinder, regardless of units */ 12436fe57b42Smillert cyls = (u_int32_t)((rval / (double)lp->d_secpercyl) + 0.5); 12446fe57b42Smillert if (rval != cyls * lp->d_secpercyl) { 12456fe57b42Smillert rval = cyls * lp->d_secpercyl; 12466fe57b42Smillert printf("Rounding to nearest cylinder: %u\n", rval); 12476fe57b42Smillert } 12486fe57b42Smillert #else 124996a888c6Smillert /* Round to nearest cylinder unless given in sectors */ 125096a888c6Smillert if (mult != 1) { 12516fe57b42Smillert cyls = (u_int32_t)((rval / (double)lp->d_secpercyl) 12526fe57b42Smillert + 0.5); 12536fe57b42Smillert if (rval != cyls * lp->d_secpercyl) { 12546fe57b42Smillert rval = cyls * lp->d_secpercyl; 12556fe57b42Smillert printf("Rounding to nearest cylinder: %u\n", 12566fe57b42Smillert rval); 12576fe57b42Smillert } 12586fe57b42Smillert } 12596fe57b42Smillert #endif 12606fe57b42Smillert } 12616fe57b42Smillert 12626fe57b42Smillert return(rval); 12636fe57b42Smillert } 12646fe57b42Smillert 12656fe57b42Smillert /* 12666fe57b42Smillert * Check for partition overlap in lp and prompt the user 12676fe57b42Smillert * to resolve the overlap if any is found. Returns 1 12686fe57b42Smillert * if unable to resolve, else 0. 12696fe57b42Smillert */ 12706fe57b42Smillert int 12716fe57b42Smillert has_overlap(lp, freep, resolve) 12726fe57b42Smillert struct disklabel *lp; 12736fe57b42Smillert u_int32_t *freep; 12746fe57b42Smillert int resolve; 12756fe57b42Smillert { 12766fe57b42Smillert struct partition **spp; 12776fe57b42Smillert u_int16_t npartitions; 1278e6aa8bafSmillert int c, i, j; 1279e6aa8bafSmillert char buf[BUFSIZ]; 12806fe57b42Smillert 1281a7e61405Smillert /* Get a sorted list of the partitions */ 1282a7e61405Smillert spp = sort_partitions(lp, &npartitions); 12836fe57b42Smillert 1284a7e61405Smillert if (npartitions < 2) { 1285a7e61405Smillert (void)free(spp); 12866fe57b42Smillert return(0); /* nothing to do */ 12876fe57b42Smillert } 12886fe57b42Smillert 12896fe57b42Smillert /* Now that we have things sorted by starting sector check overlap */ 12906fe57b42Smillert for (i = 0; i < npartitions; i++) { 12916fe57b42Smillert for (j = i + 1; j < npartitions; j++) { 12926fe57b42Smillert /* `if last_sec_in_part + 1 > first_sec_in_next_part' */ 12936fe57b42Smillert if (spp[i]->p_offset + spp[i]->p_size > spp[j]->p_offset) { 129496a888c6Smillert /* Don't print, just return */ 129596a888c6Smillert if (resolve == -1) { 129696a888c6Smillert (void)free(spp); 129796a888c6Smillert return(1); 129896a888c6Smillert } 129996a888c6Smillert 13006fe57b42Smillert /* Overlap! Convert to real part numbers. */ 13016fe57b42Smillert i = ((char *)spp[i] - (char *)lp->d_partitions) 13026fe57b42Smillert / sizeof(**spp); 13036fe57b42Smillert j = ((char *)spp[j] - (char *)lp->d_partitions) 13046fe57b42Smillert / sizeof(**spp); 13056fe57b42Smillert printf("\nError, partitions %c and %c overlap:\n", 13066fe57b42Smillert 'a' + i, 'a' + j); 13076fe57b42Smillert puts(" size offset fstype [fsize bsize cpg]"); 1308af98caf3Sderaadt display_partition(stdout, lp, i, 0, 0); 1309af98caf3Sderaadt display_partition(stdout, lp, j, 0, 0); 13106fe57b42Smillert 13116fe57b42Smillert /* Did they ask us to resolve it ourselves? */ 131296a888c6Smillert if (resolve != 1) { 1313f0b4d0a9Smillert (void)free(spp); 13146fe57b42Smillert return(1); 1315f0b4d0a9Smillert } 13166fe57b42Smillert 1317e6aa8bafSmillert /* Get partition to disable or ^D */ 1318e6aa8bafSmillert do { 1319616cd1c4Smillert printf("Disable which one? (^D to abort) [%c %c] ", 13206fe57b42Smillert 'a' + i, 'a' + j); 1321e6aa8bafSmillert buf[0] = '\0'; 1322616cd1c4Smillert if (!fgets(buf, sizeof(buf), stdin)) { 1323616cd1c4Smillert putchar('\n'); 1324e6aa8bafSmillert return(1); /* ^D */ 1325616cd1c4Smillert } 1326e6aa8bafSmillert c = buf[0] - 'a'; 1327e6aa8bafSmillert } while (buf[1] != '\n' && buf[1] != '\0' && 1328e6aa8bafSmillert c != i && c != j); 1329e6aa8bafSmillert 1330e6aa8bafSmillert /* Mark the selected one as unused */ 13316fe57b42Smillert lp->d_partitions[c].p_fstype = FS_UNUSED; 13326fe57b42Smillert *freep += lp->d_partitions[c].p_size; 1333e6aa8bafSmillert (void)free(spp); 1334e6aa8bafSmillert return(has_overlap(lp, freep, resolve)); 13356fe57b42Smillert } 13366fe57b42Smillert } 13376fe57b42Smillert } 1338f0b4d0a9Smillert 1339f0b4d0a9Smillert (void)free(spp); 1340e6aa8bafSmillert return(0); 13416fe57b42Smillert } 13426fe57b42Smillert 13436fe57b42Smillert void 13446fe57b42Smillert edit_parms(lp, freep) 13456fe57b42Smillert struct disklabel *lp; 13466fe57b42Smillert u_int32_t *freep; 13476fe57b42Smillert { 13486fe57b42Smillert char *p; 13496fe57b42Smillert u_int32_t ui; 135096a888c6Smillert struct disklabel oldlabel = *lp; 13516fe57b42Smillert 1352ea37abd3Sderaadt printf("Changing device parameters for %s:\n", specname); 13536fe57b42Smillert 13540f820bbbSmillert /* disk type */ 13550f820bbbSmillert for (;;) { 13560f820bbbSmillert p = getstring(lp, "disk type", 135741282a2aSmillert "What kind of disk is this? Usually SCSI, ESDI, ST506, or " 135841282a2aSmillert "floppy (use ESDI for IDE).", dktypenames[lp->d_type]); 135996a888c6Smillert if (p == NULL) { 136096a888c6Smillert fputs("Command aborted\n", stderr); 136196a888c6Smillert return; 136296a888c6Smillert } 136341282a2aSmillert if (strcasecmp(p, "IDE") == 0) 136441282a2aSmillert ui = DTYPE_ESDI; 136541282a2aSmillert else 136641282a2aSmillert for (ui = 1; ui < DKMAXTYPES && 136741282a2aSmillert strcasecmp(p, dktypenames[ui]); ui++) 13680f820bbbSmillert ; 13690f820bbbSmillert if (ui < DKMAXTYPES) { 13700f820bbbSmillert break; 13710f820bbbSmillert } else { 13720f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", p); 13730f820bbbSmillert fputs("Valid types are: ", stdout); 13740f820bbbSmillert for (ui = 1; ui < DKMAXTYPES; ui++) { 13750f820bbbSmillert printf("\"%s\"", dktypenames[ui]); 13760f820bbbSmillert if (ui < DKMAXTYPES - 1) 13770f820bbbSmillert fputs(", ", stdout); 13780f820bbbSmillert } 13790f820bbbSmillert putchar('\n'); 13800f820bbbSmillert } 13810f820bbbSmillert } 13820f820bbbSmillert lp->d_type = ui; 13830f820bbbSmillert 13846fe57b42Smillert /* pack/label id */ 13856fe57b42Smillert p = getstring(lp, "label name", 13866fe57b42Smillert "15 char string that describes this label, usually the disk name.", 13876fe57b42Smillert lp->d_packname); 138896a888c6Smillert if (p == NULL) { 138996a888c6Smillert fputs("Command aborted\n", stderr); 139096a888c6Smillert *lp = oldlabel; /* undo damage */ 139196a888c6Smillert return; 139296a888c6Smillert } 13936fe57b42Smillert strncpy(lp->d_packname, p, sizeof(lp->d_packname) - 1); 13946fe57b42Smillert lp->d_packname[sizeof(lp->d_packname) - 1] = '\0'; 13956fe57b42Smillert 13966fe57b42Smillert /* sectors/track */ 13976fe57b42Smillert for (;;) { 13986fe57b42Smillert ui = getuint(lp, 0, "sectors/track", 13996fe57b42Smillert "The Numer of sectors per track.", lp->d_nsectors, 14006fe57b42Smillert lp->d_nsectors, 0); 140196a888c6Smillert if (ui == UINT_MAX - 1) { 140296a888c6Smillert fputs("Command aborted\n", stderr); 140396a888c6Smillert *lp = oldlabel; /* undo damage */ 140496a888c6Smillert return; 140596a888c6Smillert } if (ui == UINT_MAX) 14066fe57b42Smillert fputs("Invalid entry\n", stderr); 14076fe57b42Smillert else 14086fe57b42Smillert break; 14096fe57b42Smillert } 14106fe57b42Smillert lp->d_nsectors = ui; 14116fe57b42Smillert 14126fe57b42Smillert /* tracks/cylinder */ 14136fe57b42Smillert for (;;) { 14146fe57b42Smillert ui = getuint(lp, 0, "tracks/cylinder", 14156fe57b42Smillert "The number of tracks per cylinder.", lp->d_ntracks, 14166fe57b42Smillert lp->d_ntracks, 0); 141796a888c6Smillert if (ui == UINT_MAX - 1) { 141896a888c6Smillert fputs("Command aborted\n", stderr); 141996a888c6Smillert *lp = oldlabel; /* undo damage */ 142096a888c6Smillert return; 142196a888c6Smillert } else if (ui == UINT_MAX) 14226fe57b42Smillert fputs("Invalid entry\n", stderr); 14236fe57b42Smillert else 14246fe57b42Smillert break; 14256fe57b42Smillert } 14266fe57b42Smillert lp->d_ntracks = ui; 14276fe57b42Smillert 14286fe57b42Smillert /* sectors/cylinder */ 1429148b6188Smillert for (;;) { 1430148b6188Smillert ui = getuint(lp, 0, "sectors/cylinder", 1431148b6188Smillert "The number of sectors per cylinder (Usually sectors/track " 1432148b6188Smillert "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl, 0); 143396a888c6Smillert if (ui == UINT_MAX - 1) { 143496a888c6Smillert fputs("Command aborted\n", stderr); 143596a888c6Smillert *lp = oldlabel; /* undo damage */ 143696a888c6Smillert return; 143796a888c6Smillert } else if (ui == UINT_MAX) 1438148b6188Smillert fputs("Invalid entry\n", stderr); 1439148b6188Smillert else 1440148b6188Smillert break; 1441148b6188Smillert } 1442148b6188Smillert lp->d_secpercyl = ui; 14436fe57b42Smillert 14446fe57b42Smillert /* number of cylinders */ 14456fe57b42Smillert for (;;) { 14466fe57b42Smillert ui = getuint(lp, 0, "number of cylinders", 14476fe57b42Smillert "The total number of cylinders on the disk.", 14486fe57b42Smillert lp->d_ncylinders, lp->d_ncylinders, 0); 144996a888c6Smillert if (ui == UINT_MAX - 1) { 145096a888c6Smillert fputs("Command aborted\n", stderr); 145196a888c6Smillert *lp = oldlabel; /* undo damage */ 145296a888c6Smillert return; 145396a888c6Smillert } else if (ui == UINT_MAX) 14546fe57b42Smillert fputs("Invalid entry\n", stderr); 14556fe57b42Smillert else 14566fe57b42Smillert break; 14576fe57b42Smillert } 14586fe57b42Smillert lp->d_ncylinders = ui; 14596fe57b42Smillert 14606fe57b42Smillert /* total sectors */ 14616fe57b42Smillert for (;;) { 14626fe57b42Smillert ui = getuint(lp, 0, "total sectors", 14636fe57b42Smillert "The total number of sectors on the disk.", 14646fe57b42Smillert lp->d_secperunit ? lp->d_secperunit : 14656fe57b42Smillert lp->d_ncylinders * lp->d_ncylinders, 14666fe57b42Smillert lp->d_ncylinders * lp->d_ncylinders, 0); 146796a888c6Smillert if (ui == UINT_MAX - 1) { 146896a888c6Smillert fputs("Command aborted\n", stderr); 146996a888c6Smillert *lp = oldlabel; /* undo damage */ 147096a888c6Smillert return; 147196a888c6Smillert } else if (ui == UINT_MAX) 14726fe57b42Smillert fputs("Invalid entry\n", stderr); 147396a888c6Smillert else if (ui > lp->d_secperunit && 147496a888c6Smillert ending_sector == lp->d_secperunit) { 14756fe57b42Smillert /* grow free count */ 14766fe57b42Smillert *freep += ui - lp->d_secperunit; 1477f98aebd4Smillert puts("You may want to increase the size of the 'c' " 1478f98aebd4Smillert "partition."); 14796fe57b42Smillert break; 148096a888c6Smillert } else if (ui < lp->d_secperunit && 148196a888c6Smillert ending_sector == lp->d_secperunit) { 14826fe57b42Smillert /* shrink free count */ 14836fe57b42Smillert if (lp->d_secperunit - ui > *freep) 14846fe57b42Smillert fprintf(stderr, 14856fe57b42Smillert "Not enough free space to shrink by %u " 14866fe57b42Smillert "sectors (only %u sectors left)\n", 14876fe57b42Smillert lp->d_secperunit - ui, *freep); 14886fe57b42Smillert else { 14896fe57b42Smillert *freep -= lp->d_secperunit - ui; 14906fe57b42Smillert break; 14916fe57b42Smillert } 14926fe57b42Smillert } else 14936fe57b42Smillert break; 14946fe57b42Smillert } 149596a888c6Smillert /* Adjust ending_sector if necesary. */ 149696a888c6Smillert if (ending_sector > ui) 149796a888c6Smillert ending_sector = ui; 14986fe57b42Smillert lp->d_secperunit = ui; 14996fe57b42Smillert 15006fe57b42Smillert /* rpm */ 15016fe57b42Smillert for (;;) { 15026fe57b42Smillert ui = getuint(lp, 0, "rpm", 1503a7e61405Smillert "The rotational speed of the disk in revolutions per minute.", 15046fe57b42Smillert lp->d_rpm, lp->d_rpm, 0); 150596a888c6Smillert if (ui == UINT_MAX - 1) { 150696a888c6Smillert fputs("Command aborted\n", stderr); 150796a888c6Smillert *lp = oldlabel; /* undo damage */ 150896a888c6Smillert return; 150996a888c6Smillert } else if (ui == UINT_MAX) 15106fe57b42Smillert fputs("Invalid entry\n", stderr); 15116fe57b42Smillert else 15126fe57b42Smillert break; 15136fe57b42Smillert } 15146fe57b42Smillert lp->d_rpm = ui; 1515440b1d70Smillert 1516440b1d70Smillert /* interleave */ 1517440b1d70Smillert for (;;) { 1518440b1d70Smillert ui = getuint(lp, 0, "interleave", 1519440b1d70Smillert "The physical sector interleave, set when formatting. Almost always 1.", 1520440b1d70Smillert lp->d_interleave, lp->d_interleave, 0); 1521440b1d70Smillert if (ui == UINT_MAX - 1) { 1522440b1d70Smillert fputs("Command aborted\n", stderr); 1523440b1d70Smillert *lp = oldlabel; /* undo damage */ 1524440b1d70Smillert return; 1525440b1d70Smillert } else if (ui == UINT_MAX || ui == 0) 1526440b1d70Smillert fputs("Invalid entry\n", stderr); 1527440b1d70Smillert else 1528440b1d70Smillert break; 1529440b1d70Smillert } 1530440b1d70Smillert lp->d_interleave = ui; 15316fe57b42Smillert } 1532a7e61405Smillert 1533a7e61405Smillert struct partition ** 1534a7e61405Smillert sort_partitions(lp, npart) 1535a7e61405Smillert struct disklabel *lp; 1536a7e61405Smillert u_int16_t *npart; 1537a7e61405Smillert { 1538a7e61405Smillert u_int16_t npartitions; 1539a7e61405Smillert struct partition **spp; 1540a7e61405Smillert int i; 1541a7e61405Smillert 1542a7e61405Smillert /* How many "real" partitions do we have? */ 1543a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1544a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1545a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 1546a7e61405Smillert lp->d_partitions[i].p_size != 0) 1547a7e61405Smillert npartitions++; 1548a7e61405Smillert } 154996a888c6Smillert if (npartitions == 0) { 155096a888c6Smillert *npart = 0; 155196a888c6Smillert return(NULL); 155296a888c6Smillert } 1553a7e61405Smillert 1554a7e61405Smillert /* Create an array of pointers to the partition data */ 1555a7e61405Smillert if ((spp = malloc(sizeof(struct partition *) * npartitions)) == NULL) 1556a7e61405Smillert errx(4, "out of memory"); 1557a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1558a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1559a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 1560a7e61405Smillert lp->d_partitions[i].p_size != 0) 1561a7e61405Smillert spp[npartitions++] = &lp->d_partitions[i]; 1562a7e61405Smillert } 1563a7e61405Smillert 1564a7e61405Smillert /* 1565a7e61405Smillert * Sort the partitions based on starting offset. 1566a7e61405Smillert * This is safe because we guarantee no overlap. 1567a7e61405Smillert */ 1568a7e61405Smillert if (npartitions > 1) 1569a7e61405Smillert if (heapsort((void *)spp, npartitions, sizeof(spp[0]), 1570a7e61405Smillert partition_cmp)) 1571a7e61405Smillert err(4, "failed to sort partition table"); 1572a7e61405Smillert 1573a7e61405Smillert *npart = npartitions; 1574a7e61405Smillert return(spp); 1575a7e61405Smillert } 15760f820bbbSmillert 15770f820bbbSmillert /* 15780f820bbbSmillert * Get a valid disk type if necessary. 15790f820bbbSmillert */ 15800f820bbbSmillert void 1581803ff7d5Smillert getdisktype(lp, banner, dev) 15820f820bbbSmillert struct disklabel *lp; 15830f820bbbSmillert char *banner; 1584803ff7d5Smillert char *dev; 15850f820bbbSmillert { 15860f820bbbSmillert int i; 1587803ff7d5Smillert char *s, *def = "SCSI"; 1588803ff7d5Smillert struct dtypes { 1589803ff7d5Smillert char *dev; 1590803ff7d5Smillert char *type; 1591803ff7d5Smillert } dtypes[] = { 1592803ff7d5Smillert "sd", "SCSI", 1593803ff7d5Smillert "wd", "IDE", 1594803ff7d5Smillert "fd", "FLOPPY", 1595803ff7d5Smillert "xd", "SMD", 1596803ff7d5Smillert "xy", "SMD", 1597803ff7d5Smillert "hd", "HP-IB", 1598803ff7d5Smillert "ccd", "CCD", 1599803ff7d5Smillert "vnd", "VND", 1600803ff7d5Smillert "svnd", "VND", 1601803ff7d5Smillert NULL, NULL 1602803ff7d5Smillert }; 1603803ff7d5Smillert 1604803ff7d5Smillert if ((s = basename(dev)) != NULL) { 1605803ff7d5Smillert if (*s == 'r') 1606803ff7d5Smillert s++; 1607803ff7d5Smillert i = strcspn(s, "0123456789"); 1608803ff7d5Smillert s[i] = '\0'; 1609803ff7d5Smillert dev = s; 1610803ff7d5Smillert for (i = 0; dtypes[i].dev != NULL; i++) { 1611803ff7d5Smillert if (strcmp(dev, dtypes[i].dev) == 0) { 1612803ff7d5Smillert def = dtypes[i].type; 1613803ff7d5Smillert break; 1614803ff7d5Smillert } 1615803ff7d5Smillert } 1616803ff7d5Smillert } 16170f820bbbSmillert 16180f820bbbSmillert if (lp->d_type > DKMAXTYPES || lp->d_type == 0) { 16190f820bbbSmillert puts(banner); 16200f820bbbSmillert puts("Possible values are:"); 1621eb5dd924Sderaadt printf("\"IDE\", "); 16220f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 16230f820bbbSmillert printf("\"%s\"", dktypenames[i]); 16240f820bbbSmillert if (i < DKMAXTYPES - 1) 16250f820bbbSmillert fputs(", ", stdout); 16260f820bbbSmillert } 16270f820bbbSmillert putchar('\n'); 16280f820bbbSmillert 16290f820bbbSmillert for (;;) { 16300f820bbbSmillert s = getstring(lp, "Disk type", 1631803ff7d5Smillert "What kind of disk is this? Usually SCSI, IDE, " 1632803ff7d5Smillert "ESDI, CCD, ST506, or floppy.", def); 163396a888c6Smillert if (s == NULL) 163496a888c6Smillert continue; 16355b412421Smillert if (strcasecmp(s, "IDE") == 0) { 16365b412421Smillert lp->d_type = DTYPE_ESDI; 16375b412421Smillert putchar('\n'); 16385b412421Smillert return; 16395b412421Smillert } 16400f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) 16410f820bbbSmillert if (strcasecmp(s, dktypenames[i]) == 0) { 16420f820bbbSmillert lp->d_type = i; 16430f820bbbSmillert putchar('\n'); 16440f820bbbSmillert return; 16450f820bbbSmillert } 16460f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", s); 16470f820bbbSmillert fputs("Valid types are: ", stdout); 16480f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 16490f820bbbSmillert printf("\"%s\"", dktypenames[i]); 16500f820bbbSmillert if (i < DKMAXTYPES - 1) 16510f820bbbSmillert fputs(", ", stdout); 16520f820bbbSmillert } 16530f820bbbSmillert putchar('\n'); 16540f820bbbSmillert } 16550f820bbbSmillert } 16560f820bbbSmillert } 165796a888c6Smillert 165896a888c6Smillert /* 165996a888c6Smillert * Get beginning and ending sectors of the OpenBSD portion of the disk 166096a888c6Smillert * from the user. 16614793b14cSmillert * XXX - should mention MBR values if DOSLABEL 166296a888c6Smillert */ 166396a888c6Smillert void 1664e8e8bdb7Sart set_bounds(lp, freep) 166596a888c6Smillert struct disklabel *lp; 1666e8e8bdb7Sart u_int32_t *freep; 166796a888c6Smillert { 166896a888c6Smillert u_int32_t ui, start_temp; 166996a888c6Smillert 167096a888c6Smillert /* Starting sector */ 167196a888c6Smillert do { 167296a888c6Smillert ui = getuint(lp, 0, "Starting sector", 167396a888c6Smillert "The start of the OpenBSD portion of the disk.", 167496a888c6Smillert starting_sector, lp->d_secperunit, 0); 167596a888c6Smillert if (ui == UINT_MAX - 1) { 167696a888c6Smillert fputs("Command aborted\n", stderr); 167796a888c6Smillert return; 167896a888c6Smillert } 167996a888c6Smillert } while (ui >= lp->d_secperunit); 168096a888c6Smillert start_temp = ui; 168196a888c6Smillert 16824793b14cSmillert /* Size */ 168396a888c6Smillert do { 1684f98aebd4Smillert ui = getuint(lp, 0, "Size ('*' for entire disk)", 1685f98aebd4Smillert "The size of the OpenBSD portion of the disk ('*' for the " 1686f98aebd4Smillert "entire disk).", ending_sector - starting_sector, 1687f98aebd4Smillert lp->d_secperunit - start_temp, 0); 168896a888c6Smillert if (ui == UINT_MAX - 1) { 168996a888c6Smillert fputs("Command aborted\n", stderr); 169096a888c6Smillert return; 169196a888c6Smillert } 1692f98aebd4Smillert } while (ui > lp->d_secperunit - start_temp); 16934793b14cSmillert ending_sector = start_temp + ui; 169496a888c6Smillert starting_sector = start_temp; 1695e8e8bdb7Sart 1696e8e8bdb7Sart /* Recalculate the free sectors */ 1697c0bdc608Smillert editor_countfree(lp, freep); 169896a888c6Smillert } 169996a888c6Smillert 170096a888c6Smillert /* 170196a888c6Smillert * Return a list of the "chunks" of free space available 170296a888c6Smillert */ 170396a888c6Smillert struct diskchunk * 170496a888c6Smillert free_chunks(lp) 170596a888c6Smillert struct disklabel *lp; 170696a888c6Smillert { 170796a888c6Smillert u_int16_t npartitions; 170896a888c6Smillert struct partition **spp; 170996a888c6Smillert static struct diskchunk chunks[MAXPARTITIONS + 2]; 171096a888c6Smillert int i, numchunks; 171196a888c6Smillert 171296a888c6Smillert /* Sort the partitions based on offset */ 171396a888c6Smillert spp = sort_partitions(lp, &npartitions); 171496a888c6Smillert 171596a888c6Smillert /* If there are no partitions, it's all free. */ 171696a888c6Smillert if (spp == NULL) { 171796a888c6Smillert chunks[0].start = 0; 171896a888c6Smillert chunks[0].stop = ending_sector; 171996a888c6Smillert chunks[1].start = chunks[1].stop = 0; 172096a888c6Smillert return(chunks); 172196a888c6Smillert } 172296a888c6Smillert 172396a888c6Smillert /* Find chunks of free space */ 172496a888c6Smillert numchunks = 0; 172596a888c6Smillert if (spp && spp[0]->p_offset > 0) { 172696a888c6Smillert chunks[0].start = 0; 172796a888c6Smillert chunks[0].stop = spp[0]->p_offset; 172896a888c6Smillert numchunks++; 172996a888c6Smillert } 173096a888c6Smillert for (i = 0; i < npartitions; i++) { 173196a888c6Smillert if (i + 1 < npartitions) { 173296a888c6Smillert if (spp[i]->p_offset + spp[i]->p_size < spp[i+1]->p_offset) { 173396a888c6Smillert chunks[numchunks].start = 173496a888c6Smillert spp[i]->p_offset + spp[i]->p_size; 173596a888c6Smillert chunks[numchunks].stop = spp[i+1]->p_offset; 173696a888c6Smillert numchunks++; 173796a888c6Smillert } 173896a888c6Smillert } else { 173996a888c6Smillert /* Last partition */ 174065ce672dScsapuntz if (spp[i]->p_offset + spp[i]->p_size < ending_sector) { 174196a888c6Smillert 174296a888c6Smillert chunks[numchunks].start = 174396a888c6Smillert spp[i]->p_offset + spp[i]->p_size; 174465ce672dScsapuntz chunks[numchunks].stop = ending_sector; 174596a888c6Smillert numchunks++; 174696a888c6Smillert } 174796a888c6Smillert } 174896a888c6Smillert } 174996a888c6Smillert 175096a888c6Smillert /* Terminate and return */ 175196a888c6Smillert chunks[numchunks].start = chunks[numchunks].stop = 0; 175296a888c6Smillert (void)free(spp); 175396a888c6Smillert return(chunks); 175496a888c6Smillert } 17554793b14cSmillert 17564793b14cSmillert /* 17574793b14cSmillert * What is the OpenBSD portion of the disk? Uses the MBR if applicable. 17584793b14cSmillert */ 17594793b14cSmillert void 17604793b14cSmillert find_bounds(lp) 17614793b14cSmillert struct disklabel *lp; 17624793b14cSmillert { 1763f98aebd4Smillert struct partition *pp = &lp->d_partitions[2]; 17644793b14cSmillert 17654793b14cSmillert /* Defaults */ 17664793b14cSmillert /* XXX - reserve a cylinder for hp300? */ 17674793b14cSmillert starting_sector = 0; 17684793b14cSmillert ending_sector = lp->d_secperunit; 17694793b14cSmillert 17704793b14cSmillert #ifdef DOSLABEL 1771aaa7b57dSderaadt /* If we have an MBR, use values from the OpenBSD/FreeBSD parition. */ 1772aaa7b57dSderaadt if (dosdp && pp->p_size && 1773aaa7b57dSderaadt (dosdp->dp_typ == DOSPTYP_OPENBSD || 1774aaa7b57dSderaadt dosdp->dp_typ == DOSPTYP_FREEBSD || 1775aaa7b57dSderaadt dosdp->dp_typ == DOSPTYP_NETBSD)) { 17764793b14cSmillert starting_sector = get_le(&dosdp->dp_start); 17774793b14cSmillert ending_sector = starting_sector + get_le(&dosdp->dp_size); 17784793b14cSmillert printf("Treating sectors %u-%u as the OpenBSD portion of the " 17794793b14cSmillert "disk.\nYou can use the 'b' command to change this.\n", 17804793b14cSmillert starting_sector, ending_sector); 1781f98aebd4Smillert /* 1782f98aebd4Smillert * XXX - check to see if any BSD/SWAP partitions go beyond 1783f98aebd4Smillert * ending_sector and prompt to extend ending_sector if so. 1784f98aebd4Smillert */ 17854793b14cSmillert } 17864793b14cSmillert #endif 17874793b14cSmillert } 1788c0bdc608Smillert 1789c0bdc608Smillert /* 1790c0bdc608Smillert * Calculate free space. 1791c0bdc608Smillert */ 1792c0bdc608Smillert void 1793c0bdc608Smillert editor_countfree(lp, freep) 1794c0bdc608Smillert struct disklabel *lp; 1795c0bdc608Smillert u_int32_t *freep; 1796c0bdc608Smillert { 1797c0bdc608Smillert struct partition *pp; 1798c0bdc608Smillert int i; 1799c0bdc608Smillert 1800c0bdc608Smillert *freep = ending_sector - starting_sector; 1801c0bdc608Smillert for (i = 0; i < lp->d_npartitions; i++) { 1802c0bdc608Smillert pp = &lp->d_partitions[i]; 1803c0bdc608Smillert if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT && 1804c0bdc608Smillert pp->p_size > 0 && 1805c0bdc608Smillert pp->p_offset + pp->p_size <= ending_sector && 1806c0bdc608Smillert pp->p_offset >= starting_sector) 1807c0bdc608Smillert *freep -= pp->p_size; 1808c0bdc608Smillert } 1809c0bdc608Smillert } 1810*617e6e4aSmillert 1811*617e6e4aSmillert void 1812*617e6e4aSmillert editor_help(arg) 1813*617e6e4aSmillert char *arg; 1814*617e6e4aSmillert { 1815*617e6e4aSmillert 1816*617e6e4aSmillert /* XXX - put these strings in a table instead? */ 1817*617e6e4aSmillert switch (*arg) { 1818*617e6e4aSmillert case 'p': 1819*617e6e4aSmillert puts( 1820*617e6e4aSmillert "The 'p' command prints the current disk label. By default, it prints the\n" 1821*617e6e4aSmillert "size and offset in sectors (a sector is usually 512 bytes). The 'p' command\n" 1822*617e6e4aSmillert "takes an optional units argument. Possible values are 'b' for bytes, 'c'\n" 1823*617e6e4aSmillert "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n"); 1824*617e6e4aSmillert break; 1825*617e6e4aSmillert case 'M': 1826*617e6e4aSmillert puts( 1827*617e6e4aSmillert "The 'M' command pipes the entire OpenBSD manual page for disklabel though\n" 1828*617e6e4aSmillert "The 'less' pager. It is especially useful during install when the normal\n" 1829*617e6e4aSmillert "system manual is not available.\n"); 1830*617e6e4aSmillert break; 1831*617e6e4aSmillert case 'e': 1832*617e6e4aSmillert puts( 1833*617e6e4aSmillert "The 'e' command is used to edit the disk drive parameters. These include\n" 1834*617e6e4aSmillert "the number of sectors/track, tracks/cylinder, sectors/cylinder, number of\n" 1835*617e6e4aSmillert "cylinders on the disk , total sectors on the disk, rpm, interleave, disk\n" 1836*617e6e4aSmillert "type, and a descriptive label string. You should not change these unless\n" 1837*617e6e4aSmillert "you know what you are doing\n"); 1838*617e6e4aSmillert break; 1839*617e6e4aSmillert case 'a': 1840*617e6e4aSmillert puts( 1841*617e6e4aSmillert "The 'a' command adds new partitions to the disk. It takes as an optional\n" 1842*617e6e4aSmillert "argument the partition letter to add. If you do not specify a partition\n" 1843*617e6e4aSmillert "letter, you will be prompted for it; the next available letter will be the\n" 1844*617e6e4aSmillert "default answer\n"); 1845*617e6e4aSmillert break; 1846*617e6e4aSmillert case 'b': 1847*617e6e4aSmillert puts( 1848*617e6e4aSmillert "The 'b' command is used to change the boundaries of the OpenBSD portion of\n" 1849*617e6e4aSmillert "the disk. This is only useful on disks with an fdisk partition. By default,\n" 1850*617e6e4aSmillert "on a disk with an fdisk partition, the boundaries are set to be the first\n" 1851*617e6e4aSmillert "and last sectors of the OpenBSD fdisk partition. You should only change\n" 1852*617e6e4aSmillert "these if your fdisk partition table is incorrect or you have a disk larger\n" 1853*617e6e4aSmillert "than 8gig, since 8gig is the maximum size an fdisk partition can be. You\n" 1854*617e6e4aSmillert "may enter '*' at the 'Size' prompt to indicate the entire size of the disk\n" 1855*617e6e4aSmillert "(minus the starting sector). Use this option with care; if you extend the\n" 1856*617e6e4aSmillert "boundaries such that they overlap with another operating system you will\n" 1857*617e6e4aSmillert "corrupt the other operating system's data.\n"); 1858*617e6e4aSmillert break; 1859*617e6e4aSmillert case 'c': 1860*617e6e4aSmillert puts( 1861*617e6e4aSmillert "The 'c' command is used to change the size of an existing partition. It\n" 1862*617e6e4aSmillert "takes as an optional argument the partition letter to change. If you do not\n" 1863*617e6e4aSmillert "specify a partition letter, you will be prompted for one. You may add a '+'\n" 1864*617e6e4aSmillert "or '-' prefix to the new size to increase or decrease the existing value\n" 1865*617e6e4aSmillert "instead of entering an absolute value. You may also use a suffix to indicate\n" 1866*617e6e4aSmillert "the units the values is in terms of. Possible suffixes are 'b' for bytes,\n" 1867*617e6e4aSmillert "'c' for cylinders, 'k' for kilobytes, 'm' for megabytes, 'g' for gigabytes or\n" 1868*617e6e4aSmillert "no suffix for sectors (usually 512 bytes). You may also enter '*' to change\n" 1869*617e6e4aSmillert "the size to be the total number of free sectors remaining.\n"); 1870*617e6e4aSmillert break; 1871*617e6e4aSmillert case 'd': 1872*617e6e4aSmillert puts( 1873*617e6e4aSmillert "The 'd' command is used to delete an existing partition. It takes as an\n" 1874*617e6e4aSmillert "optional argument the partition letter to change. If you do not specify a\n" 1875*617e6e4aSmillert "partition letter, you will be prompted for one. You may not delete the ``c''\n" 1876*617e6e4aSmillert "partition as 'c' must always exist and by default is marked as 'unused' (so\n" 1877*617e6e4aSmillert "it does not take up any space).\n"); 1878*617e6e4aSmillert break; 1879*617e6e4aSmillert case 'm': 1880*617e6e4aSmillert puts( 1881*617e6e4aSmillert "The 'm' command is used to modify an existing partition. It takes as an\n" "optional argument the partition letter to change. If you do not specify a\n" 1882*617e6e4aSmillert "partition letter, you will be prompted for one. This option allows the user\n" 1883*617e6e4aSmillert "to change the filesystem type, starting offset, partition size, block fragment\n" 1884*617e6e4aSmillert "size, block size, and cylinders per group for the specified partition (not all\n" 1885*617e6e4aSmillert "parameters are configurable for non-BSD partitions).\n"); 1886*617e6e4aSmillert break; 1887*617e6e4aSmillert case 'r': 1888*617e6e4aSmillert puts( 1889*617e6e4aSmillert "The 'r' command is used to recalculate the free space available. This option\n" 1890*617e6e4aSmillert "should really not be necessary under normal circumstances but can be useful if\n" 1891*617e6e4aSmillert "disklabel gets confused.\n"); 1892*617e6e4aSmillert break; 1893*617e6e4aSmillert case 'u': 1894*617e6e4aSmillert puts( 1895*617e6e4aSmillert "The 'u' command will undo (or redo) the last change. Entering 'u' once will\n" 1896*617e6e4aSmillert "undo your last change. Entering it again will restore the change.\n"); 1897*617e6e4aSmillert break; 1898*617e6e4aSmillert case 's': 1899*617e6e4aSmillert puts( 1900*617e6e4aSmillert "The 's' command is used to save a copy of the label to a file in ascii format\n" 1901*617e6e4aSmillert "(suitable for loading via disklabel's [-R] option). It takes as an optional\n" 1902*617e6e4aSmillert "argument the filename to save the label to. If you do not specify a filename,\n" 1903*617e6e4aSmillert "you will be prompted for one.\n"); 1904*617e6e4aSmillert break; 1905*617e6e4aSmillert case 'w': 1906*617e6e4aSmillert puts( 1907*617e6e4aSmillert "The 'w' command will write the current label to disk. This option will\n" 1908*617e6e4aSmillert "commit any changes to the on-disk label.\n"); 1909*617e6e4aSmillert break; 1910*617e6e4aSmillert case 'q': 1911*617e6e4aSmillert puts( 1912*617e6e4aSmillert "The 'q' command quits the label editor. If any changes have been made you\n" 1913*617e6e4aSmillert "will be asked whether or not to save the changes to the on-disk label.\n"); 1914*617e6e4aSmillert break; 1915*617e6e4aSmillert case 'x': 1916*617e6e4aSmillert puts( 1917*617e6e4aSmillert "The 'x' command exits the label editor without saving any changes to the\n" 1918*617e6e4aSmillert "on-disk label.\n"); 1919*617e6e4aSmillert break; 1920*617e6e4aSmillert default: 1921*617e6e4aSmillert puts("Available commands:"); 1922*617e6e4aSmillert puts("\tp [unit] - print label."); 1923*617e6e4aSmillert puts("\tM - show entire OpenBSD man page for disklabel."); 1924*617e6e4aSmillert puts("\te - edit drive parameters."); 1925*617e6e4aSmillert puts("\ta [part] - add new partition."); 1926*617e6e4aSmillert puts("\tb - set OpenBSD disk boundaries."); 1927*617e6e4aSmillert puts("\tc [part] - change partition size."); 1928*617e6e4aSmillert puts("\td [part] - delete partition."); 1929*617e6e4aSmillert puts("\tm [part] - modify existing partition."); 1930*617e6e4aSmillert puts("\tr - recalculate free space."); 1931*617e6e4aSmillert puts("\tu - undo last change."); 1932*617e6e4aSmillert puts("\ts [path] - save label to file."); 1933*617e6e4aSmillert puts("\tw - write label to disk."); 1934*617e6e4aSmillert puts("\tq - quit and save changes."); 1935*617e6e4aSmillert puts("\tx - exit without saving changes."); 1936*617e6e4aSmillert puts("\t? [cmnd] - this message or command specific help."); 1937*617e6e4aSmillert puts( 1938*617e6e4aSmillert "Numeric parameters may use suffixes to indicate units:\n\t" 1939*617e6e4aSmillert "'b' for bytes, 'c' for cylinders, 'k' for kilobytes, 'm' for megabytes,\n\t" 1940*617e6e4aSmillert "'g' for gigabytes or no suffix for sectors (usually 512 bytes).\n\t" 1941*617e6e4aSmillert "Non-sector units will be rounded to the nearest cylinder.\n" 1942*617e6e4aSmillert "Entering '?' at most prompts will give you (simple) context sensitive help."); 1943*617e6e4aSmillert break; 1944*617e6e4aSmillert } 1945*617e6e4aSmillert } 1946