1*ea37abd3Sderaadt /* $OpenBSD: editor.c,v 1.16 1997/10/17 04:37:52 deraadt Exp $ */ 26fe57b42Smillert 36fe57b42Smillert /* 46fe57b42Smillert * Copyright (c) 1997 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. 156fe57b42Smillert * 3. All advertising materials mentioning features or use of this software 166fe57b42Smillert * must display the following acknowledgement: 176fe57b42Smillert * This product includes software developed by Todd C. Miller. 186fe57b42Smillert * 4. The name of the author may not be used to endorse or promote products 196fe57b42Smillert * derived from this software without specific prior written permission. 206fe57b42Smillert * 216fe57b42Smillert * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 226fe57b42Smillert * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 236fe57b42Smillert * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 246fe57b42Smillert * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 256fe57b42Smillert * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 266fe57b42Smillert * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 276fe57b42Smillert * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 286fe57b42Smillert * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 296fe57b42Smillert * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 306fe57b42Smillert * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 316fe57b42Smillert */ 326fe57b42Smillert 336fe57b42Smillert #ifndef lint 34*ea37abd3Sderaadt static char rcsid[] = "$OpenBSD: editor.c,v 1.16 1997/10/17 04:37:52 deraadt Exp $"; 356fe57b42Smillert #endif /* not lint */ 366fe57b42Smillert 376fe57b42Smillert #include <sys/types.h> 386fe57b42Smillert #include <sys/param.h> 396fe57b42Smillert #define DKTYPENAMES 406fe57b42Smillert #include <sys/disklabel.h> 416fe57b42Smillert 426fe57b42Smillert #include <ufs/ffs/fs.h> 436fe57b42Smillert 446fe57b42Smillert #include <ctype.h> 456fe57b42Smillert #include <err.h> 466fe57b42Smillert #include <errno.h> 476fe57b42Smillert #include <string.h> 486fe57b42Smillert #include <stdio.h> 496fe57b42Smillert #include <stdlib.h> 506fe57b42Smillert #include <unistd.h> 516fe57b42Smillert 526fe57b42Smillert /* flags for getuint() */ 536fe57b42Smillert #define DO_CONVERSIONS 0x00000001 546fe57b42Smillert #define DO_ROUNDING 0x00000002 556fe57b42Smillert 566fe57b42Smillert void edit_parms __P((struct disklabel *, u_int32_t *)); 576fe57b42Smillert int editor __P((struct disklabel *, int)); 586fe57b42Smillert void editor_add __P((struct disklabel *, u_int32_t *, char *)); 596fe57b42Smillert void editor_modify __P((struct disklabel *, u_int32_t *, char *)); 606fe57b42Smillert void editor_delete __P((struct disklabel *, u_int32_t *, char *)); 616fe57b42Smillert void editor_display __P((struct disklabel *, u_int32_t *, char)); 626fe57b42Smillert void editor_change __P((struct disklabel *, u_int32_t *, char *)); 636fe57b42Smillert char *getstring __P((struct disklabel *, char *, char *, char *)); 646fe57b42Smillert u_int32_t getuint __P((struct disklabel *, int, char *, char *, u_int32_t, u_int32_t, int)); 656fe57b42Smillert int has_overlap __P((struct disklabel *, u_int32_t *, int)); 666fe57b42Smillert void make_contiguous __P((struct disklabel *)); 676fe57b42Smillert u_int32_t next_offset __P((struct disklabel *)); 686fe57b42Smillert int partition_cmp __P((const void *, const void *)); 69a7e61405Smillert struct partition **sort_partitions __P((struct disklabel *, u_int16_t *)); 700f820bbbSmillert void getdisktype __P((struct disklabel *, char *)); 716fe57b42Smillert 726fe57b42Smillert /* from disklabel.c */ 736fe57b42Smillert int checklabel __P((struct disklabel *)); 746fe57b42Smillert void display __P((FILE *, struct disklabel *)); 756fe57b42Smillert void display_partition __P((FILE *, struct disklabel *, int, char)); 766fe57b42Smillert struct disklabel *readlabel __P((int)); 776fe57b42Smillert struct disklabel *makebootarea __P((char *, struct disklabel *, int)); 786fe57b42Smillert int writelabel __P((int, char *, struct disklabel *)); 796fe57b42Smillert extern char *bootarea, *specname; 8069220492Smillert extern int donothing; 816fe57b42Smillert 826fe57b42Smillert /* 836fe57b42Smillert * Simple partition editor. Primarily intended for new labels. 846fe57b42Smillert */ 856fe57b42Smillert int 866fe57b42Smillert editor(lp, f) 876fe57b42Smillert struct disklabel *lp; 886fe57b42Smillert int f; 896fe57b42Smillert { 906fe57b42Smillert struct disklabel lastlabel, tmplabel, label = *lp; 916fe57b42Smillert u_int32_t freeblocks; 926fe57b42Smillert FILE *fp; 936fe57b42Smillert char buf[BUFSIZ], *cmd, *arg; 946fe57b42Smillert int i; 956fe57b42Smillert 966fe57b42Smillert /* Set freeblocks based on initial label */ 976fe57b42Smillert freeblocks = label.d_secperunit; 986fe57b42Smillert for (i = 0; i < label.d_npartitions; i++) 996fe57b42Smillert if (label.d_partitions[i].p_fstype != FS_UNUSED && 100229f463eSmillert label.d_partitions[i].p_fstype != FS_BOOT && 1016fe57b42Smillert label.d_partitions[i].p_size > 0) 1026fe57b42Smillert freeblocks -= label.d_partitions[i].p_size; 1036fe57b42Smillert 104*ea37abd3Sderaadt puts("Initial label editor (enter '?' for help at any prompt)"); 1056fe57b42Smillert if (has_overlap(&label, &freeblocks, 1)) 1066fe57b42Smillert errx(1, "can't run when there is partition overlap."); 1076fe57b42Smillert 1080f820bbbSmillert getdisktype(&label, "You need to specify a disk type for this disk."); 1090f820bbbSmillert 1106fe57b42Smillert #ifdef CYLCHECK 1116fe57b42Smillert puts("This platform requires that partition offsets/sizes be on cylinder boundaries.\nPartition offsets/sizes will be rounded to the nearest cylinder automatically."); 1126fe57b42Smillert #endif 1136fe57b42Smillert 1146fe57b42Smillert lastlabel = label; 1156fe57b42Smillert for (;;) { 1166fe57b42Smillert fputs("> ", stdout); 1176fe57b42Smillert fflush(stdout); 1186fe57b42Smillert rewind(stdin); 1196e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1206e0becc5Smillert putchar('\n'); 1216e0becc5Smillert buf[0] = 'q'; 1226e0becc5Smillert buf[1] = '\0'; 1236e0becc5Smillert } 124260513deSmillert if ((cmd = strtok(buf, " \t\r\n")) == NULL) 125260513deSmillert continue; 126260513deSmillert arg = strtok(NULL, " \t\r\n"); 1276fe57b42Smillert 1286fe57b42Smillert switch (*cmd) { 1296fe57b42Smillert 1306fe57b42Smillert case '?': 131*ea37abd3Sderaadt case 'h': 132*ea37abd3Sderaadt puts("Available commands:"); 133*ea37abd3Sderaadt puts("\tp [unit] - print label."); 1349bb06b6bSderaadt puts("\tM - show entire OpenBSD man page for disklabel."); 1356fe57b42Smillert puts("\te - edit drive parameters."); 1366fe57b42Smillert puts("\ta [part] - add new partition."); 1376fe57b42Smillert puts("\tc [part] - change partition size."); 1386fe57b42Smillert puts("\td [part] - delete partition."); 1396fe57b42Smillert puts("\tm [part] - modify existing partition."); 1406fe57b42Smillert puts("\tu - undo last change."); 1416fe57b42Smillert puts("\ts [path] - save label to file."); 142040947cfSmillert puts("\tw - write label to disk."); 1436fe57b42Smillert puts("\tq - quit and save changes."); 1446fe57b42Smillert puts("\tx - exit without saving changes."); 145*ea37abd3Sderaadt puts("\t? - this message."); 146*ea37abd3Sderaadt 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."); 1476fe57b42Smillert break; 1486fe57b42Smillert 1496fe57b42Smillert case 'a': 1506fe57b42Smillert tmplabel = lastlabel; 1516fe57b42Smillert lastlabel = label; 1526fe57b42Smillert editor_add(&label, &freeblocks, arg); 1536fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 1546fe57b42Smillert lastlabel = tmplabel; 1556fe57b42Smillert break; 1566fe57b42Smillert 1576fe57b42Smillert case 'c': 1586fe57b42Smillert tmplabel = lastlabel; 1596fe57b42Smillert lastlabel = label; 1606fe57b42Smillert editor_change(&label, &freeblocks, arg); 1616fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 1626fe57b42Smillert lastlabel = tmplabel; 1636fe57b42Smillert break; 1646fe57b42Smillert 1656fe57b42Smillert case 'd': 1666fe57b42Smillert tmplabel = lastlabel; 1676fe57b42Smillert lastlabel = label; 1686fe57b42Smillert editor_delete(&label, &freeblocks, arg); 1696fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 1706fe57b42Smillert lastlabel = tmplabel; 1716fe57b42Smillert break; 1726fe57b42Smillert 1736fe57b42Smillert case 'm': 1746fe57b42Smillert tmplabel = lastlabel; 1756fe57b42Smillert lastlabel = label; 1766fe57b42Smillert editor_modify(&label, &freeblocks, arg); 1776fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 1786fe57b42Smillert lastlabel = tmplabel; 1796fe57b42Smillert break; 1806fe57b42Smillert 1816fe57b42Smillert case 'p': 1826fe57b42Smillert editor_display(&label, &freeblocks, arg ? *arg : 0); 1836fe57b42Smillert break; 1846fe57b42Smillert 1855d12b01bSderaadt case 'M': 1865d12b01bSderaadt fp = popen("/usr/bin/less", "w"); 1875d12b01bSderaadt if (fp) { 1885d12b01bSderaadt extern char manpage[]; 1895d12b01bSderaadt 1905d12b01bSderaadt (void) fwrite(manpage, strlen(manpage), 1, fp); 1915d12b01bSderaadt pclose(fp); 1925d12b01bSderaadt } 1935d12b01bSderaadt break; 1945d12b01bSderaadt 1956fe57b42Smillert case 'q': 19669220492Smillert if (donothing) { 19769220492Smillert puts("In no change mode, not writing label."); 19869220492Smillert return(1); 19969220492Smillert } 2006fe57b42Smillert if (memcmp(lp, &label, sizeof(label)) == 0) { 2016fe57b42Smillert puts("No changes."); 2026fe57b42Smillert return(1); 2036fe57b42Smillert } 2046fe57b42Smillert do { 2056fe57b42Smillert arg = getstring(lp, "Save changes?", 2066fe57b42Smillert "Save changes you have made to the label?", 2076fe57b42Smillert "n"); 2086fe57b42Smillert } while (tolower(*arg) != 'y' && tolower(*arg) != 'n'); 2096fe57b42Smillert if (tolower(*arg) == 'y') { 2106fe57b42Smillert *lp = label; 2116fe57b42Smillert if (writelabel(f, bootarea, lp) == 0) 2126fe57b42Smillert return(0); 2136fe57b42Smillert } 2146fe57b42Smillert return(1); 2156fe57b42Smillert /* NOTREACHED */ 2166fe57b42Smillert break; 2176fe57b42Smillert 2186fe57b42Smillert case 's': 2196fe57b42Smillert if (arg == NULL) { 220260513deSmillert arg = getstring(lp, "Filename", 2216fe57b42Smillert "Name of the file to save label into.", 2226fe57b42Smillert NULL); 2236fe57b42Smillert if (*arg == '\0') 2246fe57b42Smillert break; 2256fe57b42Smillert } 2266fe57b42Smillert if ((fp = fopen(arg, "w")) == NULL) { 2276fe57b42Smillert warn("cannot open %s", arg); 2286fe57b42Smillert } else { 2296fe57b42Smillert display(fp, &label); 2306fe57b42Smillert (void)fclose(fp); 2316fe57b42Smillert } 2326fe57b42Smillert break; 2336fe57b42Smillert 2346fe57b42Smillert case 'u': 2356fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) { 2366fe57b42Smillert puts("Nothing to undo!"); 2376fe57b42Smillert } else { 2386fe57b42Smillert tmplabel = label; 2396fe57b42Smillert label = lastlabel; 2406fe57b42Smillert lastlabel = tmplabel; 2416fe57b42Smillert puts("Last change undone."); 2426fe57b42Smillert } 2436fe57b42Smillert break; 2446fe57b42Smillert 245040947cfSmillert case 'w': 246040947cfSmillert if (donothing) 247040947cfSmillert puts("In no change mode, not writing label."); 248040947cfSmillert else if (memcmp(lp, &label, sizeof(label)) == 0) 249040947cfSmillert puts("No changes."); 250040947cfSmillert else if (writelabel(f, bootarea, &label) != 0) 251040947cfSmillert warnx("unable to write label"); 2525af08e9cSmillert else 2535af08e9cSmillert *lp = label; 254040947cfSmillert break; 255040947cfSmillert 2566fe57b42Smillert case 'x': 2576fe57b42Smillert return(1); 2586fe57b42Smillert break; 2596fe57b42Smillert 2606fe57b42Smillert case '\n': 2616fe57b42Smillert break; 2626fe57b42Smillert 2636fe57b42Smillert case 'e': 2646fe57b42Smillert tmplabel = lastlabel; 2656fe57b42Smillert lastlabel = label; 2666fe57b42Smillert edit_parms(&label, &freeblocks); 2676fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2686fe57b42Smillert lastlabel = tmplabel; 2696fe57b42Smillert break; 2706fe57b42Smillert 2716fe57b42Smillert default: 2726fe57b42Smillert printf("Unknown option: %c ('?' for help)\n", *cmd); 2736fe57b42Smillert break; 2746fe57b42Smillert } 2756fe57b42Smillert } 2766fe57b42Smillert } 2776fe57b42Smillert 2786fe57b42Smillert /* 2796fe57b42Smillert * Add a new partition. 2806fe57b42Smillert */ 2816fe57b42Smillert void 2826fe57b42Smillert editor_add(lp, freep, p) 2836fe57b42Smillert struct disklabel *lp; 2846fe57b42Smillert u_int32_t *freep; 2856fe57b42Smillert char *p; 2866fe57b42Smillert { 2876fe57b42Smillert struct partition origpart, *pp; 2886fe57b42Smillert char buf[BUFSIZ]; 2896fe57b42Smillert int i, partno; 2906fe57b42Smillert u_int32_t ui; 2916fe57b42Smillert 2926fe57b42Smillert /* XXX - prompt user to steal space from another partition instead */ 2936fe57b42Smillert if (*freep == 0) { 2946fe57b42Smillert fputs("No space left, you need to shrink a partition\n", 2956fe57b42Smillert stderr); 2966fe57b42Smillert return; 2976fe57b42Smillert } 2986fe57b42Smillert 2996fe57b42Smillert /* XXX - make more like other editor_* */ 3006fe57b42Smillert if (p != NULL) { 3016fe57b42Smillert partno = p[0] - 'a'; 3026fe57b42Smillert if (partno < 0 || partno >= MAXPARTITIONS) { 3036fe57b42Smillert fprintf(stderr, 3046fe57b42Smillert "Partition must be between 'a' and '%c'.\n", 3056fe57b42Smillert 'a' + MAXPARTITIONS - 1); 3066fe57b42Smillert return; 3076fe57b42Smillert } 3086fe57b42Smillert } else { 3096fe57b42Smillert /* Find first unused partition that is not 'b' or 'c' */ 3106fe57b42Smillert for (partno = 0; partno < MAXPARTITIONS; partno++, p++) { 3116fe57b42Smillert if (lp->d_partitions[partno].p_size == 0 && 3126fe57b42Smillert partno != 1 && partno != 2) 3136fe57b42Smillert break; 3146fe57b42Smillert } 3156fe57b42Smillert if (partno < MAXPARTITIONS) { 3166fe57b42Smillert buf[0] = partno + 'a'; 3176fe57b42Smillert buf[1] = '\0'; 3186fe57b42Smillert p = &buf[0]; 3196fe57b42Smillert } else 3206fe57b42Smillert p = NULL; 3216fe57b42Smillert for (;;) { 3226fe57b42Smillert p = getstring(lp, "partition", 3236fe57b42Smillert "The letter of the new partition, a - p.", p); 3246fe57b42Smillert partno = p[0] - 'a'; 3256fe57b42Smillert if (partno >= 0 && partno < MAXPARTITIONS) 3266fe57b42Smillert break; 3276fe57b42Smillert fprintf(stderr, 3286fe57b42Smillert "Partition must be between 'a' and '%c'.\n", 3296fe57b42Smillert 'a' + MAXPARTITIONS - 1); 3306fe57b42Smillert } 3316fe57b42Smillert } 3326fe57b42Smillert /* Increase d_npartitions and set defaults if necesary */ 3336fe57b42Smillert pp = &lp->d_partitions[partno]; 3346fe57b42Smillert if (partno >= lp->d_npartitions || pp->p_fstype == FS_UNUSED) { 3356fe57b42Smillert if (partno >= lp->d_npartitions) 3366fe57b42Smillert lp->d_npartitions = partno + 1; 3376fe57b42Smillert memset(pp, 0, sizeof(*pp)); 3386fe57b42Smillert pp->p_offset = next_offset(lp); 3396fe57b42Smillert pp->p_size = *freep; 340f0b4d0a9Smillert if (partno == 1) 341f0b4d0a9Smillert pp->p_fstype = FS_SWAP; 342f0b4d0a9Smillert else 3436fe57b42Smillert pp->p_fstype = FS_BSDFFS; 3446fe57b42Smillert pp->p_fsize = 1024; 3456fe57b42Smillert pp->p_frag = 8; 3466fe57b42Smillert pp->p_cpg = 16; 3476fe57b42Smillert } 3486fe57b42Smillert origpart = *pp; 3496fe57b42Smillert 3506fe57b42Smillert /* Get fstype */ 3516fe57b42Smillert if (pp->p_fstype < FSMAXTYPES) { 3526fe57b42Smillert p = getstring(lp, "FS type", 3536fe57b42Smillert "Filesystem type (usually 4.2BSD or swap)", 3546fe57b42Smillert fstypenames[pp->p_fstype]); 3556fe57b42Smillert for (i = 0; i < FSMAXTYPES; i++) { 3566fe57b42Smillert if (!strcasecmp(p, fstypenames[i])) { 3576fe57b42Smillert pp->p_fstype = i; 3586fe57b42Smillert break; 3596fe57b42Smillert } 3606fe57b42Smillert } 3616fe57b42Smillert if (i >= FSMAXTYPES) { 3626fe57b42Smillert printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p); 3636fe57b42Smillert pp->p_fstype = FS_OTHER; 3646fe57b42Smillert } 3656fe57b42Smillert } else { 3666fe57b42Smillert for (;;) { 3676fe57b42Smillert ui = getuint(lp, partno, "FS type (decimal)", 3686fe57b42Smillert "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", 3696fe57b42Smillert pp->p_fstype, pp->p_fstype, 0); 3706fe57b42Smillert if (ui == UINT_MAX) 3716fe57b42Smillert fputs("Invalid entry\n", stderr); 3726fe57b42Smillert else 3736fe57b42Smillert break; 3746fe57b42Smillert } 3756fe57b42Smillert pp->p_fstype = ui; 3766fe57b42Smillert } 3776fe57b42Smillert 3786fe57b42Smillert getoff1: 3796fe57b42Smillert /* Get offset */ 3806fe57b42Smillert for (;;) { 3816fe57b42Smillert ui = getuint(lp, partno, "offset", 3826fe57b42Smillert "Starting sector for this partition.", pp->p_offset, 3836fe57b42Smillert pp->p_offset, DO_CONVERSIONS | 3846fe57b42Smillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 3856fe57b42Smillert if (ui == UINT_MAX) 3866fe57b42Smillert fputs("Invalid entry\n", stderr); 3876fe57b42Smillert else 3886fe57b42Smillert break; 3896fe57b42Smillert } 3906fe57b42Smillert pp->p_offset = ui; 3916fe57b42Smillert 3926fe57b42Smillert /* Get size */ 3936fe57b42Smillert for (;;) { 3946fe57b42Smillert ui = getuint(lp, partno, "size", "Size of the partition.", 3956fe57b42Smillert pp->p_size, *freep, DO_CONVERSIONS | 3966fe57b42Smillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 3976fe57b42Smillert if (ui + pp->p_offset > lp->d_partitions[2].p_size + 3986fe57b42Smillert lp->d_partitions[2].p_offset) 3996fe57b42Smillert fputs("Partition must not extend past 'c'\n", stderr); 4006fe57b42Smillert else if (ui > *freep) 4016fe57b42Smillert /* XXX - prompt user to steal space from another partition */ 4026fe57b42Smillert fprintf(stderr,"Sorry, there are only %u blocks left\n", 4036fe57b42Smillert *freep); 4046fe57b42Smillert else 4056fe57b42Smillert break; 4066fe57b42Smillert } 4076fe57b42Smillert pp->p_size = ui; 4086fe57b42Smillert if (pp->p_size == 0) 4096fe57b42Smillert return; 4106fe57b42Smillert 4116fe57b42Smillert /* Check for overlap and restore if not resolved */ 4126fe57b42Smillert if (has_overlap(lp, freep, 0)) { 4136fe57b42Smillert puts("\nPlease re-enter an offset and size"); 4146fe57b42Smillert pp->p_offset = origpart.p_offset; 4156fe57b42Smillert pp->p_size = origpart.p_size; 4166fe57b42Smillert goto getoff1; /* Yeah, I know... */ 4176fe57b42Smillert } 4186fe57b42Smillert 4196fe57b42Smillert if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) { 4206fe57b42Smillert /* get fsize */ 4216fe57b42Smillert for (;;) { 4226fe57b42Smillert ui = getuint(lp, partno, "fragment size", 4236fe57b42Smillert "Size of fs block fragments. Usually 1024 or 512.", 4246fe57b42Smillert pp->p_fsize, pp->p_fsize, 0); 4256fe57b42Smillert if (ui == UINT_MAX) 4266fe57b42Smillert fputs("Invalid entry\n", stderr); 4276fe57b42Smillert else 4286fe57b42Smillert break; 4296fe57b42Smillert } 4306fe57b42Smillert pp->p_fsize = ui; 4316fe57b42Smillert if (pp->p_fsize == 0) 4326fe57b42Smillert puts("Zero fragment size implies zero block size"); 4336fe57b42Smillert 4346fe57b42Smillert /* get bsize */ 4356fe57b42Smillert /* XXX - do before frag size? */ 4366fe57b42Smillert for (; pp->p_fsize > 0;) { 4376fe57b42Smillert ui = getuint(lp, partno, "block size", 4386fe57b42Smillert "Size of filesystem blocks. Usually 8192 or 4096.", 4396fe57b42Smillert pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag, 4406fe57b42Smillert 0); 4416fe57b42Smillert 4426fe57b42Smillert /* sanity checks */ 4436fe57b42Smillert if (ui == UINT_MAX) 4446fe57b42Smillert fputs("Invalid entry\n", stderr); 4456fe57b42Smillert else if (ui < getpagesize()) 4466fe57b42Smillert fprintf(stderr, 4476fe57b42Smillert "Error: block size must be at least as big " 4486fe57b42Smillert "as page size (%d).\n", getpagesize()); 4496fe57b42Smillert else if (ui % pp->p_fsize != 0) 4506fe57b42Smillert fputs("Error: block size must be a multiple of the fragment size.\n", stderr); 4516fe57b42Smillert else if (ui / pp->p_fsize < 1) 4526fe57b42Smillert fputs("Error: block size must be at least as big as fragment size.\n", stderr); 4536fe57b42Smillert else 4546fe57b42Smillert break; 4556fe57b42Smillert } 4566fe57b42Smillert pp->p_frag = ui / pp->p_fsize; 4576fe57b42Smillert 4586fe57b42Smillert if (pp->p_fstype == FS_BSDFFS) { 4596fe57b42Smillert /* get cpg */ 4606fe57b42Smillert for (;;) { 4616fe57b42Smillert ui = getuint(lp, partno, "cpg", 4626fe57b42Smillert "Number of filesystem cylinders per group. Usually 16 or 8.", 4636fe57b42Smillert pp->p_cpg, pp->p_cpg, 0); 4646fe57b42Smillert if (ui == UINT_MAX) 4656fe57b42Smillert fputs("Invalid entry\n", stderr); 4666fe57b42Smillert else 4676fe57b42Smillert break; 4686fe57b42Smillert } 4696fe57b42Smillert pp->p_cpg = ui; 4706fe57b42Smillert } 4716fe57b42Smillert } 4726fe57b42Smillert /* Update free block count and make sure things stay contiguous. */ 4736fe57b42Smillert *freep -= pp->p_size; 4746fe57b42Smillert make_contiguous(lp); 4756fe57b42Smillert } 4766fe57b42Smillert 4776fe57b42Smillert /* 4786fe57b42Smillert * Change an existing partition. 4796fe57b42Smillert */ 4806fe57b42Smillert void 4816fe57b42Smillert editor_modify(lp, freep, p) 4826fe57b42Smillert struct disklabel *lp; 4836fe57b42Smillert u_int32_t *freep; 4846fe57b42Smillert char *p; 4856fe57b42Smillert { 4866fe57b42Smillert struct partition origpart, *pp; 4876fe57b42Smillert u_int32_t ui; 4886fe57b42Smillert int partno; 4896fe57b42Smillert 4906fe57b42Smillert /* Change which partition? */ 4916fe57b42Smillert if (p == NULL) { 4926fe57b42Smillert p = getstring(lp, "partition to modify", 4936fe57b42Smillert "The letter of the partition to modify, a - p.", NULL); 4946fe57b42Smillert } 4956fe57b42Smillert partno = p[0] - 'a'; 4966fe57b42Smillert pp = &lp->d_partitions[partno]; 4976fe57b42Smillert origpart = lp->d_partitions[partno]; 4986fe57b42Smillert if (partno < 0 || partno >= lp->d_npartitions) { 4996fe57b42Smillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 5006fe57b42Smillert 'a' + lp->d_npartitions - 1); 5016fe57b42Smillert return; 5026fe57b42Smillert } else if (partno >= lp->d_npartitions || 5036fe57b42Smillert (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) { 5046fe57b42Smillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno); 5056fe57b42Smillert return; 5066fe57b42Smillert } 5076fe57b42Smillert 5086fe57b42Smillert /* Get filesystem type */ 5096fe57b42Smillert if (pp->p_fstype < FSMAXTYPES) { 5106fe57b42Smillert p = getstring(lp, "FS type", 5116fe57b42Smillert "Filesystem type (usually 4.2BSD or swap)", 5126fe57b42Smillert fstypenames[pp->p_fstype]); 5136fe57b42Smillert for (ui = 0; ui < FSMAXTYPES; ui++) { 5146fe57b42Smillert if (!strcasecmp(p, fstypenames[ui])) { 5156fe57b42Smillert pp->p_fstype = ui; 5166fe57b42Smillert break; 5176fe57b42Smillert } 5186fe57b42Smillert } 5196fe57b42Smillert if (ui >= FSMAXTYPES) { 5206fe57b42Smillert printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p); 5216fe57b42Smillert pp->p_fstype = FS_OTHER; 5226fe57b42Smillert } 5236fe57b42Smillert } else { 5246fe57b42Smillert for (;;) { 5256fe57b42Smillert ui = getuint(lp, partno, "FS type (decimal)", 5266fe57b42Smillert "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", 5276fe57b42Smillert pp->p_fstype, pp->p_fstype, 0); 5286fe57b42Smillert if (ui == UINT_MAX) 5296fe57b42Smillert fputs("Invalid entry\n", stderr); 5306fe57b42Smillert else 5316fe57b42Smillert break; 5326fe57b42Smillert } 5336fe57b42Smillert pp->p_fstype = ui; 5346fe57b42Smillert } 5356fe57b42Smillert 5366fe57b42Smillert /* Did they disable/enable the partition? */ 537229f463eSmillert if ((pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) && 538229f463eSmillert origpart.p_fstype != FS_UNUSED && origpart.p_fstype != FS_BOOT) 5396fe57b42Smillert *freep += origpart.p_size; 540229f463eSmillert else if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT && 541229f463eSmillert (origpart.p_fstype == FS_UNUSED || origpart.p_fstype == FS_BOOT)) { 5426fe57b42Smillert if (pp->p_size > *freep) { 5436fe57b42Smillert fprintf(stderr, 5446fe57b42Smillert "Warning, need %u blocks but there are only %u " 5456fe57b42Smillert "free. Setting size to %u.\n", pp->p_size, *freep, 5466fe57b42Smillert *freep); 5476fe57b42Smillert pp->p_fstype = *freep; 5486fe57b42Smillert *freep = 0; 5496fe57b42Smillert } else 5506fe57b42Smillert *freep -= pp->p_size; /* have enough space */ 5516fe57b42Smillert } 5526fe57b42Smillert 5536fe57b42Smillert getoff2: 5546fe57b42Smillert /* Get offset */ 5556fe57b42Smillert for (;;) { 5566fe57b42Smillert ui = getuint(lp, partno, "offset", 5576fe57b42Smillert "Starting sector for this partition.", pp->p_offset, 5586fe57b42Smillert pp->p_offset, DO_CONVERSIONS | 5596fe57b42Smillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 5606fe57b42Smillert if (ui == UINT_MAX) 5616fe57b42Smillert fputs("Invalid entry\n", stderr); 5626fe57b42Smillert else 5636fe57b42Smillert break; 5646fe57b42Smillert } 5656fe57b42Smillert pp->p_offset = ui; 5666fe57b42Smillert 5676fe57b42Smillert /* Get size */ 5686fe57b42Smillert /* XXX - this loop sucks */ 5696fe57b42Smillert for (;;) { 5706fe57b42Smillert ui = getuint(lp, partno, "size", "Size of the partition.", 5716fe57b42Smillert pp->p_size, *freep, 1); 5726fe57b42Smillert 5736fe57b42Smillert if (ui == pp->p_size) 5746fe57b42Smillert break; /* no change */ 5756fe57b42Smillert 5766fe57b42Smillert if (ui == UINT_MAX) { 5776fe57b42Smillert fputs("Invalid entry\n", stderr); 5786fe57b42Smillert continue; 5796fe57b42Smillert } else if (partno != 2 && ui + pp->p_offset > 5806fe57b42Smillert lp->d_partitions[2].p_size + lp->d_partitions[2].p_offset) { 5816fe57b42Smillert fputs("Partition must not extend past 'c'\n", stderr); 5826fe57b42Smillert continue; 5836fe57b42Smillert } else if (partno == 2 && ui + pp->p_offset > lp->d_secperunit) { 5846fe57b42Smillert fputs("'c' partition may not be larger than the disk\n", 5856fe57b42Smillert stderr); 5866fe57b42Smillert continue; 5876fe57b42Smillert } 5886fe57b42Smillert 589229f463eSmillert if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) { 5906fe57b42Smillert pp->p_size = ui; /* don't care what's free */ 5916fe57b42Smillert break; 5926fe57b42Smillert } else { 5936fe57b42Smillert if (ui > pp->p_size + *freep) 5946fe57b42Smillert /* XXX - prompt user to steal space from another partition */ 5956fe57b42Smillert fprintf(stderr, 5966fe57b42Smillert "Size may not be larger than %u blocks\n", 5976fe57b42Smillert pp->p_size + *freep); 5986fe57b42Smillert else { 5996fe57b42Smillert *freep += pp->p_size - ui; 6006fe57b42Smillert pp->p_size = ui; 6016fe57b42Smillert break; 6026fe57b42Smillert } 6036fe57b42Smillert } 6046fe57b42Smillert } 6056fe57b42Smillert if (pp->p_size == 0) 6066fe57b42Smillert return; 6076fe57b42Smillert 6086fe57b42Smillert /* Check for overlap and restore if not resolved */ 6096fe57b42Smillert if (has_overlap(lp, freep, 0)) { 6106fe57b42Smillert puts("\nPlease re-enter an offset and size"); 6116fe57b42Smillert pp->p_offset = origpart.p_offset; 6126fe57b42Smillert pp->p_size = origpart.p_size; 6136fe57b42Smillert goto getoff2; /* Yeah, I know... */ 6146fe57b42Smillert } 6156fe57b42Smillert 6166fe57b42Smillert if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) { 6176fe57b42Smillert /* get fsize */ 6186fe57b42Smillert for (;;) { 6196fe57b42Smillert ui = getuint(lp, partno, "fragment size", 6206fe57b42Smillert "Size of fs block fragments. Usually 1024 or 512.", 6216fe57b42Smillert pp->p_fsize, 1024, 0); 6226fe57b42Smillert if (ui == UINT_MAX) 6236fe57b42Smillert fputs("Invalid entry\n", stderr); 6246fe57b42Smillert else 6256fe57b42Smillert break; 6266fe57b42Smillert } 6276fe57b42Smillert pp->p_fsize = ui; 6286fe57b42Smillert if (pp->p_fsize == 0) 6296fe57b42Smillert puts("Zero fragment size implies zero block size"); 6306fe57b42Smillert 6316fe57b42Smillert /* get bsize */ 6326fe57b42Smillert for (; pp->p_fsize > 0;) { 6336fe57b42Smillert ui = getuint(lp, partno, "block size", 6346fe57b42Smillert "Size of filesystem blocks. Usually 8192 or 4096.", 6356fe57b42Smillert pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag, 6366fe57b42Smillert 0); 6376fe57b42Smillert 6386fe57b42Smillert /* sanity check */ 6396fe57b42Smillert if (ui == UINT_MAX) 6406fe57b42Smillert fputs("Invalid entry\n", stderr); 6416fe57b42Smillert else if (ui % pp->p_fsize != 0) 6426fe57b42Smillert puts("Error: block size must be a multiple of the fragment size."); 6436fe57b42Smillert else if (ui / pp->p_fsize < 1) 6446fe57b42Smillert puts("Error: block size must be at least as big as fragment size."); 6456fe57b42Smillert else { 6466fe57b42Smillert pp->p_frag = ui / pp->p_fsize; 6476fe57b42Smillert break; 6486fe57b42Smillert } 6496fe57b42Smillert } 6506fe57b42Smillert 6516fe57b42Smillert if (pp->p_fstype == FS_BSDFFS) { 6526fe57b42Smillert /* get cpg */ 6536fe57b42Smillert for (;;) { 6546fe57b42Smillert ui = getuint(lp, partno, "cpg", 6556fe57b42Smillert "Number of filesystem cylinders per group." 6566fe57b42Smillert " Usually 16 or 8.", pp->p_cpg, pp->p_cpg, 6576fe57b42Smillert 0); 6586fe57b42Smillert if (ui == UINT_MAX) 6596fe57b42Smillert fputs("Invalid entry\n", stderr); 6606fe57b42Smillert else 6616fe57b42Smillert break; 6626fe57b42Smillert } 6636fe57b42Smillert pp->p_cpg = ui; 6646fe57b42Smillert } 6656fe57b42Smillert } 6666fe57b42Smillert 6676fe57b42Smillert /* Make sure things stay contiguous. */ 6686fe57b42Smillert make_contiguous(lp); 6696fe57b42Smillert } 6706fe57b42Smillert 6716fe57b42Smillert /* 6726fe57b42Smillert * Delete an existing partition. 6736fe57b42Smillert */ 6746fe57b42Smillert void 6756fe57b42Smillert editor_delete(lp, freep, p) 6766fe57b42Smillert struct disklabel *lp; 6776fe57b42Smillert u_int32_t *freep; 6786fe57b42Smillert char *p; 6796fe57b42Smillert { 6806fe57b42Smillert int c; 6816fe57b42Smillert 6826fe57b42Smillert if (p == NULL) { 6836fe57b42Smillert p = getstring(lp, "partition to delete", 6846fe57b42Smillert "The letter of the partition to delete, a - p.", NULL); 6856fe57b42Smillert } 6866fe57b42Smillert c = p[0] - 'a'; 6876fe57b42Smillert if (c < 0 || c >= lp->d_npartitions) 6886fe57b42Smillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 6896fe57b42Smillert 'a' + lp->d_npartitions - 1); 6906fe57b42Smillert else if (c >= lp->d_npartitions || (lp->d_partitions[c].p_fstype == 6916fe57b42Smillert FS_UNUSED && lp->d_partitions[c].p_size == 0)) 6926fe57b42Smillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + c); 6936fe57b42Smillert else if (c == 2) 6946fe57b42Smillert fputs("You may not delete the 'c' partition.\n", stderr); 6956fe57b42Smillert else { 6966fe57b42Smillert /* Update free block count. */ 6976fe57b42Smillert if (lp->d_partitions[c].p_fstype != FS_UNUSED && 698229f463eSmillert lp->d_partitions[c].p_fstype != FS_BOOT && 6996fe57b42Smillert lp->d_partitions[c].p_size != 0) 7006fe57b42Smillert *freep += lp->d_partitions[c].p_size; 7016fe57b42Smillert 7026fe57b42Smillert /* Really delete it (as opposed to just setting to "unused") */ 7036fe57b42Smillert (void)memset(&lp->d_partitions[c], 0, 7046fe57b42Smillert sizeof(lp->d_partitions[c])); 7056fe57b42Smillert 7066fe57b42Smillert /* Fill in the gap we just made */ 7076fe57b42Smillert make_contiguous(lp); 7086fe57b42Smillert } 7096fe57b42Smillert } 7106fe57b42Smillert 7116fe57b42Smillert /* 7126fe57b42Smillert * Simplified display() for use with the builtin editor. 7136fe57b42Smillert */ 7146fe57b42Smillert void 7156fe57b42Smillert editor_display(lp, freep, unit) 7166fe57b42Smillert struct disklabel *lp; 7176fe57b42Smillert u_int32_t *freep; 7186fe57b42Smillert char unit; 7196fe57b42Smillert { 7206fe57b42Smillert int i; 7216fe57b42Smillert 7226fe57b42Smillert printf("device: %s\n", specname); 7230f820bbbSmillert printf("type: %s\n", dktypenames[lp->d_type]); 7246fe57b42Smillert printf("disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename); 7256fe57b42Smillert printf("label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname); 7266fe57b42Smillert printf("bytes/sector: %ld\n", (long)lp->d_secsize); 7276fe57b42Smillert printf("sectors/track: %ld\n", (long)lp->d_nsectors); 7286fe57b42Smillert printf("tracks/cylinder: %ld\n", (long)lp->d_ntracks); 7296fe57b42Smillert printf("sectors/cylinder: %ld\n", (long)lp->d_secpercyl); 7306fe57b42Smillert printf("cylinders: %ld\n", (long)lp->d_ncylinders); 7316fe57b42Smillert printf("total sectors: %ld\n", (long)lp->d_secperunit); 7326fe57b42Smillert printf("free sectors: %u\n", *freep); 7336fe57b42Smillert printf("rpm: %ld\n", (long)lp->d_rpm); 7346fe57b42Smillert printf("\n%d partitions:\n", lp->d_npartitions); 7356fe57b42Smillert printf("# size offset fstype [fsize bsize cpg]\n"); 7366fe57b42Smillert for (i = 0; i < lp->d_npartitions; i++) 7376fe57b42Smillert display_partition(stdout, lp, i, unit); 7386fe57b42Smillert } 7396fe57b42Smillert 7406fe57b42Smillert /* 7416fe57b42Smillert * Find the next reasonable starting offset and returns it. 7426fe57b42Smillert * Assumes there is a least one free block left (returns 0 if not). 7436fe57b42Smillert */ 7446fe57b42Smillert u_int32_t 7456fe57b42Smillert next_offset(lp) 7466fe57b42Smillert struct disklabel *lp; 7476fe57b42Smillert { 748f0b4d0a9Smillert struct partition **spp; 749f0b4d0a9Smillert u_int16_t npartitions; 7506fe57b42Smillert u_int32_t new_offset = 0; 7516fe57b42Smillert int i; 7526fe57b42Smillert 753a7e61405Smillert /* Get a sorted list of the partitions */ 754a7e61405Smillert spp = sort_partitions(lp, &npartitions); 755f0b4d0a9Smillert 756f0b4d0a9Smillert for (i = 0; i < npartitions; i++ ) { 7576fe57b42Smillert /* 7586fe57b42Smillert * Is new_offset inside this partition? If so, 7596fe57b42Smillert * make it the next block after the partition ends. 7606fe57b42Smillert */ 761f0b4d0a9Smillert if (new_offset >= spp[i]->p_offset && 762f0b4d0a9Smillert new_offset < spp[i]->p_offset + spp[i]->p_size) 763f0b4d0a9Smillert new_offset = spp[i]->p_offset + spp[i]->p_size; 7646fe57b42Smillert } 7656fe57b42Smillert 766f0b4d0a9Smillert (void)free(spp); 7676fe57b42Smillert return(new_offset); 7686fe57b42Smillert } 7696fe57b42Smillert 7706fe57b42Smillert /* 7716fe57b42Smillert * Change the size of an existing partition. 7726fe57b42Smillert */ 7736fe57b42Smillert void 7746fe57b42Smillert editor_change(lp, freep, p) 7756fe57b42Smillert struct disklabel *lp; 7766fe57b42Smillert u_int32_t *freep; 7776fe57b42Smillert char *p; 7786fe57b42Smillert { 7796fe57b42Smillert int partno; 7806fe57b42Smillert u_int32_t newsize; 7816fe57b42Smillert 7826fe57b42Smillert if (p == NULL) { 7836fe57b42Smillert p = getstring(lp, "partition to change size", 7846fe57b42Smillert "The letter of the partition to change size, a - p.", NULL); 7856fe57b42Smillert } 7866fe57b42Smillert partno = p[0] - 'a'; 7876fe57b42Smillert if (partno < 0 || partno >= lp->d_npartitions) { 7886fe57b42Smillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 7896fe57b42Smillert 'a' + lp->d_npartitions - 1); 7906fe57b42Smillert return; 7916fe57b42Smillert } else if (partno >= lp->d_npartitions || 792229f463eSmillert lp->d_partitions[partno].p_size == 0) { 7936fe57b42Smillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno); 7946fe57b42Smillert return; 7956fe57b42Smillert } 7966fe57b42Smillert 7976fe57b42Smillert printf("Partition %c is currently %u sectors in size (%u free).\n", 7986fe57b42Smillert partno + 'a', lp->d_partitions[partno].p_size, *freep); 799229f463eSmillert /* XXX - make maxsize lp->d_secperunit if FS_UNUSED/FS_BOOT? */ 8006fe57b42Smillert newsize = getuint(lp, partno, "new size", "Size of the partition. " 8016fe57b42Smillert "You may also say +/- amount for a relative change.", 8026fe57b42Smillert lp->d_partitions[partno].p_size, 8036fe57b42Smillert lp->d_partitions[partno].p_size + *freep, DO_CONVERSIONS | 8046fe57b42Smillert (lp->d_partitions[partno].p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 8056fe57b42Smillert if (newsize == UINT_MAX) { 8066fe57b42Smillert fputs("Invalid entry\n", stderr); 8076fe57b42Smillert return; 8086fe57b42Smillert } else if (newsize == lp->d_partitions[partno].p_size) 8096fe57b42Smillert return; 8106fe57b42Smillert 811229f463eSmillert if (lp->d_partitions[partno].p_fstype != FS_UNUSED && 812229f463eSmillert lp->d_partitions[partno].p_fstype != FS_BOOT) { 8136fe57b42Smillert if (newsize > lp->d_partitions[partno].p_size) { 8146fe57b42Smillert if (newsize - lp->d_partitions[partno].p_size > *freep) { 8156fe57b42Smillert fprintf(stderr, 8166fe57b42Smillert "Only %u sectors free, you asked for %u\n", 8176fe57b42Smillert *freep, 8186fe57b42Smillert newsize - lp->d_partitions[partno].p_size); 8196fe57b42Smillert return; 8206fe57b42Smillert } 8216fe57b42Smillert *freep -= newsize - lp->d_partitions[partno].p_size; 8226fe57b42Smillert } else if (newsize < lp->d_partitions[partno].p_size) { 8236fe57b42Smillert *freep += lp->d_partitions[partno].p_size - newsize; 8246fe57b42Smillert } 8256fe57b42Smillert } else { 8266fe57b42Smillert if (partno != 2 && newsize + lp->d_partitions[partno].p_offset > 8276fe57b42Smillert lp->d_partitions[2].p_size) { 8286fe57b42Smillert fputs("Partition must not extend past 'c'\n", stderr); 8296fe57b42Smillert return; 8306fe57b42Smillert } else if (partno == 2 && newsize + 8316fe57b42Smillert lp->d_partitions[partno].p_offset > lp->d_secperunit) { 8326fe57b42Smillert fputs("'c' partition may not be larger than the disk\n", 8336fe57b42Smillert stderr); 8346fe57b42Smillert return; 8356fe57b42Smillert } 8366fe57b42Smillert } 8376fe57b42Smillert lp->d_partitions[partno].p_size = newsize; 8386fe57b42Smillert make_contiguous(lp); 8396fe57b42Smillert } 8406fe57b42Smillert 8416fe57b42Smillert void 8426fe57b42Smillert make_contiguous(lp) 8436fe57b42Smillert struct disklabel *lp; 8446fe57b42Smillert { 8456fe57b42Smillert struct partition **spp; 8466fe57b42Smillert u_int16_t npartitions; 8476fe57b42Smillert int i; 8486fe57b42Smillert 849a7e61405Smillert /* Get a sorted list of the partitions */ 850a7e61405Smillert spp = sort_partitions(lp, &npartitions); 8516fe57b42Smillert 8526fe57b42Smillert /* 853a7e61405Smillert * Make everything contiguous but don't muck with start of the first one 8546fe57b42Smillert */ 8556fe57b42Smillert for (i = 1; i < npartitions; i++) 8566fe57b42Smillert spp[i]->p_offset = spp[i - 1]->p_offset + spp[i - 1]->p_size; 857f0b4d0a9Smillert 858f0b4d0a9Smillert (void)free(spp); 8596fe57b42Smillert } 8606fe57b42Smillert 8616fe57b42Smillert /* 8626fe57b42Smillert * Sort the partitions based on starting offset. 8636fe57b42Smillert * This assumes there can be no overlap. 8646fe57b42Smillert */ 8656fe57b42Smillert int 8666fe57b42Smillert partition_cmp(e1, e2) 8676fe57b42Smillert const void *e1, *e2; 8686fe57b42Smillert { 8696fe57b42Smillert struct partition *p1 = *(struct partition **)e1; 8706fe57b42Smillert struct partition *p2 = *(struct partition **)e2; 8716fe57b42Smillert 8726fe57b42Smillert return((int)(p1->p_offset - p2->p_offset)); 8736fe57b42Smillert } 8746fe57b42Smillert 8756fe57b42Smillert char * 8766fe57b42Smillert getstring(lp, prompt, helpstring, oval) 8776fe57b42Smillert struct disklabel *lp; 8786fe57b42Smillert char *prompt; 8796fe57b42Smillert char *helpstring; 8806fe57b42Smillert char *oval; 8816fe57b42Smillert { 8826fe57b42Smillert static char buf[BUFSIZ]; 8836fe57b42Smillert int n; 8846fe57b42Smillert 8856fe57b42Smillert buf[0] = '\0'; 8866fe57b42Smillert do { 8876fe57b42Smillert printf("%s: [%s] ", prompt, oval ? oval : ""); 8886fe57b42Smillert fflush(stdout); 8896fe57b42Smillert rewind(stdin); 8906e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 8916e0becc5Smillert putchar('\n'); 892260513deSmillert buf[0] = '\0'; 8936e0becc5Smillert } 8946fe57b42Smillert n = strlen(buf); 8956fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 8966fe57b42Smillert buf[--n] = '\0'; 8976fe57b42Smillert if (buf[0] == '?') 8986fe57b42Smillert puts(helpstring); 8996fe57b42Smillert else if (oval != NULL && buf[0] == '\0') { 9006fe57b42Smillert (void)strncpy(buf, oval, sizeof(buf) - 1); 9016fe57b42Smillert buf[sizeof(buf) - 1] = '\0'; 9026fe57b42Smillert } 9036fe57b42Smillert } while (buf[0] == '?'); 9046fe57b42Smillert 9056fe57b42Smillert return(&buf[0]); 9066fe57b42Smillert } 9076fe57b42Smillert 9086fe57b42Smillert /* 9096fe57b42Smillert * Returns UINT_MAX on error 9106fe57b42Smillert * XXX - there are way too many parameters here. Use inline helper functions 9116fe57b42Smillert */ 9126fe57b42Smillert u_int32_t 9136fe57b42Smillert getuint(lp, partno, prompt, helpstring, oval, maxval, flags) 9146fe57b42Smillert struct disklabel *lp; 9156fe57b42Smillert int partno; 9166fe57b42Smillert char *prompt; 9176fe57b42Smillert char *helpstring; 9186fe57b42Smillert u_int32_t oval; 9196fe57b42Smillert u_int32_t maxval; /* XXX - used inconsistently */ 9206fe57b42Smillert int flags; 9216fe57b42Smillert { 9226fe57b42Smillert char buf[BUFSIZ], *endptr, *p, operator = '\0'; 9236fe57b42Smillert u_int32_t rval = oval; 9246fe57b42Smillert size_t n; 9256fe57b42Smillert int mult = 1; 9266fe57b42Smillert u_long ul; 9276fe57b42Smillert 9286fe57b42Smillert buf[0] = '\0'; 9296fe57b42Smillert do { 9306fe57b42Smillert printf("%s: [%u] ", prompt, oval); 9316fe57b42Smillert fflush(stdout); 9326fe57b42Smillert rewind(stdin); 9336e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 9346e0becc5Smillert putchar('\n'); 9356e0becc5Smillert buf[0] = '\0'; 9366e0becc5Smillert } 9376fe57b42Smillert n = strlen(buf); 9386fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 9396fe57b42Smillert buf[--n] = '\0'; 9406fe57b42Smillert if (buf[0] == '?') 9416fe57b42Smillert puts(helpstring); 9426fe57b42Smillert } while (buf[0] == '?'); 9436fe57b42Smillert 9446fe57b42Smillert if (buf[0] == '*' && buf[1] == '\0') { 9456fe57b42Smillert rval = maxval; 9466fe57b42Smillert } else { 9476fe57b42Smillert /* deal with units */ 9486fe57b42Smillert if (buf[0] != '\0' && n > 0) { 9496fe57b42Smillert if ((flags & DO_CONVERSIONS)) { 9506fe57b42Smillert switch (buf[n-1]) { 9516fe57b42Smillert 9526fe57b42Smillert case 'c': 9536fe57b42Smillert mult = lp->d_secpercyl; 9546fe57b42Smillert buf[--n] = '\0'; 9556fe57b42Smillert break; 9566fe57b42Smillert case 'b': 9576fe57b42Smillert mult = -lp->d_secsize; 9586fe57b42Smillert buf[--n] = '\0'; 9596fe57b42Smillert break; 9606fe57b42Smillert case 'k': 9616fe57b42Smillert mult = 1024 / lp->d_secsize; 9626fe57b42Smillert buf[--n] = '\0'; 9636fe57b42Smillert break; 9646fe57b42Smillert case 'm': 9656fe57b42Smillert mult = 1048576 / lp->d_secsize; 9666fe57b42Smillert buf[--n] = '\0'; 9676fe57b42Smillert break; 9681a51a1eeSmillert case 'g': 9691a51a1eeSmillert mult = 1073741824 / lp->d_secsize; 9701a51a1eeSmillert buf[--n] = '\0'; 9711a51a1eeSmillert break; 9726fe57b42Smillert } 9736fe57b42Smillert } else 9746fe57b42Smillert mult = 1; 9756fe57b42Smillert 9766fe57b42Smillert /* Did they give us an operator? */ 9776fe57b42Smillert p = &buf[0]; 9786fe57b42Smillert if (*p == '+' || *p == '-') 9796fe57b42Smillert operator = *p++; 9806fe57b42Smillert 9816fe57b42Smillert endptr = p; 9826fe57b42Smillert if (mult > 0) 9836fe57b42Smillert ul = strtoul(p, &endptr, 10) * mult; 9846fe57b42Smillert else 9856fe57b42Smillert /* Negative mult means divide (ooh, fancy) */ 9866fe57b42Smillert ul = strtoul(p, &endptr, 10) / (-mult); 9876fe57b42Smillert 9886fe57b42Smillert /* Sanity check the return val */ 9896fe57b42Smillert if (ul == ULONG_MAX || ul >= UINT_MAX) { 9906fe57b42Smillert errno = ERANGE; /* too big */ 9916fe57b42Smillert rval = UINT_MAX; 9926fe57b42Smillert } else if (*endptr != '\0') { 9936fe57b42Smillert errno = EINVAL; /* non-numbers in str */ 9946fe57b42Smillert rval = UINT_MAX; 9956fe57b42Smillert } else { 9966fe57b42Smillert rval = ul; 9976fe57b42Smillert 9986fe57b42Smillert /* Apply the operator (XXX - check for oflow) */ 9996fe57b42Smillert if (operator == '+') 10006fe57b42Smillert rval += oval; 10016fe57b42Smillert else if (operator == '-') 10026fe57b42Smillert rval = oval - rval; 10036fe57b42Smillert } 10046fe57b42Smillert } 10056fe57b42Smillert } 10066fe57b42Smillert if ((flags & DO_ROUNDING) && rval < UINT_MAX) { 10076fe57b42Smillert u_int32_t cyls; 1008260513deSmillert /* XXX - should use maxsize and round down if too big */ 10096fe57b42Smillert #ifdef CYLCHECK 10106fe57b42Smillert /* Always round to nearest cylinder, regardless of units */ 10116fe57b42Smillert cyls = (u_int32_t)((rval / (double)lp->d_secpercyl) + 0.5); 10126fe57b42Smillert if (rval != cyls * lp->d_secpercyl) { 10136fe57b42Smillert rval = cyls * lp->d_secpercyl; 10146fe57b42Smillert printf("Rounding to nearest cylinder: %u\n", rval); 10156fe57b42Smillert } 10166fe57b42Smillert #else 10176fe57b42Smillert /* Round to nearest cylinder unless given in blocks */ 10186fe57b42Smillert if (mult > 1) { 10196fe57b42Smillert cyls = (u_int32_t)((rval / (double)lp->d_secpercyl) 10206fe57b42Smillert + 0.5); 10216fe57b42Smillert if (rval != cyls * lp->d_secpercyl) { 10226fe57b42Smillert rval = cyls * lp->d_secpercyl; 10236fe57b42Smillert printf("Rounding to nearest cylinder: %u\n", 10246fe57b42Smillert rval); 10256fe57b42Smillert } 10266fe57b42Smillert } 10276fe57b42Smillert #endif 10286fe57b42Smillert } 10296fe57b42Smillert 10306fe57b42Smillert return(rval); 10316fe57b42Smillert } 10326fe57b42Smillert 10336fe57b42Smillert /* 10346fe57b42Smillert * Check for partition overlap in lp and prompt the user 10356fe57b42Smillert * to resolve the overlap if any is found. Returns 1 10366fe57b42Smillert * if unable to resolve, else 0. 10376fe57b42Smillert */ 10386fe57b42Smillert int 10396fe57b42Smillert has_overlap(lp, freep, resolve) 10406fe57b42Smillert struct disklabel *lp; 10416fe57b42Smillert u_int32_t *freep; 10426fe57b42Smillert int resolve; 10436fe57b42Smillert { 10446fe57b42Smillert struct partition **spp; 10456fe57b42Smillert u_int16_t npartitions; 10466fe57b42Smillert int c, i, j, rval = 0; 10476fe57b42Smillert 1048a7e61405Smillert /* Get a sorted list of the partitions */ 1049a7e61405Smillert spp = sort_partitions(lp, &npartitions); 10506fe57b42Smillert 1051a7e61405Smillert if (npartitions < 2) { 1052a7e61405Smillert (void)free(spp); 10536fe57b42Smillert return(0); /* nothing to do */ 10546fe57b42Smillert } 10556fe57b42Smillert 10566fe57b42Smillert /* Now that we have things sorted by starting sector check overlap */ 10576fe57b42Smillert for (i = 0; i < npartitions; i++) { 10586fe57b42Smillert for (j = i + 1; j < npartitions; j++) { 10596fe57b42Smillert /* `if last_sec_in_part + 1 > first_sec_in_next_part' */ 10606fe57b42Smillert if (spp[i]->p_offset + spp[i]->p_size > spp[j]->p_offset) { 10616fe57b42Smillert /* Overlap! Convert to real part numbers. */ 10626fe57b42Smillert i = ((char *)spp[i] - (char *)lp->d_partitions) 10636fe57b42Smillert / sizeof(**spp); 10646fe57b42Smillert j = ((char *)spp[j] - (char *)lp->d_partitions) 10656fe57b42Smillert / sizeof(**spp); 10666fe57b42Smillert printf("\nError, partitions %c and %c overlap:\n", 10676fe57b42Smillert 'a' + i, 'a' + j); 10686fe57b42Smillert puts(" size offset fstype [fsize bsize cpg]"); 10696fe57b42Smillert display_partition(stdout, lp, i, 0); 10706fe57b42Smillert display_partition(stdout, lp, j, 0); 10716fe57b42Smillert 10726fe57b42Smillert /* Did they ask us to resolve it ourselves? */ 1073f0b4d0a9Smillert if (!resolve) { 1074f0b4d0a9Smillert (void)free(spp); 10756fe57b42Smillert return(1); 1076f0b4d0a9Smillert } 10776fe57b42Smillert 10786fe57b42Smillert printf("Disable which one? [%c %c] ", 10796fe57b42Smillert 'a' + i, 'a' + j); 10806fe57b42Smillert /* XXX - make less gross */ 10816fe57b42Smillert while ((c = getchar()) != EOF && c != '\n') { 10826fe57b42Smillert c -= 'a'; 10836fe57b42Smillert if (c == i || c == j) 10846fe57b42Smillert break; 10856fe57b42Smillert } 10866fe57b42Smillert putchar('\n'); 10876fe57b42Smillert /* Mark the selected one as unused or... */ 10886fe57b42Smillert if (c == i || c == j) { 10896fe57b42Smillert lp->d_partitions[c].p_fstype = FS_UNUSED; 10906fe57b42Smillert *freep += lp->d_partitions[c].p_size; 10916fe57b42Smillert } else 10926fe57b42Smillert rval = 1; /* still has overlap */ 10936fe57b42Smillert } 10946fe57b42Smillert } 10956fe57b42Smillert } 1096f0b4d0a9Smillert 1097f0b4d0a9Smillert (void)free(spp); 10986fe57b42Smillert return(rval); 10996fe57b42Smillert } 11006fe57b42Smillert 11016fe57b42Smillert void 11026fe57b42Smillert edit_parms(lp, freep) 11036fe57b42Smillert struct disklabel *lp; 11046fe57b42Smillert u_int32_t *freep; 11056fe57b42Smillert { 11066fe57b42Smillert char *p; 11076fe57b42Smillert u_int32_t ui; 11086fe57b42Smillert 1109*ea37abd3Sderaadt printf("Changing device parameters for %s:\n", specname); 11106fe57b42Smillert 11110f820bbbSmillert /* disk type */ 11120f820bbbSmillert for (;;) { 11130f820bbbSmillert p = getstring(lp, "disk type", 11140f820bbbSmillert "What kind of disk is this? Usually SCSI, ST506, or " 11150f820bbbSmillert "floppy (use ST506 for IDE).", dktypenames[lp->d_type]); 11160f820bbbSmillert for (ui = 1; ui < DKMAXTYPES && strcasecmp(p, dktypenames[ui]); 11170f820bbbSmillert ui++) 11180f820bbbSmillert ; 11190f820bbbSmillert if (ui < DKMAXTYPES) { 11200f820bbbSmillert break; 11210f820bbbSmillert } else { 11220f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", p); 11230f820bbbSmillert fputs("Valid types are: ", stdout); 11240f820bbbSmillert for (ui = 1; ui < DKMAXTYPES; ui++) { 11250f820bbbSmillert printf("\"%s\"", dktypenames[ui]); 11260f820bbbSmillert if (ui < DKMAXTYPES - 1) 11270f820bbbSmillert fputs(", ", stdout); 11280f820bbbSmillert } 11290f820bbbSmillert putchar('\n'); 11300f820bbbSmillert } 11310f820bbbSmillert } 11320f820bbbSmillert lp->d_type = ui; 11330f820bbbSmillert 11346fe57b42Smillert /* pack/label id */ 11356fe57b42Smillert p = getstring(lp, "label name", 11366fe57b42Smillert "15 char string that describes this label, usually the disk name.", 11376fe57b42Smillert lp->d_packname); 11386fe57b42Smillert strncpy(lp->d_packname, p, sizeof(lp->d_packname) - 1); 11396fe57b42Smillert lp->d_packname[sizeof(lp->d_packname) - 1] = '\0'; 11406fe57b42Smillert 11416fe57b42Smillert /* sectors/track */ 11426fe57b42Smillert for (;;) { 11436fe57b42Smillert ui = getuint(lp, 0, "sectors/track", 11446fe57b42Smillert "The Numer of sectors per track.", lp->d_nsectors, 11456fe57b42Smillert lp->d_nsectors, 0); 11466fe57b42Smillert if (ui == UINT_MAX) 11476fe57b42Smillert fputs("Invalid entry\n", stderr); 11486fe57b42Smillert else 11496fe57b42Smillert break; 11506fe57b42Smillert } 11516fe57b42Smillert lp->d_nsectors = ui; 11526fe57b42Smillert 11536fe57b42Smillert /* tracks/cylinder */ 11546fe57b42Smillert for (;;) { 11556fe57b42Smillert ui = getuint(lp, 0, "tracks/cylinder", 11566fe57b42Smillert "The number of tracks per cylinder.", lp->d_ntracks, 11576fe57b42Smillert lp->d_ntracks, 0); 11586fe57b42Smillert if (ui == UINT_MAX) 11596fe57b42Smillert fputs("Invalid entry\n", stderr); 11606fe57b42Smillert else 11616fe57b42Smillert break; 11626fe57b42Smillert } 11636fe57b42Smillert lp->d_ntracks = ui; 11646fe57b42Smillert 11656fe57b42Smillert /* sectors/cylinder */ 11666fe57b42Smillert lp->d_ncylinders = lp->d_ntracks * lp->d_nsectors; 11676fe57b42Smillert 11686fe57b42Smillert /* number of cylinders */ 11696fe57b42Smillert for (;;) { 11706fe57b42Smillert ui = getuint(lp, 0, "number of cylinders", 11716fe57b42Smillert "The total number of cylinders on the disk.", 11726fe57b42Smillert lp->d_ncylinders, lp->d_ncylinders, 0); 11736fe57b42Smillert if (ui == UINT_MAX) 11746fe57b42Smillert fputs("Invalid entry\n", stderr); 11756fe57b42Smillert else 11766fe57b42Smillert break; 11776fe57b42Smillert } 11786fe57b42Smillert lp->d_ncylinders = ui; 11796fe57b42Smillert 11806fe57b42Smillert /* total sectors */ 11816fe57b42Smillert for (;;) { 11826fe57b42Smillert ui = getuint(lp, 0, "total sectors", 11836fe57b42Smillert "The total number of sectors on the disk.", 11846fe57b42Smillert lp->d_secperunit ? lp->d_secperunit : 11856fe57b42Smillert lp->d_ncylinders * lp->d_ncylinders, 11866fe57b42Smillert lp->d_ncylinders * lp->d_ncylinders, 0); 11876fe57b42Smillert if (ui == UINT_MAX) 11886fe57b42Smillert fputs("Invalid entry\n", stderr); 11896fe57b42Smillert else if (ui > lp->d_secperunit) { 11906fe57b42Smillert /* grow free count */ 11916fe57b42Smillert *freep += ui - lp->d_secperunit; 11926fe57b42Smillert puts("You may want to increase the 'c' partition."); 11936fe57b42Smillert break; 11946fe57b42Smillert } else if (ui < lp->d_secperunit) { 11956fe57b42Smillert /* shrink free count */ 11966fe57b42Smillert if (lp->d_secperunit - ui > *freep) 11976fe57b42Smillert fprintf(stderr, 11986fe57b42Smillert "Not enough free space to shrink by %u " 11996fe57b42Smillert "sectors (only %u sectors left)\n", 12006fe57b42Smillert lp->d_secperunit - ui, *freep); 12016fe57b42Smillert else { 12026fe57b42Smillert *freep -= lp->d_secperunit - ui; 12036fe57b42Smillert break; 12046fe57b42Smillert } 12056fe57b42Smillert } else 12066fe57b42Smillert break; 12076fe57b42Smillert } 12086fe57b42Smillert lp->d_secperunit = ui; 12096fe57b42Smillert 12106fe57b42Smillert /* rpm */ 12116fe57b42Smillert for (;;) { 12126fe57b42Smillert ui = getuint(lp, 0, "rpm", 1213a7e61405Smillert "The rotational speed of the disk in revolutions per minute.", 12146fe57b42Smillert lp->d_rpm, lp->d_rpm, 0); 12156fe57b42Smillert if (ui == UINT_MAX) 12166fe57b42Smillert fputs("Invalid entry\n", stderr); 12176fe57b42Smillert else 12186fe57b42Smillert break; 12196fe57b42Smillert } 12206fe57b42Smillert lp->d_rpm = ui; 12216fe57b42Smillert } 1222a7e61405Smillert 1223a7e61405Smillert struct partition ** 1224a7e61405Smillert sort_partitions(lp, npart) 1225a7e61405Smillert struct disklabel *lp; 1226a7e61405Smillert u_int16_t *npart; 1227a7e61405Smillert { 1228a7e61405Smillert u_int16_t npartitions; 1229a7e61405Smillert struct partition **spp; 1230a7e61405Smillert int i; 1231a7e61405Smillert 1232a7e61405Smillert /* How many "real" partitions do we have? */ 1233a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1234a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1235a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 1236a7e61405Smillert lp->d_partitions[i].p_size != 0) 1237a7e61405Smillert npartitions++; 1238a7e61405Smillert } 1239a7e61405Smillert 1240a7e61405Smillert /* Create an array of pointers to the partition data */ 1241a7e61405Smillert if ((spp = malloc(sizeof(struct partition *) * npartitions)) == NULL) 1242a7e61405Smillert errx(4, "out of memory"); 1243a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1244a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1245a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 1246a7e61405Smillert lp->d_partitions[i].p_size != 0) 1247a7e61405Smillert spp[npartitions++] = &lp->d_partitions[i]; 1248a7e61405Smillert } 1249a7e61405Smillert 1250a7e61405Smillert /* 1251a7e61405Smillert * Sort the partitions based on starting offset. 1252a7e61405Smillert * This is safe because we guarantee no overlap. 1253a7e61405Smillert */ 1254a7e61405Smillert if (npartitions > 1) 1255a7e61405Smillert if (heapsort((void *)spp, npartitions, sizeof(spp[0]), 1256a7e61405Smillert partition_cmp)) 1257a7e61405Smillert err(4, "failed to sort partition table"); 1258a7e61405Smillert 1259a7e61405Smillert *npart = npartitions; 1260a7e61405Smillert return(spp); 1261a7e61405Smillert } 12620f820bbbSmillert 12630f820bbbSmillert /* 12640f820bbbSmillert * Get a valid disk type if necessary. 12650f820bbbSmillert */ 12660f820bbbSmillert void 12670f820bbbSmillert getdisktype(lp, banner) 12680f820bbbSmillert struct disklabel *lp; 12690f820bbbSmillert char *banner; 12700f820bbbSmillert { 12710f820bbbSmillert int i; 12720f820bbbSmillert char *s; 12730f820bbbSmillert 12740f820bbbSmillert if (lp->d_type > DKMAXTYPES || lp->d_type == 0) { 12750f820bbbSmillert puts(banner); 12760f820bbbSmillert puts("Possible values are:"); 12770f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 12780f820bbbSmillert printf("\"%s\"", dktypenames[i]); 12790f820bbbSmillert if (i < DKMAXTYPES - 1) 12800f820bbbSmillert fputs(", ", stdout); 12810f820bbbSmillert } 12820f820bbbSmillert putchar('\n'); 12830f820bbbSmillert 12840f820bbbSmillert for (;;) { 12850f820bbbSmillert s = getstring(lp, "Disk type", 12860f820bbbSmillert "What kind of disk is this? Usually SCSI, ST506, or floppy (use ST506 for IDE).", 12870f820bbbSmillert "SCSI"); 12880f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) 12890f820bbbSmillert if (strcasecmp(s, dktypenames[i]) == 0) { 12900f820bbbSmillert lp->d_type = i; 12910f820bbbSmillert putchar('\n'); 12920f820bbbSmillert return; 12930f820bbbSmillert } 12940f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", s); 12950f820bbbSmillert fputs("Valid types are: ", stdout); 12960f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 12970f820bbbSmillert printf("\"%s\"", dktypenames[i]); 12980f820bbbSmillert if (i < DKMAXTYPES - 1) 12990f820bbbSmillert fputs(", ", stdout); 13000f820bbbSmillert } 13010f820bbbSmillert putchar('\n'); 13020f820bbbSmillert } 13030f820bbbSmillert } 13040f820bbbSmillert } 1305