1*cdd7eb76Smillert /* $OpenBSD: editor.c,v 1.72 2000/06/04 18:34:41 millert Exp $ */ 26fe57b42Smillert 36fe57b42Smillert /* 42d8451b0Smillert * Copyright (c) 1997-2000 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*cdd7eb76Smillert static char rcsid[] = "$OpenBSD: editor.c,v 1.72 2000/06/04 18:34:41 millert Exp $"; 326fe57b42Smillert #endif /* not lint */ 336fe57b42Smillert 346fe57b42Smillert #include <sys/types.h> 356fe57b42Smillert #include <sys/param.h> 36c33fcabaSmillert #include <sys/stat.h> 37c33fcabaSmillert #include <sys/ioctl.h> 386fe57b42Smillert #define DKTYPENAMES 396fe57b42Smillert #include <sys/disklabel.h> 40c33fcabaSmillert #include <sys/reboot.h> 41c33fcabaSmillert #include <sys/sysctl.h> 42c33fcabaSmillert #include <machine/cpu.h> 43c33fcabaSmillert #ifdef CPU_BIOS 44c33fcabaSmillert #include <machine/biosvar.h> 45c33fcabaSmillert #endif 466fe57b42Smillert 476fe57b42Smillert #include <ufs/ffs/fs.h> 486fe57b42Smillert 496fe57b42Smillert #include <ctype.h> 506fe57b42Smillert #include <err.h> 516fe57b42Smillert #include <errno.h> 526fe57b42Smillert #include <string.h> 53803ff7d5Smillert #include <libgen.h> 546fe57b42Smillert #include <stdio.h> 556fe57b42Smillert #include <stdlib.h> 566fe57b42Smillert #include <unistd.h> 576fe57b42Smillert 584793b14cSmillert #include "pathnames.h" 594793b14cSmillert 606fe57b42Smillert /* flags for getuint() */ 616fe57b42Smillert #define DO_CONVERSIONS 0x00000001 626fe57b42Smillert #define DO_ROUNDING 0x00000002 636fe57b42Smillert 64f98aebd4Smillert #ifndef NUMBOOT 65f98aebd4Smillert #define NUMBOOT 0 66f98aebd4Smillert #endif 67f98aebd4Smillert 6896a888c6Smillert /* structure to describe a portion of a disk */ 6996a888c6Smillert struct diskchunk { 7096a888c6Smillert u_int32_t start; 7196a888c6Smillert u_int32_t stop; 7296a888c6Smillert }; 7396a888c6Smillert 743f843443Smillert /* used when sorting mountpoints in mpsave() */ 753f843443Smillert struct mountinfo { 763f843443Smillert char *mountpoint; 773f843443Smillert int partno; 783f843443Smillert }; 793f843443Smillert 806fe57b42Smillert void edit_parms __P((struct disklabel *, u_int32_t *)); 819785f718Smillert int editor __P((struct disklabel *, int, char *, char *)); 82bd6726faSmillert void editor_add __P((struct disklabel *, char **, u_int32_t *, char *)); 836fe57b42Smillert void editor_change __P((struct disklabel *, u_int32_t *, char *)); 84c0bdc608Smillert void editor_countfree __P((struct disklabel *, u_int32_t *)); 85bd6726faSmillert void editor_delete __P((struct disklabel *, char **, u_int32_t *, char *)); 86bd6726faSmillert void editor_display __P((struct disklabel *, char **, u_int32_t *, char)); 87617e6e4aSmillert void editor_help __P((char *)); 88bd6726faSmillert void editor_modify __P((struct disklabel *, char **, u_int32_t *, char *)); 89bd6726faSmillert void editor_name __P((struct disklabel *, char **, char *)); 90c33fcabaSmillert char *getstring __P((char *, char *, char *)); 914b9a3bdaSmillert u_int32_t getuint __P((struct disklabel *, int, char *, char *, u_int32_t, u_int32_t, u_int32_t, int)); 926fe57b42Smillert int has_overlap __P((struct disklabel *, u_int32_t *, int)); 936fe57b42Smillert void make_contiguous __P((struct disklabel *)); 942d8451b0Smillert u_int32_t next_offset __P((struct disklabel *, u_int32_t *)); 956fe57b42Smillert int partition_cmp __P((const void *, const void *)); 96a7e61405Smillert struct partition **sort_partitions __P((struct disklabel *, u_int16_t *)); 97803ff7d5Smillert void getdisktype __P((struct disklabel *, char *, char *)); 989785f718Smillert void find_bounds __P((struct disklabel *, struct disklabel *)); 99e8e8bdb7Sart void set_bounds __P((struct disklabel *, u_int32_t *)); 10096a888c6Smillert struct diskchunk *free_chunks __P((struct disklabel *)); 101bd6726faSmillert char ** mpcopy __P((char **, char **)); 1023f843443Smillert int micmp __P((const void *, const void *)); 103bd6726faSmillert int mpequal __P((char **, char **)); 104bd6726faSmillert int mpsave __P((struct disklabel *, char **, char *, char *)); 10524a2c1a4Smillert int get_bsize __P((struct disklabel *, int)); 10624a2c1a4Smillert int get_cpg __P((struct disklabel *, int)); 10724a2c1a4Smillert int get_fsize __P((struct disklabel *, int)); 10824a2c1a4Smillert int get_fstype __P((struct disklabel *, int)); 10924a2c1a4Smillert int get_mp __P((struct disklabel *, char **, int)); 11024a2c1a4Smillert int get_offset __P((struct disklabel *, int)); 11124a2c1a4Smillert int get_size __P((struct disklabel *, int, u_int32_t *, int)); 112c33fcabaSmillert void get_geometry __P((int, struct disklabel **, struct disklabel **)); 113c33fcabaSmillert void set_geometry __P((struct disklabel *, struct disklabel *, struct disklabel *, struct disklabel *, char *)); 1149afbe9eeSmillert void zero_partitions __P((struct disklabel *, u_int32_t *)); 11596a888c6Smillert 11696a888c6Smillert static u_int32_t starting_sector; 11796a888c6Smillert static u_int32_t ending_sector; 1182d8451b0Smillert static int expert; 1196fe57b42Smillert 1206fe57b42Smillert /* from disklabel.c */ 1216fe57b42Smillert int checklabel __P((struct disklabel *)); 1226fe57b42Smillert void display __P((FILE *, struct disklabel *)); 123bd6726faSmillert void display_partition __P((FILE *, struct disklabel *, char **, int, char, int)); 124af98caf3Sderaadt int width_partition __P((struct disklabel *, int)); 125af98caf3Sderaadt 1266fe57b42Smillert struct disklabel *readlabel __P((int)); 1276fe57b42Smillert struct disklabel *makebootarea __P((char *, struct disklabel *, int)); 1286fe57b42Smillert int writelabel __P((int, char *, struct disklabel *)); 1296fe57b42Smillert extern char *bootarea, *specname; 13069220492Smillert extern int donothing; 1314793b14cSmillert #ifdef DOSLABEL 13210bddbefSmillert extern struct dos_partition *dosdp; /* DOS partition, if found */ 1334793b14cSmillert #endif 1346fe57b42Smillert 1356fe57b42Smillert /* 1366fe57b42Smillert * Simple partition editor. Primarily intended for new labels. 1376fe57b42Smillert */ 1386fe57b42Smillert int 1399785f718Smillert editor(lp, f, dev, fstabfile) 1406fe57b42Smillert struct disklabel *lp; 1416fe57b42Smillert int f; 142803ff7d5Smillert char *dev; 143bd6726faSmillert char *fstabfile; 1446fe57b42Smillert { 1456fe57b42Smillert struct disklabel lastlabel, tmplabel, label = *lp; 146c33fcabaSmillert struct disklabel *disk_geop, *bios_geop; 14796a888c6Smillert struct partition *pp; 14896a888c6Smillert u_int32_t freesectors; 1496fe57b42Smillert FILE *fp; 1506fe57b42Smillert char buf[BUFSIZ], *cmd, *arg; 151bd6726faSmillert char **mountpoints = NULL, **omountpoints, **tmpmountpoints; 152bd6726faSmillert 153bd6726faSmillert /* Alloc and init mount point info */ 154bd6726faSmillert if (fstabfile) { 155bd6726faSmillert if (!(mountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 156bd6726faSmillert !(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 157bd6726faSmillert !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *)))) 158bd6726faSmillert errx(4, "out of memory"); 159bd6726faSmillert } 1606fe57b42Smillert 16196a888c6Smillert /* Don't allow disk type of "unknown" */ 162803ff7d5Smillert getdisktype(&label, "You need to specify a type for this disk.", dev); 1636fe57b42Smillert 164c33fcabaSmillert /* Get the on-disk and BIOS geometries if possible */ 165c33fcabaSmillert get_geometry(f, &disk_geop, &bios_geop); 166c33fcabaSmillert 167d09f3941Smillert /* How big is the OpenBSD portion of the disk? */ 1689785f718Smillert find_bounds(&label, bios_geop); 169d09f3941Smillert 17096a888c6Smillert /* Set freesectors based on bounds and initial label */ 171c0bdc608Smillert editor_countfree(&label, &freesectors); 17296a888c6Smillert 17396a888c6Smillert /* Make sure there is no partition overlap. */ 17496a888c6Smillert if (has_overlap(&label, &freesectors, 1)) 1756fe57b42Smillert errx(1, "can't run when there is partition overlap."); 1766fe57b42Smillert 17796a888c6Smillert /* If we don't have a 'c' partition, create one. */ 178d09f3941Smillert pp = &label.d_partitions[RAW_PART]; 17996a888c6Smillert if (label.d_npartitions < 3 || pp->p_size == 0) { 18096a888c6Smillert puts("No 'c' partition found, adding one that spans the disk."); 18196a888c6Smillert if (label.d_npartitions < 3) 18296a888c6Smillert label.d_npartitions = 3; 18396a888c6Smillert pp->p_offset = 0; 18496a888c6Smillert pp->p_size = label.d_secperunit; 18596a888c6Smillert pp->p_fstype = FS_UNUSED; 18696a888c6Smillert pp->p_fsize = pp->p_frag = pp->p_cpg = 0; 18796a888c6Smillert } 1880f820bbbSmillert 1896fe57b42Smillert #ifdef CYLCHECK 1906fe57b42Smillert puts("This platform requires that partition offsets/sizes be on cylinder boundaries.\nPartition offsets/sizes will be rounded to the nearest cylinder automatically."); 1916fe57b42Smillert #endif 1926fe57b42Smillert 193bd6726faSmillert /* Set d_bbsize and d_sbsize as necessary */ 19455403f76Smillert if (label.d_bbsize == 0) 19555403f76Smillert label.d_bbsize = BBSIZE; 19655403f76Smillert if (label.d_sbsize == 0) 19755403f76Smillert label.d_sbsize = SBSIZE; 198f98aebd4Smillert 199440b1d70Smillert /* Interleave must be >= 1 */ 200440b1d70Smillert if (label.d_interleave == 0) 201440b1d70Smillert label.d_interleave = 1; 202440b1d70Smillert 20396a888c6Smillert puts("\nInitial label editor (enter '?' for help at any prompt)"); 2046fe57b42Smillert lastlabel = label; 2056fe57b42Smillert for (;;) { 2066fe57b42Smillert fputs("> ", stdout); 2076fe57b42Smillert fflush(stdout); 2086fe57b42Smillert rewind(stdin); 2096e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 2106e0becc5Smillert putchar('\n'); 2116e0becc5Smillert buf[0] = 'q'; 2126e0becc5Smillert buf[1] = '\0'; 2136e0becc5Smillert } 214260513deSmillert if ((cmd = strtok(buf, " \t\r\n")) == NULL) 215260513deSmillert continue; 216260513deSmillert arg = strtok(NULL, " \t\r\n"); 2176fe57b42Smillert 2186fe57b42Smillert switch (*cmd) { 2196fe57b42Smillert 2206fe57b42Smillert case '?': 221ea37abd3Sderaadt case 'h': 222617e6e4aSmillert editor_help(arg ? arg : ""); 2236fe57b42Smillert break; 2246fe57b42Smillert 2256fe57b42Smillert case 'a': 2266fe57b42Smillert tmplabel = lastlabel; 2276fe57b42Smillert lastlabel = label; 228bd6726faSmillert if (mountpoints != NULL) { 229bd6726faSmillert mpcopy(tmpmountpoints, omountpoints); 230bd6726faSmillert mpcopy(omountpoints, mountpoints); 231bd6726faSmillert } 232bd6726faSmillert editor_add(&label, mountpoints, &freesectors, arg); 23396a888c6Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 23496a888c6Smillert lastlabel = tmplabel; 235bd6726faSmillert if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints)) 236bd6726faSmillert mpcopy(omountpoints, tmpmountpoints); 23796a888c6Smillert break; 23896a888c6Smillert 23996a888c6Smillert case 'b': 24096a888c6Smillert tmplabel = lastlabel; 24196a888c6Smillert lastlabel = label; 242e8e8bdb7Sart set_bounds(&label, &freesectors); 2436fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2446fe57b42Smillert lastlabel = tmplabel; 2456fe57b42Smillert break; 2466fe57b42Smillert 2476fe57b42Smillert case 'c': 2486fe57b42Smillert tmplabel = lastlabel; 2496fe57b42Smillert lastlabel = label; 25096a888c6Smillert editor_change(&label, &freesectors, arg); 2516fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2526fe57b42Smillert lastlabel = tmplabel; 2536fe57b42Smillert break; 2546fe57b42Smillert 2559afbe9eeSmillert case 'D': 256*cdd7eb76Smillert tmplabel = lastlabel; 257*cdd7eb76Smillert lastlabel = label; 258*cdd7eb76Smillert if (ioctl(f, DIOCGPDINFO, &label) == 0) 2599afbe9eeSmillert editor_countfree(&label, &freesectors); 260*cdd7eb76Smillert else { 261*cdd7eb76Smillert warn("unable to get default partition table"); 262*cdd7eb76Smillert lastlabel = tmplabel; 263*cdd7eb76Smillert } 2649afbe9eeSmillert break; 2659afbe9eeSmillert 2666fe57b42Smillert case 'd': 2676fe57b42Smillert tmplabel = lastlabel; 2686fe57b42Smillert lastlabel = label; 269bd6726faSmillert if (mountpoints != NULL) { 270bd6726faSmillert mpcopy(tmpmountpoints, omountpoints); 271bd6726faSmillert mpcopy(omountpoints, mountpoints); 272bd6726faSmillert } 273bd6726faSmillert editor_delete(&label, mountpoints, &freesectors, arg); 2746fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2756fe57b42Smillert lastlabel = tmplabel; 276bd6726faSmillert if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints)) 277bd6726faSmillert mpcopy(omountpoints, tmpmountpoints); 2786fe57b42Smillert break; 2796fe57b42Smillert 2809afbe9eeSmillert case 'e': 2819afbe9eeSmillert tmplabel = lastlabel; 2829afbe9eeSmillert lastlabel = label; 2839afbe9eeSmillert edit_parms(&label, &freesectors); 2849afbe9eeSmillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2859afbe9eeSmillert lastlabel = tmplabel; 2869afbe9eeSmillert break; 2879afbe9eeSmillert 288c33fcabaSmillert case 'g': 289c33fcabaSmillert tmplabel = lastlabel; 290c33fcabaSmillert lastlabel = label; 291c33fcabaSmillert set_geometry(&label, disk_geop, bios_geop, lp, arg); 292c33fcabaSmillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 293c33fcabaSmillert lastlabel = tmplabel; 294c33fcabaSmillert break; 295c33fcabaSmillert 2966fe57b42Smillert case 'm': 2976fe57b42Smillert tmplabel = lastlabel; 2986fe57b42Smillert lastlabel = label; 299bd6726faSmillert if (mountpoints != NULL) { 300bd6726faSmillert mpcopy(tmpmountpoints, omountpoints); 301bd6726faSmillert mpcopy(omountpoints, mountpoints); 302bd6726faSmillert } 303bd6726faSmillert editor_modify(&label, mountpoints, &freesectors, arg); 3046fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 3056fe57b42Smillert lastlabel = tmplabel; 306bd6726faSmillert if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints)) 307bd6726faSmillert mpcopy(omountpoints, tmpmountpoints); 308bd6726faSmillert break; 309bd6726faSmillert 310bd6726faSmillert case 'n': 311bd6726faSmillert if (mountpoints == NULL) { 312bd6726faSmillert fputs("This option is not valid when run " 313bd6726faSmillert "without the -F flag.\n", stderr); 314bd6726faSmillert break; 315bd6726faSmillert } 316bd6726faSmillert mpcopy(tmpmountpoints, omountpoints); 317bd6726faSmillert mpcopy(omountpoints, mountpoints); 318bd6726faSmillert editor_name(&label, mountpoints, arg); 319bd6726faSmillert if (mpequal(omountpoints, tmpmountpoints)) 320bd6726faSmillert mpcopy(omountpoints, tmpmountpoints); 3216fe57b42Smillert break; 3226fe57b42Smillert 3236fe57b42Smillert case 'p': 324bd6726faSmillert editor_display(&label, mountpoints, &freesectors, 325bd6726faSmillert arg ? *arg : 0); 3266fe57b42Smillert break; 3276fe57b42Smillert 328508086e9Smillert case 'M': { 329508086e9Smillert sig_t opipe = signal(SIGPIPE, SIG_IGN); 330508086e9Smillert char *pager; 3315d12b01bSderaadt extern char manpage[]; 3325d12b01bSderaadt 333489bd112Spjanzen if ((pager = getenv("PAGER")) == NULL || *pager == '\0') 334508086e9Smillert pager = _PATH_LESS; 335508086e9Smillert if ((fp = popen(pager, "w")) != NULL) { 3365d12b01bSderaadt (void) fwrite(manpage, strlen(manpage), 1, fp); 3375d12b01bSderaadt pclose(fp); 338508086e9Smillert } else 339508086e9Smillert warn("unable to execute %s", pager); 340508086e9Smillert 341508086e9Smillert (void)signal(SIGPIPE, opipe); 3425d12b01bSderaadt break; 343508086e9Smillert } 3445d12b01bSderaadt 3456fe57b42Smillert case 'q': 34669220492Smillert if (donothing) { 34769220492Smillert puts("In no change mode, not writing label."); 34869220492Smillert return(1); 34969220492Smillert } 350bd6726faSmillert /* Save mountpoint info if there is any. */ 351bd6726faSmillert if (mountpoints != NULL) 352bd6726faSmillert mpsave(&label, mountpoints, dev, fstabfile); 3536fe57b42Smillert if (memcmp(lp, &label, sizeof(label)) == 0) { 354bd6726faSmillert puts("No label changes."); 3556fe57b42Smillert return(1); 3566fe57b42Smillert } 3576fe57b42Smillert do { 358d0e67762Smillert arg = getstring("Write new label?", 359d0e67762Smillert "Write the modified label to disk?", 360d0e67762Smillert "y"); 36196a888c6Smillert } while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n'); 36296a888c6Smillert if (arg && tolower(*arg) == 'y') { 363d0e67762Smillert if (writelabel(f, bootarea, &label) == 0) { 3646fe57b42Smillert *lp = label; 3656fe57b42Smillert return(0); 3666fe57b42Smillert } 367d0e67762Smillert warnx("unable to write label"); 368d0e67762Smillert } 3696fe57b42Smillert return(1); 3706fe57b42Smillert /* NOTREACHED */ 3716fe57b42Smillert break; 3726fe57b42Smillert 373c0bdc608Smillert case 'r': 374c0bdc608Smillert /* Recalculate free space */ 375c0bdc608Smillert editor_countfree(&label, &freesectors); 376c0bdc608Smillert puts("Recalculated free space."); 377c0bdc608Smillert break; 378c0bdc608Smillert 3796fe57b42Smillert case 's': 3806fe57b42Smillert if (arg == NULL) { 381c33fcabaSmillert arg = getstring("Filename", 3826fe57b42Smillert "Name of the file to save label into.", 3836fe57b42Smillert NULL); 38496a888c6Smillert if (arg == NULL && *arg == '\0') 3856fe57b42Smillert break; 3866fe57b42Smillert } 3876fe57b42Smillert if ((fp = fopen(arg, "w")) == NULL) { 3886fe57b42Smillert warn("cannot open %s", arg); 3896fe57b42Smillert } else { 3906fe57b42Smillert display(fp, &label); 3916fe57b42Smillert (void)fclose(fp); 3926fe57b42Smillert } 3936fe57b42Smillert break; 3946fe57b42Smillert 3956fe57b42Smillert case 'u': 396bd6726faSmillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0 && 397bd6726faSmillert mountpoints != NULL && 398bd6726faSmillert mpequal(mountpoints, omountpoints)) { 3996fe57b42Smillert puts("Nothing to undo!"); 4006fe57b42Smillert } else { 4016fe57b42Smillert tmplabel = label; 4026fe57b42Smillert label = lastlabel; 4036fe57b42Smillert lastlabel = tmplabel; 404c0bdc608Smillert /* Recalculate free space */ 405c0bdc608Smillert editor_countfree(&label, &freesectors); 406bd6726faSmillert /* Restore mountpoints */ 407bd6726faSmillert if (mountpoints != NULL) 408bd6726faSmillert mpcopy(mountpoints, omountpoints); 4096fe57b42Smillert puts("Last change undone."); 4106fe57b42Smillert } 4116fe57b42Smillert break; 4126fe57b42Smillert 413040947cfSmillert case 'w': 414bd6726faSmillert if (donothing) { 415040947cfSmillert puts("In no change mode, not writing label."); 416bd6726faSmillert break; 417bd6726faSmillert } 418bd6726faSmillert /* Save mountpoint info if there is any. */ 419bd6726faSmillert if (mountpoints != NULL) 420bd6726faSmillert mpsave(&label, mountpoints, dev, fstabfile); 421bd6726faSmillert /* Save label if it has changed. */ 422bd6726faSmillert if (memcmp(lp, &label, sizeof(label)) == 0) 423bd6726faSmillert puts("No label changes."); 424040947cfSmillert else if (writelabel(f, bootarea, &label) != 0) 425040947cfSmillert warnx("unable to write label"); 4265af08e9cSmillert else 4275af08e9cSmillert *lp = label; 428040947cfSmillert break; 429040947cfSmillert 4302d8451b0Smillert case 'X': 4312d8451b0Smillert expert = !expert; 4322d8451b0Smillert printf("%s expert mode\n", expert ? "Entering" : 4332d8451b0Smillert "Exiting"); 4342d8451b0Smillert break; 4352d8451b0Smillert 4366fe57b42Smillert case 'x': 4376fe57b42Smillert return(1); 4386fe57b42Smillert break; 4396fe57b42Smillert 4409afbe9eeSmillert case 'z': 441*cdd7eb76Smillert tmplabel = lastlabel; 442*cdd7eb76Smillert lastlabel = label; 4439afbe9eeSmillert zero_partitions(&label, &freesectors); 4446fe57b42Smillert break; 4456fe57b42Smillert 4469afbe9eeSmillert case '\n': 4476fe57b42Smillert break; 4486fe57b42Smillert 4496fe57b42Smillert default: 4506fe57b42Smillert printf("Unknown option: %c ('?' for help)\n", *cmd); 4516fe57b42Smillert break; 4526fe57b42Smillert } 4536fe57b42Smillert } 4546fe57b42Smillert } 4556fe57b42Smillert 4566fe57b42Smillert /* 4576fe57b42Smillert * Add a new partition. 4586fe57b42Smillert */ 4596fe57b42Smillert void 460bd6726faSmillert editor_add(lp, mp, freep, p) 4616fe57b42Smillert struct disklabel *lp; 462bd6726faSmillert char **mp; 4636fe57b42Smillert u_int32_t *freep; 4646fe57b42Smillert char *p; 4656fe57b42Smillert { 46696a888c6Smillert struct partition *pp; 46796a888c6Smillert struct diskchunk *chunks; 4686fe57b42Smillert char buf[BUFSIZ]; 4696fe57b42Smillert int i, partno; 47096a888c6Smillert u_int32_t ui, old_offset, old_size; 4716fe57b42Smillert 4726fe57b42Smillert /* XXX - prompt user to steal space from another partition instead */ 4736fe57b42Smillert if (*freep == 0) { 4746fe57b42Smillert fputs("No space left, you need to shrink a partition\n", 4756fe57b42Smillert stderr); 4766fe57b42Smillert return; 4776fe57b42Smillert } 4786fe57b42Smillert 4796fe57b42Smillert /* XXX - make more like other editor_* */ 4806fe57b42Smillert if (p != NULL) { 4816fe57b42Smillert partno = p[0] - 'a'; 4829afbe9eeSmillert if (partno < 0 || partno == RAW_PART || 4839afbe9eeSmillert partno >= MAXPARTITIONS) { 4846fe57b42Smillert fprintf(stderr, 485e6ab932bSmillert "Partition must be between 'a' and '%c' " 486e6ab932bSmillert "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1); 4876fe57b42Smillert return; 48896a888c6Smillert } else if (lp->d_partitions[partno].p_fstype != FS_UNUSED && 489f6299b35Sderaadt lp->d_partitions[partno].p_size != 0) { 490f6299b35Sderaadt fprintf(stderr, 491f6299b35Sderaadt "Partition '%c' exists. Delete it first.\n", 492f6299b35Sderaadt p[0]); 493f6299b35Sderaadt return; 4946fe57b42Smillert } 4956fe57b42Smillert } else { 4969c5f1350Smillert /* Find first unused partition that is not 'c' */ 4976fe57b42Smillert for (partno = 0; partno < MAXPARTITIONS; partno++, p++) { 4989afbe9eeSmillert if (lp->d_partitions[partno].p_size == 0 && 4999afbe9eeSmillert partno != RAW_PART) 5006fe57b42Smillert break; 5016fe57b42Smillert } 5026fe57b42Smillert if (partno < MAXPARTITIONS) { 5036fe57b42Smillert buf[0] = partno + 'a'; 5046fe57b42Smillert buf[1] = '\0'; 5056fe57b42Smillert p = &buf[0]; 5066fe57b42Smillert } else 5076fe57b42Smillert p = NULL; 5086fe57b42Smillert for (;;) { 509c33fcabaSmillert p = getstring("partition", 5106fe57b42Smillert "The letter of the new partition, a - p.", p); 51196a888c6Smillert if (p == NULL) 51296a888c6Smillert return; 5136fe57b42Smillert partno = p[0] - 'a'; 51496a888c6Smillert if (lp->d_partitions[partno].p_fstype != FS_UNUSED && 51596a888c6Smillert lp->d_partitions[partno].p_size != 0) { 51696a888c6Smillert fprintf(stderr, 51796a888c6Smillert "Partition '%c' already exists.\n", p[0]); 51896a888c6Smillert } else if (partno >= 0 && partno < MAXPARTITIONS) 5196fe57b42Smillert break; 5206fe57b42Smillert fprintf(stderr, 5216fe57b42Smillert "Partition must be between 'a' and '%c'.\n", 5226fe57b42Smillert 'a' + MAXPARTITIONS - 1); 5236fe57b42Smillert } 5246fe57b42Smillert } 52596a888c6Smillert 52696a888c6Smillert /* Increase d_npartitions if necesary */ 52796a888c6Smillert if (partno >= lp->d_npartitions) 52896a888c6Smillert lp->d_npartitions = partno + 1; 52996a888c6Smillert 53096a888c6Smillert /* Set defaults */ 5316fe57b42Smillert pp = &lp->d_partitions[partno]; 5326fe57b42Smillert if (partno >= lp->d_npartitions) 5336fe57b42Smillert lp->d_npartitions = partno + 1; 5346fe57b42Smillert memset(pp, 0, sizeof(*pp)); 5352d8451b0Smillert pp->p_size = *freep; 5362d8451b0Smillert pp->p_offset = next_offset(lp, &pp->p_size); 53796a888c6Smillert pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS; 5386fe57b42Smillert pp->p_fsize = 1024; 5396fe57b42Smillert pp->p_frag = 8; 5406fe57b42Smillert pp->p_cpg = 16; 54196a888c6Smillert old_offset = pp->p_offset; 54296a888c6Smillert old_size = pp->p_size; 54396a888c6Smillert 54496a888c6Smillert getoff1: 54596a888c6Smillert /* Get offset */ 54624a2c1a4Smillert if (get_offset(lp, partno) != 0) { 54796a888c6Smillert pp->p_size = 0; /* effective delete */ 54896a888c6Smillert return; 54996a888c6Smillert } 55096a888c6Smillert 55196a888c6Smillert /* Recompute recommended size based on new offset */ 55296a888c6Smillert ui = pp->p_fstype; 55396a888c6Smillert pp->p_fstype = FS_UNUSED; 55496a888c6Smillert chunks = free_chunks(lp); 55596a888c6Smillert for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 55696a888c6Smillert if (pp->p_offset >= chunks[i].start && 55796a888c6Smillert pp->p_offset < chunks[i].stop) { 55896a888c6Smillert pp->p_size = chunks[i].stop - pp->p_offset; 55996a888c6Smillert break; 56096a888c6Smillert } 56196a888c6Smillert } 56296a888c6Smillert pp->p_fstype = ui; 56396a888c6Smillert 56496a888c6Smillert /* Get size */ 56524a2c1a4Smillert if (get_size(lp, partno, freep, 1) != 0 || pp->p_size == 0) { 56696a888c6Smillert pp->p_size = 0; /* effective delete */ 56796a888c6Smillert return; 56896a888c6Smillert } 56996a888c6Smillert 57096a888c6Smillert /* Check for overlap */ 57196a888c6Smillert if (has_overlap(lp, freep, 0)) { 5724793b14cSmillert printf("\nPlease re-enter an offset and size for partition " 5734793b14cSmillert "%c.\n", 'a' + partno); 57496a888c6Smillert pp->p_offset = old_offset; 57596a888c6Smillert pp->p_size = old_size; 57696a888c6Smillert goto getoff1; /* Yeah, I know... */ 57796a888c6Smillert } 5786fe57b42Smillert 5797a201fc6Smillert /* Get filesystem type and mountpoint */ 5807a201fc6Smillert if (get_fstype(lp, partno) != 0 || get_mp(lp, mp, partno) != 0) { 58196a888c6Smillert pp->p_size = 0; /* effective delete */ 58296a888c6Smillert return; 5836fe57b42Smillert } 5846fe57b42Smillert 5852d8451b0Smillert if (expert && pp->p_fstype == FS_BSDFFS) { 5867a201fc6Smillert /* Get fsize, bsize, and cpg */ 5877a201fc6Smillert if (get_fsize(lp, partno) != 0 || get_bsize(lp, partno) != 0 || 5887a201fc6Smillert get_cpg(lp, partno) != 0) { 58996a888c6Smillert pp->p_size = 0; /* effective delete */ 59096a888c6Smillert return; 5916fe57b42Smillert } 5926fe57b42Smillert } 59324a2c1a4Smillert 59496a888c6Smillert /* Update free sector count and make sure things stay contiguous. */ 5956fe57b42Smillert *freep -= pp->p_size; 59696a888c6Smillert if (pp->p_size + pp->p_offset > ending_sector || 59796a888c6Smillert has_overlap(lp, freep, -1)) 5986fe57b42Smillert make_contiguous(lp); 5996fe57b42Smillert } 6006fe57b42Smillert 6016fe57b42Smillert /* 602bd6726faSmillert * Set the mountpoint of an existing partition ('name'). 603bd6726faSmillert */ 604bd6726faSmillert void 605bd6726faSmillert editor_name(lp, mp, p) 606bd6726faSmillert struct disklabel *lp; 607bd6726faSmillert char **mp; 608bd6726faSmillert char *p; 609bd6726faSmillert { 610bd6726faSmillert struct partition *pp; 611bd6726faSmillert int partno; 612bd6726faSmillert 613bd6726faSmillert /* Change which partition? */ 614bd6726faSmillert if (p == NULL) { 615c33fcabaSmillert p = getstring("partition to name", 616bd6726faSmillert "The letter of the partition to name, a - p.", NULL); 617bd6726faSmillert } 618bd6726faSmillert if (p == NULL) { 619bd6726faSmillert fputs("Command aborted\n", stderr); 620bd6726faSmillert return; 621bd6726faSmillert } 622bd6726faSmillert partno = p[0] - 'a'; 623bd6726faSmillert pp = &lp->d_partitions[partno]; 624bd6726faSmillert if (partno < 0 || partno >= lp->d_npartitions) { 625bd6726faSmillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 626bd6726faSmillert 'a' + lp->d_npartitions - 1); 627bd6726faSmillert return; 628bd6726faSmillert } else if (partno >= lp->d_npartitions || 629bd6726faSmillert (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) { 630bd6726faSmillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno); 631bd6726faSmillert return; 632bd6726faSmillert } 633bd6726faSmillert 634bd6726faSmillert /* Not all fstypes can be named */ 635bd6726faSmillert if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP || 636bd6726faSmillert pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER) { 637bd6726faSmillert fprintf(stderr, "You cannot name a filesystem of type %s.\n", 638baa55472Smillert fstypenames[lp->d_partitions[partno].p_fstype]); 639bd6726faSmillert return; 640bd6726faSmillert } 641bd6726faSmillert 642ddaff619Smillert get_mp(lp, mp, partno); 643bd6726faSmillert } 644bd6726faSmillert 645bd6726faSmillert /* 6466fe57b42Smillert * Change an existing partition. 6476fe57b42Smillert */ 6486fe57b42Smillert void 649bd6726faSmillert editor_modify(lp, mp, freep, p) 6506fe57b42Smillert struct disklabel *lp; 651bd6726faSmillert char **mp; 6526fe57b42Smillert u_int32_t *freep; 6536fe57b42Smillert char *p; 6546fe57b42Smillert { 6556fe57b42Smillert struct partition origpart, *pp; 6566fe57b42Smillert int partno; 6576fe57b42Smillert 6586fe57b42Smillert /* Change which partition? */ 6596fe57b42Smillert if (p == NULL) { 660c33fcabaSmillert p = getstring("partition to modify", 6616fe57b42Smillert "The letter of the partition to modify, a - p.", NULL); 6626fe57b42Smillert } 66396a888c6Smillert if (p == NULL) { 66496a888c6Smillert fputs("Command aborted\n", stderr); 66596a888c6Smillert return; 66696a888c6Smillert } 6676fe57b42Smillert partno = p[0] - 'a'; 6686fe57b42Smillert pp = &lp->d_partitions[partno]; 6696fe57b42Smillert origpart = lp->d_partitions[partno]; 6706fe57b42Smillert if (partno < 0 || partno >= lp->d_npartitions) { 6716fe57b42Smillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 6726fe57b42Smillert 'a' + lp->d_npartitions - 1); 6736fe57b42Smillert return; 6746fe57b42Smillert } else if (partno >= lp->d_npartitions || 6756fe57b42Smillert (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) { 6766fe57b42Smillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno); 6776fe57b42Smillert return; 6786fe57b42Smillert } 6796fe57b42Smillert 6806fe57b42Smillert /* Get filesystem type */ 68124a2c1a4Smillert if (get_fstype(lp, partno) != 0) { 68224a2c1a4Smillert *pp = origpart; /* undo changes */ 68396a888c6Smillert return; 68496a888c6Smillert } 6856fe57b42Smillert 6866fe57b42Smillert /* Did they disable/enable the partition? */ 687229f463eSmillert if ((pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) && 688229f463eSmillert origpart.p_fstype != FS_UNUSED && origpart.p_fstype != FS_BOOT) 6896fe57b42Smillert *freep += origpart.p_size; 690229f463eSmillert else if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT && 691229f463eSmillert (origpart.p_fstype == FS_UNUSED || origpart.p_fstype == FS_BOOT)) { 6926fe57b42Smillert if (pp->p_size > *freep) { 6936fe57b42Smillert fprintf(stderr, 69496a888c6Smillert "Warning, need %u sectors but there are only %u " 6956fe57b42Smillert "free. Setting size to %u.\n", pp->p_size, *freep, 6966fe57b42Smillert *freep); 6976fe57b42Smillert pp->p_fstype = *freep; 6986fe57b42Smillert *freep = 0; 6996fe57b42Smillert } else 7006fe57b42Smillert *freep -= pp->p_size; /* have enough space */ 7016fe57b42Smillert } 7026fe57b42Smillert 7036fe57b42Smillert getoff2: 7046fe57b42Smillert /* Get offset */ 70524a2c1a4Smillert if (get_offset(lp, partno) != 0) { 70696a888c6Smillert *pp = origpart; /* undo changes */ 70796a888c6Smillert return; 7086fe57b42Smillert } 7096fe57b42Smillert 7106fe57b42Smillert /* Get size */ 71124a2c1a4Smillert if (get_size(lp, partno, freep, 0) != 0 || pp->p_size == 0) { 71224a2c1a4Smillert pp->p_size = 0; /* effective delete */ 71396a888c6Smillert return; 7146fe57b42Smillert } 7156fe57b42Smillert 7166fe57b42Smillert /* Check for overlap and restore if not resolved */ 7176fe57b42Smillert if (has_overlap(lp, freep, 0)) { 7186fe57b42Smillert puts("\nPlease re-enter an offset and size"); 7196fe57b42Smillert pp->p_offset = origpart.p_offset; 7206fe57b42Smillert pp->p_size = origpart.p_size; 7216fe57b42Smillert goto getoff2; /* Yeah, I know... */ 7226fe57b42Smillert } 7236fe57b42Smillert 7247a201fc6Smillert /* get mount point */ 7257a201fc6Smillert if (get_mp(lp, mp, partno) != 0) { 7267a201fc6Smillert *pp = origpart; /* undo changes */ 7277a201fc6Smillert return; 7287a201fc6Smillert } 7297a201fc6Smillert 7302d8451b0Smillert if (expert && (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED)){ 7316fe57b42Smillert /* get fsize */ 73224a2c1a4Smillert if (get_fsize(lp, partno) != 0) { 73396a888c6Smillert *pp = origpart; /* undo changes */ 73496a888c6Smillert return; 7356fe57b42Smillert } 7366fe57b42Smillert 7376fe57b42Smillert /* get bsize */ 73824a2c1a4Smillert if (get_bsize(lp, partno) != 0) { 73996a888c6Smillert *pp = origpart; /* undo changes */ 74096a888c6Smillert return; 7416fe57b42Smillert } 7426fe57b42Smillert 7436fe57b42Smillert if (pp->p_fstype == FS_BSDFFS) { 7446fe57b42Smillert /* get cpg */ 74524a2c1a4Smillert if (get_cpg(lp, partno) != 0) { 74696a888c6Smillert *pp = origpart; /* undo changes */ 74796a888c6Smillert return; 7486fe57b42Smillert } 7496fe57b42Smillert } 7506fe57b42Smillert } 7516fe57b42Smillert 7526fe57b42Smillert /* Make sure things stay contiguous. */ 75396a888c6Smillert if (pp->p_size + pp->p_offset > ending_sector || 75496a888c6Smillert has_overlap(lp, freep, -1)) 7556fe57b42Smillert make_contiguous(lp); 7566fe57b42Smillert } 7576fe57b42Smillert 7586fe57b42Smillert /* 7596fe57b42Smillert * Delete an existing partition. 7606fe57b42Smillert */ 7616fe57b42Smillert void 762bd6726faSmillert editor_delete(lp, mp, freep, p) 7636fe57b42Smillert struct disklabel *lp; 764bd6726faSmillert char **mp; 7656fe57b42Smillert u_int32_t *freep; 7666fe57b42Smillert char *p; 7676fe57b42Smillert { 7686fe57b42Smillert int c; 7696fe57b42Smillert 7706fe57b42Smillert if (p == NULL) { 771c33fcabaSmillert p = getstring("partition to delete", 772945ae268Smillert "The letter of the partition to delete, a - p, or '*'.", 773945ae268Smillert NULL); 7746fe57b42Smillert } 77596a888c6Smillert if (p == NULL) { 77696a888c6Smillert fputs("Command aborted\n", stderr); 77796a888c6Smillert return; 77896a888c6Smillert } 779945ae268Smillert if (p[0] == '*') { 780945ae268Smillert for (c = 0; c < lp->d_npartitions; c++) { 7819afbe9eeSmillert if (c == RAW_PART) 782945ae268Smillert continue; 783945ae268Smillert 784945ae268Smillert /* Update free sector count. */ 785945ae268Smillert if (lp->d_partitions[c].p_fstype != FS_UNUSED && 786945ae268Smillert lp->d_partitions[c].p_fstype != FS_BOOT && 787945ae268Smillert lp->d_partitions[c].p_size != 0) 788945ae268Smillert *freep += lp->d_partitions[c].p_size; 789945ae268Smillert 790945ae268Smillert (void)memset(&lp->d_partitions[c], 0, 791945ae268Smillert sizeof(lp->d_partitions[c])); 792945ae268Smillert } 793945ae268Smillert return; 794945ae268Smillert } 7956fe57b42Smillert c = p[0] - 'a'; 7966fe57b42Smillert if (c < 0 || c >= lp->d_npartitions) 7976fe57b42Smillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 7986fe57b42Smillert 'a' + lp->d_npartitions - 1); 7996fe57b42Smillert else if (c >= lp->d_npartitions || (lp->d_partitions[c].p_fstype == 8006fe57b42Smillert FS_UNUSED && lp->d_partitions[c].p_size == 0)) 8016fe57b42Smillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + c); 8029afbe9eeSmillert else if (c == RAW_PART) 803617e6e4aSmillert fputs( 804617e6e4aSmillert "You may not delete the 'c' partition. The 'c' partition must exist and\n" 805617e6e4aSmillert "should span the entire disk. By default it is of type 'unused' and so\n" 806617e6e4aSmillert "does not take up any space.\n", stderr); 8076fe57b42Smillert else { 80896a888c6Smillert /* Update free sector count. */ 809e49c5d78Smillert if (lp->d_partitions[c].p_offset < ending_sector && 810e49c5d78Smillert lp->d_partitions[c].p_offset >= starting_sector && 811e49c5d78Smillert lp->d_partitions[c].p_fstype != FS_UNUSED && 812229f463eSmillert lp->d_partitions[c].p_fstype != FS_BOOT && 8136fe57b42Smillert lp->d_partitions[c].p_size != 0) 8146fe57b42Smillert *freep += lp->d_partitions[c].p_size; 8156fe57b42Smillert 8166fe57b42Smillert /* Really delete it (as opposed to just setting to "unused") */ 8176fe57b42Smillert (void)memset(&lp->d_partitions[c], 0, 8186fe57b42Smillert sizeof(lp->d_partitions[c])); 8196fe57b42Smillert } 820bd6726faSmillert if (mp != NULL && mp[c] != NULL) { 821bd6726faSmillert free(mp[c]); 822bd6726faSmillert mp[c] = NULL; 823bd6726faSmillert } 8246fe57b42Smillert } 8256fe57b42Smillert 8266fe57b42Smillert /* 8276fe57b42Smillert * Simplified display() for use with the builtin editor. 8286fe57b42Smillert */ 8296fe57b42Smillert void 830bd6726faSmillert editor_display(lp, mp, freep, unit) 8316fe57b42Smillert struct disklabel *lp; 832bd6726faSmillert char **mp; 8336fe57b42Smillert u_int32_t *freep; 8346fe57b42Smillert char unit; 8356fe57b42Smillert { 8366fe57b42Smillert int i; 837af98caf3Sderaadt int width; 8386fe57b42Smillert 8396fe57b42Smillert printf("device: %s\n", specname); 8400f820bbbSmillert printf("type: %s\n", dktypenames[lp->d_type]); 8416fe57b42Smillert printf("disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename); 8426fe57b42Smillert printf("label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname); 8436fe57b42Smillert printf("bytes/sector: %ld\n", (long)lp->d_secsize); 8446fe57b42Smillert printf("sectors/track: %ld\n", (long)lp->d_nsectors); 8456fe57b42Smillert printf("tracks/cylinder: %ld\n", (long)lp->d_ntracks); 8466fe57b42Smillert printf("sectors/cylinder: %ld\n", (long)lp->d_secpercyl); 8476fe57b42Smillert printf("cylinders: %ld\n", (long)lp->d_ncylinders); 8486fe57b42Smillert printf("total sectors: %ld\n", (long)lp->d_secperunit); 8496fe57b42Smillert printf("free sectors: %u\n", *freep); 8506fe57b42Smillert printf("rpm: %ld\n", (long)lp->d_rpm); 8516fe57b42Smillert printf("\n%d partitions:\n", lp->d_npartitions); 852af98caf3Sderaadt width = width_partition(lp, unit); 853af98caf3Sderaadt printf("# %*.*s %*.*s fstype [fsize bsize cpg]\n", 854af98caf3Sderaadt width, width, "size", width, width, "offset"); 8556fe57b42Smillert for (i = 0; i < lp->d_npartitions; i++) 856bd6726faSmillert display_partition(stdout, lp, mp, i, unit, width); 8576fe57b42Smillert } 8586fe57b42Smillert 8596fe57b42Smillert /* 8606fe57b42Smillert * Find the next reasonable starting offset and returns it. 86196a888c6Smillert * Assumes there is a least one free sector left (returns 0 if not). 8626fe57b42Smillert */ 8636fe57b42Smillert u_int32_t 8642d8451b0Smillert next_offset(lp, sizep) 8656fe57b42Smillert struct disklabel *lp; 8662d8451b0Smillert u_int32_t *sizep; 8676fe57b42Smillert { 868f0b4d0a9Smillert struct partition **spp; 86996a888c6Smillert struct diskchunk *chunks; 870f0b4d0a9Smillert u_int16_t npartitions; 87196a888c6Smillert u_int32_t new_offset, new_size; 87296a888c6Smillert int i, good_offset; 8736fe57b42Smillert 874a7e61405Smillert /* Get a sorted list of the partitions */ 87596a888c6Smillert if ((spp = sort_partitions(lp, &npartitions)) == NULL) 8762d8451b0Smillert return(starting_sector); 877f0b4d0a9Smillert 87896a888c6Smillert new_offset = starting_sector; 879f0b4d0a9Smillert for (i = 0; i < npartitions; i++ ) { 8806fe57b42Smillert /* 8816fe57b42Smillert * Is new_offset inside this partition? If so, 88296a888c6Smillert * make it the next sector after the partition ends. 8836fe57b42Smillert */ 8844793b14cSmillert if (spp[i]->p_offset + spp[i]->p_size < ending_sector && 8854793b14cSmillert ((new_offset >= spp[i]->p_offset && 88696a888c6Smillert new_offset < spp[i]->p_offset + spp[i]->p_size) || 8872d8451b0Smillert (new_offset + *sizep >= spp[i]->p_offset && new_offset 8882d8451b0Smillert + *sizep <= spp[i]->p_offset + spp[i]->p_size))) 889f0b4d0a9Smillert new_offset = spp[i]->p_offset + spp[i]->p_size; 8906fe57b42Smillert } 8916fe57b42Smillert 89296a888c6Smillert /* Did we find a suitable offset? */ 89396a888c6Smillert for (good_offset = 1, i = 0; i < npartitions; i++ ) { 8942d8451b0Smillert if (new_offset + *sizep >= spp[i]->p_offset && 8952d8451b0Smillert new_offset + *sizep <= spp[i]->p_offset + spp[i]->p_size) { 89696a888c6Smillert /* Nope */ 89796a888c6Smillert good_offset = 0; 89896a888c6Smillert break; 89996a888c6Smillert } 90096a888c6Smillert } 90196a888c6Smillert 90296a888c6Smillert /* Specified size is too big, find something that fits */ 90396a888c6Smillert if (!good_offset) { 90496a888c6Smillert chunks = free_chunks(lp); 90596a888c6Smillert new_size = 0; 90696a888c6Smillert for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 90796a888c6Smillert if (chunks[i].stop - chunks[i].start > new_size) { 90896a888c6Smillert new_size = chunks[i].stop - chunks[i].start; 90996a888c6Smillert new_offset = chunks[i].start; 91096a888c6Smillert } 91196a888c6Smillert } 9124793b14cSmillert /* XXX - should do something intelligent if new_size == 0 */ 9132d8451b0Smillert *sizep = new_size; 91496a888c6Smillert } 91596a888c6Smillert 916f0b4d0a9Smillert (void)free(spp); 9176fe57b42Smillert return(new_offset); 9186fe57b42Smillert } 9196fe57b42Smillert 9206fe57b42Smillert /* 9216fe57b42Smillert * Change the size of an existing partition. 9226fe57b42Smillert */ 9236fe57b42Smillert void 9246fe57b42Smillert editor_change(lp, freep, p) 9256fe57b42Smillert struct disklabel *lp; 9266fe57b42Smillert u_int32_t *freep; 9276fe57b42Smillert char *p; 9286fe57b42Smillert { 9296fe57b42Smillert int partno; 9306fe57b42Smillert u_int32_t newsize; 9314b9a3bdaSmillert struct partition *pp; 9326fe57b42Smillert 9336fe57b42Smillert if (p == NULL) { 934c33fcabaSmillert p = getstring("partition to change size", 9356fe57b42Smillert "The letter of the partition to change size, a - p.", NULL); 9366fe57b42Smillert } 93796a888c6Smillert if (p == NULL) { 93896a888c6Smillert fputs("Command aborted\n", stderr); 93996a888c6Smillert return; 94096a888c6Smillert } 9416fe57b42Smillert partno = p[0] - 'a'; 9426fe57b42Smillert if (partno < 0 || partno >= lp->d_npartitions) { 9436fe57b42Smillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 9446fe57b42Smillert 'a' + lp->d_npartitions - 1); 9456fe57b42Smillert return; 9466fe57b42Smillert } else if (partno >= lp->d_npartitions || 947229f463eSmillert lp->d_partitions[partno].p_size == 0) { 9486fe57b42Smillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno); 9496fe57b42Smillert return; 9506fe57b42Smillert } 9514b9a3bdaSmillert pp = &lp->d_partitions[partno]; 9526fe57b42Smillert 9536fe57b42Smillert printf("Partition %c is currently %u sectors in size (%u free).\n", 9544b9a3bdaSmillert partno + 'a', pp->p_size, *freep); 955229f463eSmillert /* XXX - make maxsize lp->d_secperunit if FS_UNUSED/FS_BOOT? */ 9566fe57b42Smillert newsize = getuint(lp, partno, "new size", "Size of the partition. " 9576fe57b42Smillert "You may also say +/- amount for a relative change.", 9584b9a3bdaSmillert pp->p_size, pp->p_size + *freep, pp->p_offset, DO_CONVERSIONS | 9594b9a3bdaSmillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 96096a888c6Smillert if (newsize == UINT_MAX - 1) { 96196a888c6Smillert fputs("Command aborted\n", stderr); 96296a888c6Smillert return; 96396a888c6Smillert } else if (newsize == UINT_MAX) { 9646fe57b42Smillert fputs("Invalid entry\n", stderr); 9656fe57b42Smillert return; 9664b9a3bdaSmillert } else if (newsize == pp->p_size) 9676fe57b42Smillert return; 9686fe57b42Smillert 9694b9a3bdaSmillert if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT) { 9704b9a3bdaSmillert if (newsize > pp->p_size) { 9714b9a3bdaSmillert if (newsize - pp->p_size > *freep) { 9726fe57b42Smillert fprintf(stderr, 9736fe57b42Smillert "Only %u sectors free, you asked for %u\n", 9744b9a3bdaSmillert *freep, newsize - pp->p_size); 9756fe57b42Smillert return; 9766fe57b42Smillert } 9774b9a3bdaSmillert *freep -= newsize - pp->p_size; 9784b9a3bdaSmillert } else if (newsize < pp->p_size) { 9794b9a3bdaSmillert *freep += pp->p_size - newsize; 9806fe57b42Smillert } 9816fe57b42Smillert } else { 9829afbe9eeSmillert if (partno == RAW_PART && newsize + 9834b9a3bdaSmillert pp->p_offset > lp->d_secperunit) { 9846fe57b42Smillert fputs("'c' partition may not be larger than the disk\n", 9856fe57b42Smillert stderr); 9866fe57b42Smillert return; 9876fe57b42Smillert } 9886fe57b42Smillert } 9894b9a3bdaSmillert pp->p_size = newsize; 9904b9a3bdaSmillert if (newsize + pp->p_offset > ending_sector || 99196a888c6Smillert has_overlap(lp, freep, -1)) 9926fe57b42Smillert make_contiguous(lp); 9936fe57b42Smillert } 9946fe57b42Smillert 9956fe57b42Smillert void 9966fe57b42Smillert make_contiguous(lp) 9976fe57b42Smillert struct disklabel *lp; 9986fe57b42Smillert { 9996fe57b42Smillert struct partition **spp; 10006fe57b42Smillert u_int16_t npartitions; 10016fe57b42Smillert int i; 10026fe57b42Smillert 1003a7e61405Smillert /* Get a sorted list of the partitions */ 100496a888c6Smillert if ((spp = sort_partitions(lp, &npartitions)) == NULL) 100596a888c6Smillert return; 10066fe57b42Smillert 10076fe57b42Smillert /* 1008a7e61405Smillert * Make everything contiguous but don't muck with start of the first one 100996a888c6Smillert * or partitions not in the BSD part of the label. 10106fe57b42Smillert */ 101196a888c6Smillert for (i = 1; i < npartitions; i++) { 101296a888c6Smillert if (spp[i]->p_offset >= starting_sector || 101396a888c6Smillert spp[i]->p_offset < ending_sector) 101496a888c6Smillert spp[i]->p_offset = 101596a888c6Smillert spp[i - 1]->p_offset + spp[i - 1]->p_size; 101696a888c6Smillert } 1017f0b4d0a9Smillert 1018f0b4d0a9Smillert (void)free(spp); 10196fe57b42Smillert } 10206fe57b42Smillert 10216fe57b42Smillert /* 10226fe57b42Smillert * Sort the partitions based on starting offset. 10236fe57b42Smillert * This assumes there can be no overlap. 10246fe57b42Smillert */ 10256fe57b42Smillert int 10266fe57b42Smillert partition_cmp(e1, e2) 10276fe57b42Smillert const void *e1, *e2; 10286fe57b42Smillert { 10296fe57b42Smillert struct partition *p1 = *(struct partition **)e1; 10306fe57b42Smillert struct partition *p2 = *(struct partition **)e2; 10316fe57b42Smillert 10326fe57b42Smillert return((int)(p1->p_offset - p2->p_offset)); 10336fe57b42Smillert } 10346fe57b42Smillert 10356fe57b42Smillert char * 1036c33fcabaSmillert getstring(prompt, helpstring, oval) 10376fe57b42Smillert char *prompt; 10386fe57b42Smillert char *helpstring; 10396fe57b42Smillert char *oval; 10406fe57b42Smillert { 10416fe57b42Smillert static char buf[BUFSIZ]; 10426fe57b42Smillert int n; 10436fe57b42Smillert 10446fe57b42Smillert buf[0] = '\0'; 10456fe57b42Smillert do { 10466fe57b42Smillert printf("%s: [%s] ", prompt, oval ? oval : ""); 10476fe57b42Smillert fflush(stdout); 10486fe57b42Smillert rewind(stdin); 10496e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1050260513deSmillert buf[0] = '\0'; 105196a888c6Smillert if (feof(stdin)) { 105296a888c6Smillert putchar('\n'); 105396a888c6Smillert return(NULL); 105496a888c6Smillert } 10556e0becc5Smillert } 10566fe57b42Smillert n = strlen(buf); 10576fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 10586fe57b42Smillert buf[--n] = '\0'; 10596fe57b42Smillert if (buf[0] == '?') 10606fe57b42Smillert puts(helpstring); 10616fe57b42Smillert else if (oval != NULL && buf[0] == '\0') { 10626fe57b42Smillert (void)strncpy(buf, oval, sizeof(buf) - 1); 10636fe57b42Smillert buf[sizeof(buf) - 1] = '\0'; 10646fe57b42Smillert } 10656fe57b42Smillert } while (buf[0] == '?'); 10666fe57b42Smillert 10676fe57b42Smillert return(&buf[0]); 10686fe57b42Smillert } 10696fe57b42Smillert 10706fe57b42Smillert /* 10716fe57b42Smillert * Returns UINT_MAX on error 107224a2c1a4Smillert * Usually only called by helper functions. 10736fe57b42Smillert */ 10746fe57b42Smillert u_int32_t 10754b9a3bdaSmillert getuint(lp, partno, prompt, helpstring, oval, maxval, offset, flags) 10766fe57b42Smillert struct disklabel *lp; 10776fe57b42Smillert int partno; 10786fe57b42Smillert char *prompt; 10796fe57b42Smillert char *helpstring; 10806fe57b42Smillert u_int32_t oval; 10816fe57b42Smillert u_int32_t maxval; /* XXX - used inconsistently */ 10824b9a3bdaSmillert u_int32_t offset; 10836fe57b42Smillert int flags; 10846fe57b42Smillert { 10856fe57b42Smillert char buf[BUFSIZ], *endptr, *p, operator = '\0'; 10866fe57b42Smillert u_int32_t rval = oval; 10876fe57b42Smillert size_t n; 10886fe57b42Smillert int mult = 1; 108996a888c6Smillert double d; 10906fe57b42Smillert 10914b9a3bdaSmillert /* We only care about the remainder */ 10924b9a3bdaSmillert offset = offset % lp->d_secpercyl; 10934b9a3bdaSmillert 10946fe57b42Smillert buf[0] = '\0'; 10956fe57b42Smillert do { 10966fe57b42Smillert printf("%s: [%u] ", prompt, oval); 10976fe57b42Smillert fflush(stdout); 10986fe57b42Smillert rewind(stdin); 10996e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 11006e0becc5Smillert buf[0] = '\0'; 110196a888c6Smillert if (feof(stdin)) { 110296a888c6Smillert putchar('\n'); 110396a888c6Smillert return(UINT_MAX - 1); 110496a888c6Smillert } 11056e0becc5Smillert } 11066fe57b42Smillert n = strlen(buf); 11076fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 11086fe57b42Smillert buf[--n] = '\0'; 11096fe57b42Smillert if (buf[0] == '?') 11106fe57b42Smillert puts(helpstring); 11116fe57b42Smillert } while (buf[0] == '?'); 11126fe57b42Smillert 11136fe57b42Smillert if (buf[0] == '*' && buf[1] == '\0') { 11146fe57b42Smillert rval = maxval; 11156fe57b42Smillert } else { 11166fe57b42Smillert /* deal with units */ 11176fe57b42Smillert if (buf[0] != '\0' && n > 0) { 11186fe57b42Smillert if ((flags & DO_CONVERSIONS)) { 111996a888c6Smillert switch (tolower(buf[n-1])) { 11206fe57b42Smillert 11216fe57b42Smillert case 'c': 11226fe57b42Smillert mult = lp->d_secpercyl; 11236fe57b42Smillert buf[--n] = '\0'; 11246fe57b42Smillert break; 11256fe57b42Smillert case 'b': 11266fe57b42Smillert mult = -lp->d_secsize; 11276fe57b42Smillert buf[--n] = '\0'; 11286fe57b42Smillert break; 11296fe57b42Smillert case 'k': 11306fe57b42Smillert mult = 1024 / lp->d_secsize; 11316fe57b42Smillert buf[--n] = '\0'; 11326fe57b42Smillert break; 11336fe57b42Smillert case 'm': 11346fe57b42Smillert mult = 1048576 / lp->d_secsize; 11356fe57b42Smillert buf[--n] = '\0'; 11366fe57b42Smillert break; 11371a51a1eeSmillert case 'g': 11381a51a1eeSmillert mult = 1073741824 / lp->d_secsize; 11391a51a1eeSmillert buf[--n] = '\0'; 11401a51a1eeSmillert break; 11416fe57b42Smillert } 114296a888c6Smillert } 11436fe57b42Smillert 11446fe57b42Smillert /* Did they give us an operator? */ 11456fe57b42Smillert p = &buf[0]; 11466fe57b42Smillert if (*p == '+' || *p == '-') 11476fe57b42Smillert operator = *p++; 11486fe57b42Smillert 11496fe57b42Smillert endptr = p; 115096a888c6Smillert errno = 0; 115196a888c6Smillert d = strtod(p, &endptr); 115296a888c6Smillert if (errno == ERANGE) 115396a888c6Smillert rval = UINT_MAX; /* too big/small */ 115496a888c6Smillert else if (*endptr != '\0') { 11556fe57b42Smillert errno = EINVAL; /* non-numbers in str */ 11566fe57b42Smillert rval = UINT_MAX; 11576fe57b42Smillert } else { 115896a888c6Smillert /* XXX - should check for overflow */ 115996a888c6Smillert if (mult > 0) 116096a888c6Smillert rval = d * mult; 116196a888c6Smillert else 116296a888c6Smillert /* Negative mult means divide (fancy) */ 116396a888c6Smillert rval = d / (-mult); 11646fe57b42Smillert 116596a888c6Smillert /* Apply the operator */ 11666fe57b42Smillert if (operator == '+') 11676fe57b42Smillert rval += oval; 11686fe57b42Smillert else if (operator == '-') 11696fe57b42Smillert rval = oval - rval; 11706fe57b42Smillert } 11716fe57b42Smillert } 11726fe57b42Smillert } 11736fe57b42Smillert if ((flags & DO_ROUNDING) && rval < UINT_MAX) { 1174dbffb156Smillert #ifndef CYLCHECK 117596a888c6Smillert /* Round to nearest cylinder unless given in sectors */ 1176dbffb156Smillert if (mult != 1) 1177dbffb156Smillert #endif 1178dbffb156Smillert { 1179dbffb156Smillert u_int32_t cyls; 1180dbffb156Smillert 1181dbffb156Smillert /* If we round up past the end, round down instead */ 11826fe57b42Smillert cyls = (u_int32_t)((rval / (double)lp->d_secpercyl) 11836fe57b42Smillert + 0.5); 11844b9a3bdaSmillert if (cyls != 0 && lp->d_secpercyl != 0) { 11854b9a3bdaSmillert if ((cyls * lp->d_secpercyl) - offset > maxval) 1186dbffb156Smillert cyls--; 1187dbffb156Smillert 11884b9a3bdaSmillert if (rval != (cyls * lp->d_secpercyl) - offset) { 11894b9a3bdaSmillert rval = (cyls * lp->d_secpercyl) - offset; 11906fe57b42Smillert printf("Rounding to nearest cylinder: %u\n", 11916fe57b42Smillert rval); 11926fe57b42Smillert } 11936fe57b42Smillert } 11946fe57b42Smillert } 11954b9a3bdaSmillert } 11966fe57b42Smillert 11976fe57b42Smillert return(rval); 11986fe57b42Smillert } 11996fe57b42Smillert 12006fe57b42Smillert /* 12016fe57b42Smillert * Check for partition overlap in lp and prompt the user 12026fe57b42Smillert * to resolve the overlap if any is found. Returns 1 12036fe57b42Smillert * if unable to resolve, else 0. 12046fe57b42Smillert */ 12056fe57b42Smillert int 12066fe57b42Smillert has_overlap(lp, freep, resolve) 12076fe57b42Smillert struct disklabel *lp; 12086fe57b42Smillert u_int32_t *freep; 12096fe57b42Smillert int resolve; 12106fe57b42Smillert { 12116fe57b42Smillert struct partition **spp; 12126fe57b42Smillert u_int16_t npartitions; 1213e6aa8bafSmillert int c, i, j; 1214e6aa8bafSmillert char buf[BUFSIZ]; 12156fe57b42Smillert 1216a7e61405Smillert /* Get a sorted list of the partitions */ 1217a7e61405Smillert spp = sort_partitions(lp, &npartitions); 12186fe57b42Smillert 12199afbe9eeSmillert if (npartitions < RAW_PART) { 1220a7e61405Smillert (void)free(spp); 12216fe57b42Smillert return(0); /* nothing to do */ 12226fe57b42Smillert } 12236fe57b42Smillert 12246fe57b42Smillert /* Now that we have things sorted by starting sector check overlap */ 12256fe57b42Smillert for (i = 0; i < npartitions; i++) { 12266fe57b42Smillert for (j = i + 1; j < npartitions; j++) { 12276fe57b42Smillert /* `if last_sec_in_part + 1 > first_sec_in_next_part' */ 12286fe57b42Smillert if (spp[i]->p_offset + spp[i]->p_size > spp[j]->p_offset) { 122996a888c6Smillert /* Don't print, just return */ 123096a888c6Smillert if (resolve == -1) { 123196a888c6Smillert (void)free(spp); 123296a888c6Smillert return(1); 123396a888c6Smillert } 123496a888c6Smillert 12356fe57b42Smillert /* Overlap! Convert to real part numbers. */ 12366fe57b42Smillert i = ((char *)spp[i] - (char *)lp->d_partitions) 12376fe57b42Smillert / sizeof(**spp); 12386fe57b42Smillert j = ((char *)spp[j] - (char *)lp->d_partitions) 12396fe57b42Smillert / sizeof(**spp); 12406fe57b42Smillert printf("\nError, partitions %c and %c overlap:\n", 12416fe57b42Smillert 'a' + i, 'a' + j); 12426fe57b42Smillert puts(" size offset fstype [fsize bsize cpg]"); 1243bd6726faSmillert display_partition(stdout, lp, NULL, i, 0, 0); 1244bd6726faSmillert display_partition(stdout, lp, NULL, j, 0, 0); 12456fe57b42Smillert 12466fe57b42Smillert /* Did they ask us to resolve it ourselves? */ 124796a888c6Smillert if (resolve != 1) { 1248f0b4d0a9Smillert (void)free(spp); 12496fe57b42Smillert return(1); 1250f0b4d0a9Smillert } 12516fe57b42Smillert 1252e6aa8bafSmillert /* Get partition to disable or ^D */ 1253e6aa8bafSmillert do { 1254616cd1c4Smillert printf("Disable which one? (^D to abort) [%c %c] ", 12556fe57b42Smillert 'a' + i, 'a' + j); 1256e6aa8bafSmillert buf[0] = '\0'; 1257616cd1c4Smillert if (!fgets(buf, sizeof(buf), stdin)) { 1258616cd1c4Smillert putchar('\n'); 1259e6aa8bafSmillert return(1); /* ^D */ 1260616cd1c4Smillert } 1261e6aa8bafSmillert c = buf[0] - 'a'; 1262e6aa8bafSmillert } while (buf[1] != '\n' && buf[1] != '\0' && 1263e6aa8bafSmillert c != i && c != j); 1264e6aa8bafSmillert 1265e6aa8bafSmillert /* Mark the selected one as unused */ 12666fe57b42Smillert lp->d_partitions[c].p_fstype = FS_UNUSED; 12676fe57b42Smillert *freep += lp->d_partitions[c].p_size; 1268e6aa8bafSmillert (void)free(spp); 1269e6aa8bafSmillert return(has_overlap(lp, freep, resolve)); 12706fe57b42Smillert } 12716fe57b42Smillert } 12726fe57b42Smillert } 1273f0b4d0a9Smillert 1274f0b4d0a9Smillert (void)free(spp); 1275e6aa8bafSmillert return(0); 12766fe57b42Smillert } 12776fe57b42Smillert 12786fe57b42Smillert void 12796fe57b42Smillert edit_parms(lp, freep) 12806fe57b42Smillert struct disklabel *lp; 12816fe57b42Smillert u_int32_t *freep; 12826fe57b42Smillert { 12836fe57b42Smillert char *p; 12846fe57b42Smillert u_int32_t ui; 128596a888c6Smillert struct disklabel oldlabel = *lp; 12866fe57b42Smillert 1287ea37abd3Sderaadt printf("Changing device parameters for %s:\n", specname); 12886fe57b42Smillert 12890f820bbbSmillert /* disk type */ 12900f820bbbSmillert for (;;) { 1291c33fcabaSmillert p = getstring("disk type", 129241282a2aSmillert "What kind of disk is this? Usually SCSI, ESDI, ST506, or " 129341282a2aSmillert "floppy (use ESDI for IDE).", dktypenames[lp->d_type]); 129496a888c6Smillert if (p == NULL) { 129596a888c6Smillert fputs("Command aborted\n", stderr); 129696a888c6Smillert return; 129796a888c6Smillert } 129841282a2aSmillert if (strcasecmp(p, "IDE") == 0) 129941282a2aSmillert ui = DTYPE_ESDI; 130041282a2aSmillert else 130141282a2aSmillert for (ui = 1; ui < DKMAXTYPES && 130241282a2aSmillert strcasecmp(p, dktypenames[ui]); ui++) 13030f820bbbSmillert ; 13040f820bbbSmillert if (ui < DKMAXTYPES) { 13050f820bbbSmillert break; 13060f820bbbSmillert } else { 13070f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", p); 13080f820bbbSmillert fputs("Valid types are: ", stdout); 13090f820bbbSmillert for (ui = 1; ui < DKMAXTYPES; ui++) { 13100f820bbbSmillert printf("\"%s\"", dktypenames[ui]); 13110f820bbbSmillert if (ui < DKMAXTYPES - 1) 13120f820bbbSmillert fputs(", ", stdout); 13130f820bbbSmillert } 13140f820bbbSmillert putchar('\n'); 13150f820bbbSmillert } 13160f820bbbSmillert } 13170f820bbbSmillert lp->d_type = ui; 13180f820bbbSmillert 13196fe57b42Smillert /* pack/label id */ 1320c33fcabaSmillert p = getstring("label name", 13216fe57b42Smillert "15 char string that describes this label, usually the disk name.", 13226fe57b42Smillert lp->d_packname); 132396a888c6Smillert if (p == NULL) { 132496a888c6Smillert fputs("Command aborted\n", stderr); 132596a888c6Smillert *lp = oldlabel; /* undo damage */ 132696a888c6Smillert return; 132796a888c6Smillert } 13286fe57b42Smillert strncpy(lp->d_packname, p, sizeof(lp->d_packname) - 1); 13296fe57b42Smillert lp->d_packname[sizeof(lp->d_packname) - 1] = '\0'; 13306fe57b42Smillert 13316fe57b42Smillert /* sectors/track */ 13326fe57b42Smillert for (;;) { 13336fe57b42Smillert ui = getuint(lp, 0, "sectors/track", 13346fe57b42Smillert "The Numer of sectors per track.", lp->d_nsectors, 13354b9a3bdaSmillert lp->d_nsectors, 0, 0); 133696a888c6Smillert if (ui == UINT_MAX - 1) { 133796a888c6Smillert fputs("Command aborted\n", stderr); 133896a888c6Smillert *lp = oldlabel; /* undo damage */ 133996a888c6Smillert return; 134096a888c6Smillert } if (ui == UINT_MAX) 13416fe57b42Smillert fputs("Invalid entry\n", stderr); 13426fe57b42Smillert else 13436fe57b42Smillert break; 13446fe57b42Smillert } 13456fe57b42Smillert lp->d_nsectors = ui; 13466fe57b42Smillert 13476fe57b42Smillert /* tracks/cylinder */ 13486fe57b42Smillert for (;;) { 13496fe57b42Smillert ui = getuint(lp, 0, "tracks/cylinder", 13506fe57b42Smillert "The number of tracks per cylinder.", lp->d_ntracks, 13514b9a3bdaSmillert lp->d_ntracks, 0, 0); 135296a888c6Smillert if (ui == UINT_MAX - 1) { 135396a888c6Smillert fputs("Command aborted\n", stderr); 135496a888c6Smillert *lp = oldlabel; /* undo damage */ 135596a888c6Smillert return; 135696a888c6Smillert } else if (ui == UINT_MAX) 13576fe57b42Smillert fputs("Invalid entry\n", stderr); 13586fe57b42Smillert else 13596fe57b42Smillert break; 13606fe57b42Smillert } 13616fe57b42Smillert lp->d_ntracks = ui; 13626fe57b42Smillert 13636fe57b42Smillert /* sectors/cylinder */ 1364148b6188Smillert for (;;) { 1365148b6188Smillert ui = getuint(lp, 0, "sectors/cylinder", 1366148b6188Smillert "The number of sectors per cylinder (Usually sectors/track " 13674b9a3bdaSmillert "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl, 13684b9a3bdaSmillert 0, 0); 136996a888c6Smillert if (ui == UINT_MAX - 1) { 137096a888c6Smillert fputs("Command aborted\n", stderr); 137196a888c6Smillert *lp = oldlabel; /* undo damage */ 137296a888c6Smillert return; 137396a888c6Smillert } else if (ui == UINT_MAX) 1374148b6188Smillert fputs("Invalid entry\n", stderr); 1375148b6188Smillert else 1376148b6188Smillert break; 1377148b6188Smillert } 1378148b6188Smillert lp->d_secpercyl = ui; 13796fe57b42Smillert 13806fe57b42Smillert /* number of cylinders */ 13816fe57b42Smillert for (;;) { 13826fe57b42Smillert ui = getuint(lp, 0, "number of cylinders", 13836fe57b42Smillert "The total number of cylinders on the disk.", 13844b9a3bdaSmillert lp->d_ncylinders, lp->d_ncylinders, 0, 0); 138596a888c6Smillert if (ui == UINT_MAX - 1) { 138696a888c6Smillert fputs("Command aborted\n", stderr); 138796a888c6Smillert *lp = oldlabel; /* undo damage */ 138896a888c6Smillert return; 138996a888c6Smillert } else if (ui == UINT_MAX) 13906fe57b42Smillert fputs("Invalid entry\n", stderr); 13916fe57b42Smillert else 13926fe57b42Smillert break; 13936fe57b42Smillert } 13946fe57b42Smillert lp->d_ncylinders = ui; 13956fe57b42Smillert 13966fe57b42Smillert /* total sectors */ 13976fe57b42Smillert for (;;) { 13986fe57b42Smillert ui = getuint(lp, 0, "total sectors", 13996fe57b42Smillert "The total number of sectors on the disk.", 14006fe57b42Smillert lp->d_secperunit ? lp->d_secperunit : 14016fe57b42Smillert lp->d_ncylinders * lp->d_ncylinders, 14024b9a3bdaSmillert lp->d_ncylinders * lp->d_ncylinders, 0, 0); 140396a888c6Smillert if (ui == UINT_MAX - 1) { 140496a888c6Smillert fputs("Command aborted\n", stderr); 140596a888c6Smillert *lp = oldlabel; /* undo damage */ 140696a888c6Smillert return; 140796a888c6Smillert } else if (ui == UINT_MAX) 14086fe57b42Smillert fputs("Invalid entry\n", stderr); 140996a888c6Smillert else if (ui > lp->d_secperunit && 141096a888c6Smillert ending_sector == lp->d_secperunit) { 14116fe57b42Smillert /* grow free count */ 14126fe57b42Smillert *freep += ui - lp->d_secperunit; 1413f98aebd4Smillert puts("You may want to increase the size of the 'c' " 1414f98aebd4Smillert "partition."); 14156fe57b42Smillert break; 141696a888c6Smillert } else if (ui < lp->d_secperunit && 141796a888c6Smillert ending_sector == lp->d_secperunit) { 14186fe57b42Smillert /* shrink free count */ 14196fe57b42Smillert if (lp->d_secperunit - ui > *freep) 14206fe57b42Smillert fprintf(stderr, 14216fe57b42Smillert "Not enough free space to shrink by %u " 14226fe57b42Smillert "sectors (only %u sectors left)\n", 14236fe57b42Smillert lp->d_secperunit - ui, *freep); 14246fe57b42Smillert else { 14256fe57b42Smillert *freep -= lp->d_secperunit - ui; 14266fe57b42Smillert break; 14276fe57b42Smillert } 14286fe57b42Smillert } else 14296fe57b42Smillert break; 14306fe57b42Smillert } 143196a888c6Smillert /* Adjust ending_sector if necesary. */ 143296a888c6Smillert if (ending_sector > ui) 143396a888c6Smillert ending_sector = ui; 14346fe57b42Smillert lp->d_secperunit = ui; 14356fe57b42Smillert 14366fe57b42Smillert /* rpm */ 14376fe57b42Smillert for (;;) { 14386fe57b42Smillert ui = getuint(lp, 0, "rpm", 1439a7e61405Smillert "The rotational speed of the disk in revolutions per minute.", 14404b9a3bdaSmillert lp->d_rpm, lp->d_rpm, 0, 0); 144196a888c6Smillert if (ui == UINT_MAX - 1) { 144296a888c6Smillert fputs("Command aborted\n", stderr); 144396a888c6Smillert *lp = oldlabel; /* undo damage */ 144496a888c6Smillert return; 144596a888c6Smillert } else if (ui == UINT_MAX) 14466fe57b42Smillert fputs("Invalid entry\n", stderr); 14476fe57b42Smillert else 14486fe57b42Smillert break; 14496fe57b42Smillert } 14506fe57b42Smillert lp->d_rpm = ui; 1451440b1d70Smillert 1452440b1d70Smillert /* interleave */ 1453440b1d70Smillert for (;;) { 1454440b1d70Smillert ui = getuint(lp, 0, "interleave", 1455440b1d70Smillert "The physical sector interleave, set when formatting. Almost always 1.", 14564b9a3bdaSmillert lp->d_interleave, lp->d_interleave, 0, 0); 1457440b1d70Smillert if (ui == UINT_MAX - 1) { 1458440b1d70Smillert fputs("Command aborted\n", stderr); 1459440b1d70Smillert *lp = oldlabel; /* undo damage */ 1460440b1d70Smillert return; 1461440b1d70Smillert } else if (ui == UINT_MAX || ui == 0) 1462440b1d70Smillert fputs("Invalid entry\n", stderr); 1463440b1d70Smillert else 1464440b1d70Smillert break; 1465440b1d70Smillert } 1466440b1d70Smillert lp->d_interleave = ui; 14676fe57b42Smillert } 1468a7e61405Smillert 1469a7e61405Smillert struct partition ** 1470a7e61405Smillert sort_partitions(lp, npart) 1471a7e61405Smillert struct disklabel *lp; 1472a7e61405Smillert u_int16_t *npart; 1473a7e61405Smillert { 1474a7e61405Smillert u_int16_t npartitions; 1475a7e61405Smillert struct partition **spp; 1476a7e61405Smillert int i; 1477a7e61405Smillert 1478a7e61405Smillert /* How many "real" partitions do we have? */ 1479a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1480a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1481a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 1482a7e61405Smillert lp->d_partitions[i].p_size != 0) 1483a7e61405Smillert npartitions++; 1484a7e61405Smillert } 148596a888c6Smillert if (npartitions == 0) { 148696a888c6Smillert *npart = 0; 148796a888c6Smillert return(NULL); 148896a888c6Smillert } 1489a7e61405Smillert 1490a7e61405Smillert /* Create an array of pointers to the partition data */ 1491a7e61405Smillert if ((spp = malloc(sizeof(struct partition *) * npartitions)) == NULL) 1492a7e61405Smillert errx(4, "out of memory"); 1493a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1494a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1495a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 1496a7e61405Smillert lp->d_partitions[i].p_size != 0) 1497a7e61405Smillert spp[npartitions++] = &lp->d_partitions[i]; 1498a7e61405Smillert } 1499a7e61405Smillert 1500a7e61405Smillert /* 1501a7e61405Smillert * Sort the partitions based on starting offset. 1502a7e61405Smillert * This is safe because we guarantee no overlap. 1503a7e61405Smillert */ 1504a7e61405Smillert if (npartitions > 1) 1505a7e61405Smillert if (heapsort((void *)spp, npartitions, sizeof(spp[0]), 1506a7e61405Smillert partition_cmp)) 1507a7e61405Smillert err(4, "failed to sort partition table"); 1508a7e61405Smillert 1509a7e61405Smillert *npart = npartitions; 1510a7e61405Smillert return(spp); 1511a7e61405Smillert } 15120f820bbbSmillert 15130f820bbbSmillert /* 15140f820bbbSmillert * Get a valid disk type if necessary. 15150f820bbbSmillert */ 15160f820bbbSmillert void 1517803ff7d5Smillert getdisktype(lp, banner, dev) 15180f820bbbSmillert struct disklabel *lp; 15190f820bbbSmillert char *banner; 1520803ff7d5Smillert char *dev; 15210f820bbbSmillert { 15220f820bbbSmillert int i; 1523803ff7d5Smillert char *s, *def = "SCSI"; 1524803ff7d5Smillert struct dtypes { 1525803ff7d5Smillert char *dev; 1526803ff7d5Smillert char *type; 1527803ff7d5Smillert } dtypes[] = { 1528c33fcabaSmillert { "sd", "SCSI" }, 1529c33fcabaSmillert { "rz", "SCSI" }, 1530c33fcabaSmillert { "wd", "IDE" }, 1531c33fcabaSmillert { "fd", "FLOPPY" }, 1532c33fcabaSmillert { "xd", "SMD" }, 1533c33fcabaSmillert { "xy", "SMD" }, 1534c33fcabaSmillert { "hd", "HP-IB" }, 1535c33fcabaSmillert { "ccd", "CCD" }, 1536c33fcabaSmillert { "vnd", "VND" }, 1537c33fcabaSmillert { "svnd", "VND" }, 1538c33fcabaSmillert { NULL, NULL } 1539803ff7d5Smillert }; 1540803ff7d5Smillert 1541803ff7d5Smillert if ((s = basename(dev)) != NULL) { 1542803ff7d5Smillert if (*s == 'r') 1543803ff7d5Smillert s++; 1544803ff7d5Smillert i = strcspn(s, "0123456789"); 1545803ff7d5Smillert s[i] = '\0'; 1546803ff7d5Smillert dev = s; 1547803ff7d5Smillert for (i = 0; dtypes[i].dev != NULL; i++) { 1548803ff7d5Smillert if (strcmp(dev, dtypes[i].dev) == 0) { 1549803ff7d5Smillert def = dtypes[i].type; 1550803ff7d5Smillert break; 1551803ff7d5Smillert } 1552803ff7d5Smillert } 1553803ff7d5Smillert } 15540f820bbbSmillert 15550f820bbbSmillert if (lp->d_type > DKMAXTYPES || lp->d_type == 0) { 15560f820bbbSmillert puts(banner); 15570f820bbbSmillert puts("Possible values are:"); 1558eb5dd924Sderaadt printf("\"IDE\", "); 15590f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15600f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15610f820bbbSmillert if (i < DKMAXTYPES - 1) 15620f820bbbSmillert fputs(", ", stdout); 15630f820bbbSmillert } 15640f820bbbSmillert putchar('\n'); 15650f820bbbSmillert 15660f820bbbSmillert for (;;) { 1567c33fcabaSmillert s = getstring("Disk type", 1568803ff7d5Smillert "What kind of disk is this? Usually SCSI, IDE, " 1569803ff7d5Smillert "ESDI, CCD, ST506, or floppy.", def); 157096a888c6Smillert if (s == NULL) 157196a888c6Smillert continue; 15725b412421Smillert if (strcasecmp(s, "IDE") == 0) { 15735b412421Smillert lp->d_type = DTYPE_ESDI; 15745b412421Smillert return; 15755b412421Smillert } 15760f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) 15770f820bbbSmillert if (strcasecmp(s, dktypenames[i]) == 0) { 15780f820bbbSmillert lp->d_type = i; 15790f820bbbSmillert return; 15800f820bbbSmillert } 15810f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", s); 15820f820bbbSmillert fputs("Valid types are: ", stdout); 15830f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15840f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15850f820bbbSmillert if (i < DKMAXTYPES - 1) 15860f820bbbSmillert fputs(", ", stdout); 15870f820bbbSmillert } 15880f820bbbSmillert putchar('\n'); 15890f820bbbSmillert } 15900f820bbbSmillert } 15910f820bbbSmillert } 159296a888c6Smillert 159396a888c6Smillert /* 159496a888c6Smillert * Get beginning and ending sectors of the OpenBSD portion of the disk 159596a888c6Smillert * from the user. 15964793b14cSmillert * XXX - should mention MBR values if DOSLABEL 159796a888c6Smillert */ 159896a888c6Smillert void 1599e8e8bdb7Sart set_bounds(lp, freep) 160096a888c6Smillert struct disklabel *lp; 1601e8e8bdb7Sart u_int32_t *freep; 160296a888c6Smillert { 160396a888c6Smillert u_int32_t ui, start_temp; 160496a888c6Smillert 160596a888c6Smillert /* Starting sector */ 160696a888c6Smillert do { 160796a888c6Smillert ui = getuint(lp, 0, "Starting sector", 160896a888c6Smillert "The start of the OpenBSD portion of the disk.", 16094b9a3bdaSmillert starting_sector, lp->d_secperunit, 0, 0); 161096a888c6Smillert if (ui == UINT_MAX - 1) { 161196a888c6Smillert fputs("Command aborted\n", stderr); 161296a888c6Smillert return; 161396a888c6Smillert } 161496a888c6Smillert } while (ui >= lp->d_secperunit); 161596a888c6Smillert start_temp = ui; 161696a888c6Smillert 16174793b14cSmillert /* Size */ 161896a888c6Smillert do { 1619f98aebd4Smillert ui = getuint(lp, 0, "Size ('*' for entire disk)", 1620f98aebd4Smillert "The size of the OpenBSD portion of the disk ('*' for the " 1621f98aebd4Smillert "entire disk).", ending_sector - starting_sector, 16224b9a3bdaSmillert lp->d_secperunit - start_temp, 0, 0); 162396a888c6Smillert if (ui == UINT_MAX - 1) { 162496a888c6Smillert fputs("Command aborted\n", stderr); 162596a888c6Smillert return; 162696a888c6Smillert } 1627f98aebd4Smillert } while (ui > lp->d_secperunit - start_temp); 16284793b14cSmillert ending_sector = start_temp + ui; 162996a888c6Smillert starting_sector = start_temp; 1630e8e8bdb7Sart 1631e8e8bdb7Sart /* Recalculate the free sectors */ 1632c0bdc608Smillert editor_countfree(lp, freep); 163396a888c6Smillert } 163496a888c6Smillert 163596a888c6Smillert /* 163696a888c6Smillert * Return a list of the "chunks" of free space available 163796a888c6Smillert */ 163896a888c6Smillert struct diskchunk * 163996a888c6Smillert free_chunks(lp) 164096a888c6Smillert struct disklabel *lp; 164196a888c6Smillert { 164296a888c6Smillert u_int16_t npartitions; 164396a888c6Smillert struct partition **spp; 164496a888c6Smillert static struct diskchunk chunks[MAXPARTITIONS + 2]; 164596a888c6Smillert int i, numchunks; 164696a888c6Smillert 164796a888c6Smillert /* Sort the partitions based on offset */ 164896a888c6Smillert spp = sort_partitions(lp, &npartitions); 164996a888c6Smillert 165096a888c6Smillert /* If there are no partitions, it's all free. */ 165196a888c6Smillert if (spp == NULL) { 16522d8451b0Smillert chunks[0].start = starting_sector; 165396a888c6Smillert chunks[0].stop = ending_sector; 165496a888c6Smillert chunks[1].start = chunks[1].stop = 0; 165596a888c6Smillert return(chunks); 165696a888c6Smillert } 165796a888c6Smillert 165896a888c6Smillert /* Find chunks of free space */ 165996a888c6Smillert numchunks = 0; 166096a888c6Smillert if (spp && spp[0]->p_offset > 0) { 16612d8451b0Smillert chunks[0].start = starting_sector; 166296a888c6Smillert chunks[0].stop = spp[0]->p_offset; 166396a888c6Smillert numchunks++; 166496a888c6Smillert } 166596a888c6Smillert for (i = 0; i < npartitions; i++) { 166696a888c6Smillert if (i + 1 < npartitions) { 166796a888c6Smillert if (spp[i]->p_offset + spp[i]->p_size < spp[i+1]->p_offset) { 166896a888c6Smillert chunks[numchunks].start = 166996a888c6Smillert spp[i]->p_offset + spp[i]->p_size; 167096a888c6Smillert chunks[numchunks].stop = spp[i+1]->p_offset; 167196a888c6Smillert numchunks++; 167296a888c6Smillert } 167396a888c6Smillert } else { 167496a888c6Smillert /* Last partition */ 167565ce672dScsapuntz if (spp[i]->p_offset + spp[i]->p_size < ending_sector) { 167696a888c6Smillert 167796a888c6Smillert chunks[numchunks].start = 167896a888c6Smillert spp[i]->p_offset + spp[i]->p_size; 167965ce672dScsapuntz chunks[numchunks].stop = ending_sector; 168096a888c6Smillert numchunks++; 168196a888c6Smillert } 168296a888c6Smillert } 168396a888c6Smillert } 168496a888c6Smillert 168596a888c6Smillert /* Terminate and return */ 168696a888c6Smillert chunks[numchunks].start = chunks[numchunks].stop = 0; 168796a888c6Smillert (void)free(spp); 168896a888c6Smillert return(chunks); 168996a888c6Smillert } 16904793b14cSmillert 16914793b14cSmillert /* 16924793b14cSmillert * What is the OpenBSD portion of the disk? Uses the MBR if applicable. 16934793b14cSmillert */ 16944793b14cSmillert void 16959785f718Smillert find_bounds(lp, bios_lp) 16964793b14cSmillert struct disklabel *lp; 1697d09f3941Smillert struct disklabel *bios_lp; 16984793b14cSmillert { 1699d09f3941Smillert struct partition *pp = &lp->d_partitions[RAW_PART]; 17004793b14cSmillert 17014793b14cSmillert /* Defaults */ 17024793b14cSmillert /* XXX - reserve a cylinder for hp300? */ 17034793b14cSmillert starting_sector = 0; 17044793b14cSmillert ending_sector = lp->d_secperunit; 17054793b14cSmillert 17064793b14cSmillert #ifdef DOSLABEL 1707528915f5Smillert /* 1708d09f3941Smillert * If we have an MBR, use values from the {Open,Free,Net}BSD partition 1709528915f5Smillert */ 1710d09f3941Smillert if (dosdp) { 1711fd29f560Sderaadt if (dosdp->dp_typ == DOSPTYP_OPENBSD || 1712aaa7b57dSderaadt dosdp->dp_typ == DOSPTYP_FREEBSD || 1713fd29f560Sderaadt dosdp->dp_typ == DOSPTYP_NETBSD) { 1714528915f5Smillert u_int32_t i, new_end; 1715528915f5Smillert 1716d09f3941Smillert /* Set start and end based on fdisk partition bounds */ 17174793b14cSmillert starting_sector = get_le(&dosdp->dp_start); 17184793b14cSmillert ending_sector = starting_sector + get_le(&dosdp->dp_size); 1719528915f5Smillert 1720528915f5Smillert /* 1721d09f3941Smillert * If the ending sector of the BSD fdisk partition 1722d09f3941Smillert * is equal to the ending sector of the BIOS geometry 1723d09f3941Smillert * but the real sector count > BIOS sector count, 1724d09f3941Smillert * adjust the bounds accordingly. We do this because 1725d09f3941Smillert * the BIOS geometry is limited to disks of ~4gig. 1726d09f3941Smillert */ 1727d09f3941Smillert if (bios_lp && ending_sector == bios_lp->d_secperunit && 1728d09f3941Smillert lp->d_secperunit > bios_lp->d_secperunit) 1729d09f3941Smillert ending_sector = lp->d_secperunit; 1730d09f3941Smillert 1731d09f3941Smillert /* 1732d09f3941Smillert * If there are any BSD or SWAP partitions beyond 1733d09f3941Smillert * ending_sector we extend ending_sector to include 1734d09f3941Smillert * them. This is done because the BIOS geometry is 1735d09f3941Smillert * generally different from the disk geometry. 1736528915f5Smillert */ 1737528915f5Smillert for (i = new_end = 0; i < lp->d_npartitions; i++) { 1738528915f5Smillert pp = &lp->d_partitions[i]; 1739528915f5Smillert if ((pp->p_fstype == FS_BSDFFS || 1740528915f5Smillert pp->p_fstype == FS_SWAP) && 1741528915f5Smillert pp->p_size + pp->p_offset > new_end) 1742528915f5Smillert new_end = pp->p_size + pp->p_offset; 1743528915f5Smillert } 1744528915f5Smillert if (new_end > ending_sector) 1745528915f5Smillert ending_sector = new_end; 1746d09f3941Smillert } else { 1747d09f3941Smillert /* Don't trounce the MBR */ 17489785f718Smillert starting_sector = 63; 1749d09f3941Smillert } 1750d09f3941Smillert 1751508086e9Smillert printf("\nTreating sectors %u-%u as the OpenBSD portion of the " 17524793b14cSmillert "disk.\nYou can use the 'b' command to change this.\n", 17534793b14cSmillert starting_sector, ending_sector); 17544793b14cSmillert } 1755d3f02056Smillert #elif (NUMBOOT == 1) 1756d3f02056Smillert /* Boot blocks take up the first cylinder */ 1757d3f02056Smillert starting_sector = lp->d_secpercyl; 1758d3f02056Smillert printf("\nReserving the first data cylinder for boot blocks.\n" 1759d3f02056Smillert "You can use the 'b' command to change this.\n"); 17604793b14cSmillert #endif 17614793b14cSmillert } 1762c0bdc608Smillert 1763c0bdc608Smillert /* 1764c0bdc608Smillert * Calculate free space. 1765c0bdc608Smillert */ 1766c0bdc608Smillert void 1767c0bdc608Smillert editor_countfree(lp, freep) 1768c0bdc608Smillert struct disklabel *lp; 1769c0bdc608Smillert u_int32_t *freep; 1770c0bdc608Smillert { 1771c0bdc608Smillert struct partition *pp; 1772c0bdc608Smillert int i; 1773c0bdc608Smillert 1774c0bdc608Smillert *freep = ending_sector - starting_sector; 1775c0bdc608Smillert for (i = 0; i < lp->d_npartitions; i++) { 1776c0bdc608Smillert pp = &lp->d_partitions[i]; 1777c0bdc608Smillert if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT && 1778c0bdc608Smillert pp->p_size > 0 && 1779c0bdc608Smillert pp->p_offset + pp->p_size <= ending_sector && 1780c0bdc608Smillert pp->p_offset >= starting_sector) 1781c0bdc608Smillert *freep -= pp->p_size; 1782c0bdc608Smillert } 1783c0bdc608Smillert } 1784617e6e4aSmillert 1785617e6e4aSmillert void 1786617e6e4aSmillert editor_help(arg) 1787617e6e4aSmillert char *arg; 1788617e6e4aSmillert { 1789617e6e4aSmillert 1790617e6e4aSmillert /* XXX - put these strings in a table instead? */ 1791617e6e4aSmillert switch (*arg) { 1792617e6e4aSmillert case 'p': 1793617e6e4aSmillert puts( 1794617e6e4aSmillert "The 'p' command prints the current disk label. By default, it prints the\n" 1795617e6e4aSmillert "size and offset in sectors (a sector is usually 512 bytes). The 'p' command\n" 1796617e6e4aSmillert "takes an optional units argument. Possible values are 'b' for bytes, 'c'\n" 1797617e6e4aSmillert "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n"); 1798617e6e4aSmillert break; 1799617e6e4aSmillert case 'M': 1800617e6e4aSmillert puts( 18019afbe9eeSmillert "The 'M' command pipes the entire OpenBSD manual page for disk label through\n" 1802508086e9Smillert "the pager specified by the PAGER environment variable or 'less' if PAGER is\n" 1803508086e9Smillert "not set. It is especially useful during install when the normal system\n" 1804508086e9Smillert "manual is not available.\n"); 1805617e6e4aSmillert break; 1806617e6e4aSmillert case 'e': 1807617e6e4aSmillert puts( 1808617e6e4aSmillert "The 'e' command is used to edit the disk drive parameters. These include\n" 1809617e6e4aSmillert "the number of sectors/track, tracks/cylinder, sectors/cylinder, number of\n" 1810617e6e4aSmillert "cylinders on the disk , total sectors on the disk, rpm, interleave, disk\n" 1811617e6e4aSmillert "type, and a descriptive label string. You should not change these unless\n" 1812617e6e4aSmillert "you know what you are doing\n"); 1813617e6e4aSmillert break; 1814617e6e4aSmillert case 'a': 1815617e6e4aSmillert puts( 1816617e6e4aSmillert "The 'a' command adds new partitions to the disk. It takes as an optional\n" 1817617e6e4aSmillert "argument the partition letter to add. If you do not specify a partition\n" 1818617e6e4aSmillert "letter, you will be prompted for it; the next available letter will be the\n" 1819617e6e4aSmillert "default answer\n"); 1820617e6e4aSmillert break; 1821617e6e4aSmillert case 'b': 1822617e6e4aSmillert puts( 1823617e6e4aSmillert "The 'b' command is used to change the boundaries of the OpenBSD portion of\n" 1824617e6e4aSmillert "the disk. This is only useful on disks with an fdisk partition. By default,\n" 1825617e6e4aSmillert "on a disk with an fdisk partition, the boundaries are set to be the first\n" 1826617e6e4aSmillert "and last sectors of the OpenBSD fdisk partition. You should only change\n" 1827617e6e4aSmillert "these if your fdisk partition table is incorrect or you have a disk larger\n" 1828617e6e4aSmillert "than 8gig, since 8gig is the maximum size an fdisk partition can be. You\n" 1829617e6e4aSmillert "may enter '*' at the 'Size' prompt to indicate the entire size of the disk\n" 1830617e6e4aSmillert "(minus the starting sector). Use this option with care; if you extend the\n" 1831617e6e4aSmillert "boundaries such that they overlap with another operating system you will\n" 1832617e6e4aSmillert "corrupt the other operating system's data.\n"); 1833617e6e4aSmillert break; 1834617e6e4aSmillert case 'c': 1835617e6e4aSmillert puts( 1836617e6e4aSmillert "The 'c' command is used to change the size of an existing partition. It\n" 1837617e6e4aSmillert "takes as an optional argument the partition letter to change. If you do not\n" 1838617e6e4aSmillert "specify a partition letter, you will be prompted for one. You may add a '+'\n" 1839617e6e4aSmillert "or '-' prefix to the new size to increase or decrease the existing value\n" 1840617e6e4aSmillert "instead of entering an absolute value. You may also use a suffix to indicate\n" 1841617e6e4aSmillert "the units the values is in terms of. Possible suffixes are 'b' for bytes,\n" 1842617e6e4aSmillert "'c' for cylinders, 'k' for kilobytes, 'm' for megabytes, 'g' for gigabytes or\n" 1843617e6e4aSmillert "no suffix for sectors (usually 512 bytes). You may also enter '*' to change\n" 1844617e6e4aSmillert "the size to be the total number of free sectors remaining.\n"); 1845617e6e4aSmillert break; 18469afbe9eeSmillert case 'D': 18479afbe9eeSmillert puts( 18489afbe9eeSmillert "The 'D' command will set the disk label to the default values as reported\n" 18499afbe9eeSmillert "by the disk itself. This similates the case where there is no disk label.\n"); 18509afbe9eeSmillert break; 1851617e6e4aSmillert case 'd': 1852617e6e4aSmillert puts( 1853617e6e4aSmillert "The 'd' command is used to delete an existing partition. It takes as an\n" 1854617e6e4aSmillert "optional argument the partition letter to change. If you do not specify a\n" 1855617e6e4aSmillert "partition letter, you will be prompted for one. You may not delete the ``c''\n" 1856617e6e4aSmillert "partition as 'c' must always exist and by default is marked as 'unused' (so\n" 1857617e6e4aSmillert "it does not take up any space).\n"); 1858617e6e4aSmillert break; 1859c33fcabaSmillert case 'g': 1860c33fcabaSmillert puts( 1861c33fcabaSmillert "The 'g' command is used select which disk geometry to use, the disk, BIOS, or\n" 1862c33fcabaSmillert "user geometry. It takes as an optional argument ``d'', ``b'', or ``u''. If \n" 1863c33fcabaSmillert "you do not specify the type as an argument, you will be prompted for it.\n"); 1864c33fcabaSmillert break; 1865617e6e4aSmillert case 'm': 1866617e6e4aSmillert puts( 1867617e6e4aSmillert "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" 1868617e6e4aSmillert "partition letter, you will be prompted for one. This option allows the user\n" 1869617e6e4aSmillert "to change the filesystem type, starting offset, partition size, block fragment\n" 1870617e6e4aSmillert "size, block size, and cylinders per group for the specified partition (not all\n" 1871617e6e4aSmillert "parameters are configurable for non-BSD partitions).\n"); 1872617e6e4aSmillert break; 1873bd6726faSmillert case 'n': 1874bd6726faSmillert puts( 1875fb932baaSaaron "The 'n' command is used to set the mount point for a partition (ie: name it).\n" 1876bd6726faSmillert "It takes as an optional argument the partition letter to name. If you do\n" 1877bd6726faSmillert "not specify a partition letter, you will be prompted for one. This option\n" 1878bd6726faSmillert "is only valid if disklabel was invoked with the -F flag.\n"); 1879bd6726faSmillert break; 1880617e6e4aSmillert case 'r': 1881617e6e4aSmillert puts( 1882617e6e4aSmillert "The 'r' command is used to recalculate the free space available. This option\n" 1883617e6e4aSmillert "should really not be necessary under normal circumstances but can be useful if\n" 1884617e6e4aSmillert "disklabel gets confused.\n"); 1885617e6e4aSmillert break; 1886617e6e4aSmillert case 'u': 1887617e6e4aSmillert puts( 1888617e6e4aSmillert "The 'u' command will undo (or redo) the last change. Entering 'u' once will\n" 1889617e6e4aSmillert "undo your last change. Entering it again will restore the change.\n"); 1890617e6e4aSmillert break; 1891617e6e4aSmillert case 's': 1892617e6e4aSmillert puts( 1893617e6e4aSmillert "The 's' command is used to save a copy of the label to a file in ascii format\n" 1894617e6e4aSmillert "(suitable for loading via disklabel's [-R] option). It takes as an optional\n" 1895617e6e4aSmillert "argument the filename to save the label to. If you do not specify a filename,\n" 1896617e6e4aSmillert "you will be prompted for one.\n"); 1897617e6e4aSmillert break; 1898617e6e4aSmillert case 'w': 1899617e6e4aSmillert puts( 1900617e6e4aSmillert "The 'w' command will write the current label to disk. This option will\n" 1901617e6e4aSmillert "commit any changes to the on-disk label.\n"); 1902617e6e4aSmillert break; 1903617e6e4aSmillert case 'q': 1904617e6e4aSmillert puts( 1905617e6e4aSmillert "The 'q' command quits the label editor. If any changes have been made you\n" 1906617e6e4aSmillert "will be asked whether or not to save the changes to the on-disk label.\n"); 1907617e6e4aSmillert break; 19089afbe9eeSmillert case 'X': 19099afbe9eeSmillert puts( 19109afbe9eeSmillert "The 'X' command toggles disklabel in to/out of 'expert mode'. By default,\n" 19119afbe9eeSmillert "some settings are reserved for experts only (such as the block and fragment\n" 19129afbe9eeSmillert "size on ffs partitions).\n"); 19139afbe9eeSmillert break; 1914617e6e4aSmillert case 'x': 1915617e6e4aSmillert puts( 1916617e6e4aSmillert "The 'x' command exits the label editor without saving any changes to the\n" 1917617e6e4aSmillert "on-disk label.\n"); 1918617e6e4aSmillert break; 19199afbe9eeSmillert case 'z': 19209afbe9eeSmillert puts( 19219afbe9eeSmillert "The 'z' command zeroes out the existing partition table, leaving only the 'c'\n" 19229afbe9eeSmillert "partition. The drive parameters are not changed.\n"); 19239afbe9eeSmillert break; 1924617e6e4aSmillert default: 1925617e6e4aSmillert puts("Available commands:"); 1926617e6e4aSmillert puts("\tp [unit] - print label."); 1927617e6e4aSmillert puts("\tM - show entire OpenBSD man page for disklabel."); 1928617e6e4aSmillert puts("\te - edit drive parameters."); 1929617e6e4aSmillert puts("\ta [part] - add new partition."); 1930617e6e4aSmillert puts("\tb - set OpenBSD disk boundaries."); 1931617e6e4aSmillert puts("\tc [part] - change partition size."); 1932617e6e4aSmillert puts("\td [part] - delete partition."); 19339afbe9eeSmillert puts("\tD - set label to default."); 1934c33fcabaSmillert puts("\tg [d|b] - Use [d]isk or [b]ios geometry."); 1935617e6e4aSmillert puts("\tm [part] - modify existing partition."); 1936bd6726faSmillert puts("\tn [part] - set the mount point for a partition."); 1937617e6e4aSmillert puts("\tr - recalculate free space."); 1938617e6e4aSmillert puts("\tu - undo last change."); 1939617e6e4aSmillert puts("\ts [path] - save label to file."); 1940617e6e4aSmillert puts("\tw - write label to disk."); 1941617e6e4aSmillert puts("\tq - quit and save changes."); 1942617e6e4aSmillert puts("\tx - exit without saving changes."); 19432d8451b0Smillert puts("\tX - toggle expert mode."); 19449afbe9eeSmillert puts("\tz - zero out partition table."); 1945617e6e4aSmillert puts("\t? [cmnd] - this message or command specific help."); 1946617e6e4aSmillert puts( 1947617e6e4aSmillert "Numeric parameters may use suffixes to indicate units:\n\t" 1948617e6e4aSmillert "'b' for bytes, 'c' for cylinders, 'k' for kilobytes, 'm' for megabytes,\n\t" 1949617e6e4aSmillert "'g' for gigabytes or no suffix for sectors (usually 512 bytes).\n\t" 1950617e6e4aSmillert "Non-sector units will be rounded to the nearest cylinder.\n" 1951617e6e4aSmillert "Entering '?' at most prompts will give you (simple) context sensitive help."); 1952617e6e4aSmillert break; 1953617e6e4aSmillert } 1954617e6e4aSmillert } 1955bd6726faSmillert 1956bd6726faSmillert char ** 1957bd6726faSmillert mpcopy(to, from) 1958bd6726faSmillert char **to; 1959bd6726faSmillert char **from; 1960bd6726faSmillert { 1961bd6726faSmillert int i; 1962bd6726faSmillert 1963bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1964bd6726faSmillert if (from[i] != NULL) { 1965bd6726faSmillert to[i] = realloc(to[i], strlen(from[i]) + 1); 1966bd6726faSmillert if (to[i] == NULL) 1967bd6726faSmillert errx(4, "out of memory"); 1968bd6726faSmillert (void)strcpy(to[i], from[i]); 1969bd6726faSmillert } else if (to[i] != NULL) { 1970bd6726faSmillert free(to[i]); 1971bd6726faSmillert to[i] = NULL; 1972bd6726faSmillert } 1973bd6726faSmillert } 1974bd6726faSmillert return(to); 1975bd6726faSmillert } 1976bd6726faSmillert 1977bd6726faSmillert int 1978bd6726faSmillert mpequal(mp1, mp2) 1979bd6726faSmillert char **mp1; 1980bd6726faSmillert char **mp2; 1981bd6726faSmillert { 1982bd6726faSmillert int i; 1983bd6726faSmillert 1984bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1985bd6726faSmillert if (mp1[i] == NULL && mp2[i] == NULL) 1986bd6726faSmillert continue; 1987bd6726faSmillert 1988bd6726faSmillert if ((mp1[i] != NULL && mp2[i] == NULL) || 1989bd6726faSmillert (mp1[i] == NULL && mp2[i] != NULL) || 1990bd6726faSmillert (strcmp(mp1[i], mp2[i]) != 0)) 1991bd6726faSmillert return(0); 1992bd6726faSmillert } 1993bd6726faSmillert return(1); 1994bd6726faSmillert } 1995bd6726faSmillert 1996bd6726faSmillert int 1997bd6726faSmillert mpsave(lp, mp, cdev, fstabfile) 1998bd6726faSmillert struct disklabel *lp; 1999bd6726faSmillert char **mp; 2000bd6726faSmillert char *cdev; 2001bd6726faSmillert char *fstabfile; 2002bd6726faSmillert { 20035fea0b85Smillert int i, j, mpset; 2004bd6726faSmillert char bdev[MAXPATHLEN], *p; 20053f843443Smillert struct mountinfo mi[MAXPARTITIONS]; 2006bd6726faSmillert FILE *fp; 2007bd6726faSmillert 20083f843443Smillert memset(&mi, 0, sizeof(mi)); 20093f843443Smillert 2010bd6726faSmillert for (i = 0, mpset = 0; i < MAXPARTITIONS; i++) { 2011bd6726faSmillert if (mp[i] != NULL) { 20123f843443Smillert mi[i].mountpoint = mp[i]; 20133f843443Smillert mi[i].partno = i; 2014bd6726faSmillert mpset = 1; 2015bd6726faSmillert } 2016bd6726faSmillert } 20173f843443Smillert /* Exit if there is nothing to do... */ 2018bd6726faSmillert if (!mpset) 20193f843443Smillert return(0); 2020bd6726faSmillert 2021bd6726faSmillert /* Convert cdev to bdev */ 2022bd6726faSmillert if (strncmp(_PATH_DEV, cdev, sizeof(_PATH_DEV) - 1) == 0 && 2023bd6726faSmillert cdev[sizeof(_PATH_DEV) - 1] == 'r') { 2024bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV, 2025bd6726faSmillert &cdev[sizeof(_PATH_DEV)]); 2026bd6726faSmillert } else { 2027bd6726faSmillert if ((p = strrchr(cdev, '/')) == NULL || *(++p) != 'r') 2028bd6726faSmillert return(1); 2029bd6726faSmillert *p = '\0'; 2030bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", cdev, p + 1); 2031bd6726faSmillert *p = 'r'; 2032bd6726faSmillert } 2033bd6726faSmillert bdev[strlen(bdev) - 1] = '\0'; 2034bd6726faSmillert 20353f843443Smillert /* Sort mountpoints so we don't try to mount /usr/local before /usr */ 20363f843443Smillert qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp); 20373f843443Smillert 2038bd6726faSmillert if ((fp = fopen(fstabfile, "w")) == NULL) 2039bd6726faSmillert return(1); 2040bd6726faSmillert 20413f843443Smillert for (i = 0; i < MAXPARTITIONS && mi[i].mountpoint != NULL; i++) { 20425fea0b85Smillert j = mi[i].partno; 20435fea0b85Smillert fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 'a' + j, 20443f843443Smillert mi[i].mountpoint, 20455fea0b85Smillert fstypesnames[lp->d_partitions[j].p_fstype], 20465fea0b85Smillert j == 0 ? 1 : 2); 2047bd6726faSmillert } 2048bd6726faSmillert fclose(fp); 2049bd6726faSmillert return(0); 2050bd6726faSmillert } 205124a2c1a4Smillert 205224a2c1a4Smillert int 205324a2c1a4Smillert get_offset(lp, partno) 205424a2c1a4Smillert struct disklabel *lp; 205524a2c1a4Smillert int partno; 205624a2c1a4Smillert { 205724a2c1a4Smillert u_int32_t ui; 205824a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 205924a2c1a4Smillert 206024a2c1a4Smillert for (;;) { 206124a2c1a4Smillert ui = getuint(lp, partno, "offset", 206224a2c1a4Smillert "Starting sector for this partition.", pp->p_offset, 206324a2c1a4Smillert pp->p_offset, 0, DO_CONVERSIONS | 206424a2c1a4Smillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 206524a2c1a4Smillert if (ui == UINT_MAX - 1) { 206624a2c1a4Smillert fputs("Command aborted\n", stderr); 206724a2c1a4Smillert return(1); 206824a2c1a4Smillert } else if (ui == UINT_MAX) 206924a2c1a4Smillert fputs("Invalid entry\n", stderr); 207024a2c1a4Smillert else if (ui < starting_sector) 207124a2c1a4Smillert fprintf(stderr, "The OpenBSD portion of the disk starts" 207224a2c1a4Smillert " at sector %u, you tried to add a partition at %u." 207324a2c1a4Smillert " You can use the 'b' command to change the size " 207424a2c1a4Smillert "of the OpenBSD portion.\n" , starting_sector, ui); 207524a2c1a4Smillert else if (ui >= ending_sector) 207624a2c1a4Smillert fprintf(stderr, "The OpenBSD portion of the disk ends " 207724a2c1a4Smillert "at sector %u, you tried to add a partition at %u." 207824a2c1a4Smillert " You can use the 'b' command to change the size " 207924a2c1a4Smillert "of the OpenBSD portion.\n", ending_sector, ui); 208049bf537cSderaadt #ifdef AAT0 208149bf537cSderaadt else if (partno == 0 && ui != 0) 208249bf537cSderaadt fprintf(stderr, "This architecture requires that " 208340f544cdSderaadt "partition 'a' start at sector 0.\n"); 208449bf537cSderaadt #endif 208524a2c1a4Smillert else 208624a2c1a4Smillert break; 208724a2c1a4Smillert } 208824a2c1a4Smillert pp->p_offset = ui; 208924a2c1a4Smillert return(0); 209024a2c1a4Smillert } 209124a2c1a4Smillert 209224a2c1a4Smillert int 209324a2c1a4Smillert get_size(lp, partno, freep, new) 209424a2c1a4Smillert struct disklabel *lp; 209524a2c1a4Smillert int partno; 209624a2c1a4Smillert u_int32_t *freep; 209724a2c1a4Smillert int new; 209824a2c1a4Smillert { 209924a2c1a4Smillert u_int32_t ui; 210024a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 210124a2c1a4Smillert 210224a2c1a4Smillert for (;;) { 210324a2c1a4Smillert ui = getuint(lp, partno, "size", "Size of the partition.", 210424a2c1a4Smillert pp->p_size, *freep, pp->p_offset, DO_CONVERSIONS | 210524a2c1a4Smillert ((pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_SWAP) ? 210624a2c1a4Smillert DO_ROUNDING : 0)); 210724a2c1a4Smillert if (ui == UINT_MAX - 1) { 210824a2c1a4Smillert fputs("Command aborted\n", stderr); 210924a2c1a4Smillert return(1); 211024a2c1a4Smillert } else if (ui == UINT_MAX) { 211124a2c1a4Smillert fputs("Invalid entry\n", stderr); 211224a2c1a4Smillert continue; 211324a2c1a4Smillert } 211424a2c1a4Smillert if (new) { 211524a2c1a4Smillert if (ui > *freep) 211624a2c1a4Smillert /* XXX - steal space from another partition */ 211724a2c1a4Smillert fprintf(stderr,"Sorry, there are only %u " 211824a2c1a4Smillert "sectors left\n", *freep); 211924a2c1a4Smillert else if (pp->p_offset + ui > ending_sector) 212024a2c1a4Smillert fprintf(stderr, "The OpenBSD portion of the " 212124a2c1a4Smillert "disk ends at sector %u, you tried to add " 212224a2c1a4Smillert "a partition ending at sector %u. You can " 212324a2c1a4Smillert "use the 'b' command to change the size of " 212424a2c1a4Smillert "the OpenBSD portion.\n", 212524a2c1a4Smillert ending_sector, pp->p_offset + ui); 212624a2c1a4Smillert else 212724a2c1a4Smillert break; /* ok */ 212824a2c1a4Smillert } else { 212924a2c1a4Smillert if (ui == pp->p_size) 213024a2c1a4Smillert break; /* no change */ 21319afbe9eeSmillert if (partno == RAW_PART && 21329afbe9eeSmillert ui + pp->p_offset > lp->d_secperunit) { 213324a2c1a4Smillert fputs("'c' partition may not be larger than the disk\n", 213424a2c1a4Smillert stderr); 213524a2c1a4Smillert } else if (pp->p_fstype == FS_UNUSED || 213624a2c1a4Smillert pp->p_fstype == FS_BOOT) { 213724a2c1a4Smillert /* don't care what's free */ 213824a2c1a4Smillert pp->p_size = ui; 213924a2c1a4Smillert break; 214024a2c1a4Smillert } else { 214124a2c1a4Smillert if (ui > pp->p_size + *freep) 214224a2c1a4Smillert /* XXX - steal from another partition */ 214324a2c1a4Smillert fprintf(stderr, 214424a2c1a4Smillert "Size may not be larger than %u " 214524a2c1a4Smillert "sectors\n", pp->p_size + *freep); 214624a2c1a4Smillert else { 214724a2c1a4Smillert *freep += pp->p_size - ui; 214824a2c1a4Smillert pp->p_size = ui; 214924a2c1a4Smillert break; /* ok */ 215024a2c1a4Smillert } 215124a2c1a4Smillert } 215224a2c1a4Smillert } 215324a2c1a4Smillert } 215424a2c1a4Smillert pp->p_size = ui; 215524a2c1a4Smillert return(0); 215624a2c1a4Smillert } 215724a2c1a4Smillert 215824a2c1a4Smillert int 215924a2c1a4Smillert get_fsize(lp, partno) 216024a2c1a4Smillert struct disklabel *lp; 216124a2c1a4Smillert int partno; 216224a2c1a4Smillert { 216324a2c1a4Smillert u_int32_t ui; 216424a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 216524a2c1a4Smillert 216624a2c1a4Smillert for (;;) { 216724a2c1a4Smillert ui = getuint(lp, partno, "fragment size", 216824a2c1a4Smillert "Size of fs block fragments. Usually 1024 or 512.", 216924a2c1a4Smillert pp->p_fsize, pp->p_fsize, 0, 0); 217024a2c1a4Smillert if (ui == UINT_MAX - 1) { 217124a2c1a4Smillert fputs("Command aborted\n", stderr); 217224a2c1a4Smillert return(1); 217324a2c1a4Smillert } else if (ui == UINT_MAX) 217424a2c1a4Smillert fputs("Invalid entry\n", stderr); 217524a2c1a4Smillert else 217624a2c1a4Smillert break; 217724a2c1a4Smillert } 217824a2c1a4Smillert if (ui == 0) 217924a2c1a4Smillert puts("Zero fragment size implies zero block size"); 218024a2c1a4Smillert pp->p_fsize = ui; 218124a2c1a4Smillert return(0); 218224a2c1a4Smillert } 218324a2c1a4Smillert 218424a2c1a4Smillert int 218524a2c1a4Smillert get_bsize(lp, partno) 218624a2c1a4Smillert struct disklabel *lp; 218724a2c1a4Smillert int partno; 218824a2c1a4Smillert { 218924a2c1a4Smillert u_int32_t ui; 219024a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 219124a2c1a4Smillert 219224a2c1a4Smillert /* Avoid dividing by zero... */ 219324a2c1a4Smillert if (pp->p_fsize == 0) { 219424a2c1a4Smillert pp->p_frag = 0; 219524a2c1a4Smillert return(1); 219624a2c1a4Smillert } 219724a2c1a4Smillert 219824a2c1a4Smillert for (;;) { 219924a2c1a4Smillert ui = getuint(lp, partno, "block size", 220024a2c1a4Smillert "Size of filesystem blocks. Usually 8192 or 4096.", 220124a2c1a4Smillert pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag, 220224a2c1a4Smillert 0, 0); 220324a2c1a4Smillert 220424a2c1a4Smillert /* sanity checks */ 220524a2c1a4Smillert if (ui == UINT_MAX - 1) { 220624a2c1a4Smillert fputs("Command aborted\n", stderr); 220724a2c1a4Smillert return(1); 220824a2c1a4Smillert } else if (ui == UINT_MAX) 220924a2c1a4Smillert fputs("Invalid entry\n", stderr); 221024a2c1a4Smillert else if (ui < getpagesize()) 221124a2c1a4Smillert fprintf(stderr, 221224a2c1a4Smillert "Error: block size must be at least as big " 221324a2c1a4Smillert "as page size (%d).\n", getpagesize()); 221424a2c1a4Smillert else if (ui % pp->p_fsize != 0) 221524a2c1a4Smillert fputs("Error: block size must be a multiple of the " 221624a2c1a4Smillert "fragment size.\n", stderr); 221724a2c1a4Smillert else if (ui / pp->p_fsize < 1) 221824a2c1a4Smillert fputs("Error: block size must be at least as big as " 221924a2c1a4Smillert "fragment size.\n", stderr); 222024a2c1a4Smillert else 222124a2c1a4Smillert break; 222224a2c1a4Smillert } 222324a2c1a4Smillert pp->p_frag = ui / pp->p_fsize; 222424a2c1a4Smillert return(0); 222524a2c1a4Smillert } 222624a2c1a4Smillert 222724a2c1a4Smillert int 222824a2c1a4Smillert get_cpg(lp, partno) 222924a2c1a4Smillert struct disklabel *lp; 223024a2c1a4Smillert int partno; 223124a2c1a4Smillert { 223224a2c1a4Smillert u_int32_t ui; 223324a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 223424a2c1a4Smillert 223524a2c1a4Smillert for (;;) { 223624a2c1a4Smillert ui = getuint(lp, partno, "cpg", 223724a2c1a4Smillert "Number of filesystem cylinders per group." 223824a2c1a4Smillert " Usually 16 or 8.", 223924a2c1a4Smillert pp->p_cpg ? pp->p_cpg : 16, 16, 0, 0); 224024a2c1a4Smillert if (ui == UINT_MAX - 1) { 224124a2c1a4Smillert fputs("Command aborted\n", stderr); 224224a2c1a4Smillert return(1); 224324a2c1a4Smillert } else if (ui == UINT_MAX) 224424a2c1a4Smillert fputs("Invalid entry\n", stderr); 224524a2c1a4Smillert else 224624a2c1a4Smillert break; 224724a2c1a4Smillert } 224824a2c1a4Smillert pp->p_cpg = ui; 224924a2c1a4Smillert return(0); 225024a2c1a4Smillert } 225124a2c1a4Smillert 225224a2c1a4Smillert int 225324a2c1a4Smillert get_fstype(lp, partno) 225424a2c1a4Smillert struct disklabel *lp; 225524a2c1a4Smillert int partno; 225624a2c1a4Smillert { 225724a2c1a4Smillert char *p; 225824a2c1a4Smillert u_int32_t ui; 225924a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 226024a2c1a4Smillert 226124a2c1a4Smillert if (pp->p_fstype < FSMAXTYPES) { 2262c33fcabaSmillert p = getstring("FS type", 226324a2c1a4Smillert "Filesystem type (usually 4.2BSD or swap)", 226424a2c1a4Smillert fstypenames[pp->p_fstype]); 226524a2c1a4Smillert if (p == NULL) { 226624a2c1a4Smillert fputs("Command aborted\n", stderr); 226724a2c1a4Smillert return(1); 226824a2c1a4Smillert } 226924a2c1a4Smillert for (ui = 0; ui < FSMAXTYPES; ui++) { 227024a2c1a4Smillert if (!strcasecmp(p, fstypenames[ui])) { 227124a2c1a4Smillert pp->p_fstype = ui; 227224a2c1a4Smillert break; 227324a2c1a4Smillert } 227424a2c1a4Smillert } 227524a2c1a4Smillert if (ui >= FSMAXTYPES) { 227624a2c1a4Smillert printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p); 227724a2c1a4Smillert pp->p_fstype = FS_OTHER; 227824a2c1a4Smillert } 227924a2c1a4Smillert } else { 228024a2c1a4Smillert for (;;) { 228124a2c1a4Smillert ui = getuint(lp, partno, "FS type (decimal)", 228224a2c1a4Smillert "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", 228324a2c1a4Smillert pp->p_fstype, pp->p_fstype, 0, 0); 228424a2c1a4Smillert if (ui == UINT_MAX - 1) { 228524a2c1a4Smillert fputs("Command aborted\n", stderr); 228624a2c1a4Smillert return(1); 228724a2c1a4Smillert } if (ui == UINT_MAX) 228824a2c1a4Smillert fputs("Invalid entry\n", stderr); 228924a2c1a4Smillert else 229024a2c1a4Smillert break; 229124a2c1a4Smillert } 229224a2c1a4Smillert pp->p_fstype = ui; 229324a2c1a4Smillert } 229424a2c1a4Smillert return(0); 229524a2c1a4Smillert } 229624a2c1a4Smillert 229724a2c1a4Smillert int 229824a2c1a4Smillert get_mp(lp, mp, partno) 229924a2c1a4Smillert struct disklabel *lp; 230024a2c1a4Smillert char **mp; 230124a2c1a4Smillert int partno; 230224a2c1a4Smillert { 230324a2c1a4Smillert char *p; 230424a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 230524a2c1a4Smillert 230624a2c1a4Smillert if (mp != NULL && pp->p_fstype != FS_UNUSED && 230724a2c1a4Smillert pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT && 230824a2c1a4Smillert pp->p_fstype != FS_OTHER) { 2309ddaff619Smillert for (;;) { 2310c33fcabaSmillert p = getstring("mount point", 231124a2c1a4Smillert "Where to mount this filesystem (ie: / /var /usr)", 231224a2c1a4Smillert mp[partno] ? mp[partno] : "none"); 231324a2c1a4Smillert if (p == NULL) { 231424a2c1a4Smillert fputs("Command aborted\n", stderr); 231524a2c1a4Smillert return(1); 231624a2c1a4Smillert } 2317ddaff619Smillert if (strcasecmp(p, "none") == 0) { 231824a2c1a4Smillert if (mp[partno] != NULL) { 231924a2c1a4Smillert free(mp[partno]); 232024a2c1a4Smillert mp[partno] = NULL; 232124a2c1a4Smillert } 2322ddaff619Smillert break; 2323ddaff619Smillert } 2324ddaff619Smillert if (*p == '/') { 2325ddaff619Smillert /* XXX - might as well realloc */ 2326ddaff619Smillert if (mp[partno] != NULL) 2327ddaff619Smillert free(mp[partno]); 232824a2c1a4Smillert if ((mp[partno] = strdup(p)) == NULL) 232924a2c1a4Smillert errx(4, "out of memory"); 2330ddaff619Smillert break; 2331ddaff619Smillert } 2332ddaff619Smillert fputs("Mount points must start with '/'\n", stderr); 233324a2c1a4Smillert } 233424a2c1a4Smillert } 233524a2c1a4Smillert return(0); 233624a2c1a4Smillert } 23373f843443Smillert 23383f843443Smillert int 23393f843443Smillert micmp(a1, a2) 23403f843443Smillert const void *a1; 23413f843443Smillert const void *a2; 23423f843443Smillert { 23433f843443Smillert struct mountinfo *mi1 = (struct mountinfo *)a1; 23443f843443Smillert struct mountinfo *mi2 = (struct mountinfo *)a2; 23453f843443Smillert 23463f843443Smillert /* We want all the NULLs at the end... */ 23473f843443Smillert if (mi1->mountpoint == NULL && mi2->mountpoint == NULL) 23483f843443Smillert return(0); 23493f843443Smillert else if (mi1->mountpoint == NULL) 23503f843443Smillert return(1); 23513f843443Smillert else if (mi2->mountpoint == NULL) 23523f843443Smillert return(-1); 23533f843443Smillert else 23543f843443Smillert return(strcmp(mi1->mountpoint, mi2->mountpoint)); 23553f843443Smillert } 2356c33fcabaSmillert 2357c33fcabaSmillert void 2358c33fcabaSmillert get_geometry(f, dgpp, bgpp) 2359c33fcabaSmillert int f; 2360c33fcabaSmillert struct disklabel **dgpp; 2361c33fcabaSmillert struct disklabel **bgpp; 2362c33fcabaSmillert { 2363c33fcabaSmillert #ifdef CPU_BIOS 2364c33fcabaSmillert int mib[4]; 2365c33fcabaSmillert size_t size; 2366c33fcabaSmillert dev_t devno; 2367c33fcabaSmillert bios_diskinfo_t di; 2368c33fcabaSmillert #endif 2369c33fcabaSmillert struct stat st; 2370c33fcabaSmillert struct disklabel *disk_geop; 2371c33fcabaSmillert struct disklabel *bios_geop; 2372c33fcabaSmillert 2373c33fcabaSmillert if (fstat(f, &st) == -1) 2374c33fcabaSmillert err(4, "Can't stat device"); 2375c33fcabaSmillert 2376c33fcabaSmillert /* Get disk geometry */ 2377c33fcabaSmillert if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL) 2378c33fcabaSmillert errx(4, "out of memory"); 2379c33fcabaSmillert if (ioctl(f, DIOCGPDINFO, disk_geop) < 0 && 2380c33fcabaSmillert ioctl(f, DIOCGDINFO, disk_geop) < 0) 2381c33fcabaSmillert err(4, "ioctl DIOCGDINFO"); 2382c33fcabaSmillert *dgpp = disk_geop; 2383c33fcabaSmillert 2384c33fcabaSmillert /* Get BIOS geometry */ 2385c33fcabaSmillert *bgpp = NULL; 2386c33fcabaSmillert #ifdef CPU_BIOS 2387c33fcabaSmillert mib[0] = CTL_MACHDEP; 2388c33fcabaSmillert mib[1] = CPU_CHR2BLK; 2389c33fcabaSmillert mib[2] = st.st_rdev; 2390c33fcabaSmillert size = sizeof(devno); 2391c33fcabaSmillert if (sysctl(mib, 3, &devno, &size, NULL, 0) == -1) { 2392c33fcabaSmillert warn("sysctl(machdep.chr2blk)"); 2393c33fcabaSmillert return; 2394c33fcabaSmillert } 2395c33fcabaSmillert devno = MAKEBOOTDEV(major(devno), 0, 0, DISKUNIT(devno), RAW_PART); 2396c33fcabaSmillert 2397c33fcabaSmillert mib[0] = CTL_MACHDEP; 2398c33fcabaSmillert mib[1] = CPU_BIOS; 2399c33fcabaSmillert mib[2] = BIOS_DISKINFO; 2400c33fcabaSmillert mib[3] = devno; 2401c33fcabaSmillert size = sizeof(di); 2402c33fcabaSmillert if (sysctl(mib, 4, &di, &size, NULL, 0) == -1) { 2403c33fcabaSmillert warn("Can't get bios geometry"); 2404c33fcabaSmillert return; 2405c33fcabaSmillert } 2406c33fcabaSmillert if ((bios_geop = calloc(1, sizeof(struct disklabel))) == NULL) 2407c33fcabaSmillert errx(4, "out of memory"); 2408c33fcabaSmillert 2409c33fcabaSmillert bios_geop->d_secsize = DEV_BSIZE; 2410c33fcabaSmillert bios_geop->d_nsectors = di.bios_sectors; 2411c33fcabaSmillert bios_geop->d_ntracks = di.bios_heads; 2412c33fcabaSmillert bios_geop->d_ncylinders = di.bios_cylinders; 2413c33fcabaSmillert bios_geop->d_secpercyl = di.bios_sectors * di.bios_heads; 2414c33fcabaSmillert bios_geop->d_secperunit = di.bios_cylinders * 2415c33fcabaSmillert di.bios_heads * di.bios_sectors; 2416c33fcabaSmillert *bgpp = bios_geop; 2417c33fcabaSmillert #endif 2418c33fcabaSmillert } 2419c33fcabaSmillert 2420c33fcabaSmillert void 2421c33fcabaSmillert set_geometry(lp, dgp, bgp, ugp, p) 2422c33fcabaSmillert struct disklabel *lp; 2423c33fcabaSmillert struct disklabel *dgp; 2424c33fcabaSmillert struct disklabel *bgp; 2425c33fcabaSmillert struct disklabel *ugp; 2426c33fcabaSmillert char *p; 2427c33fcabaSmillert { 2428c33fcabaSmillert if (p == NULL) { 2429c33fcabaSmillert p = getstring("[d]isk, [b]ios, or [u]ser geometry", 2430c33fcabaSmillert "Enter 'd' to use the geometry based on what the disk " 2431c33fcabaSmillert "itself thinks it is, 'b' to use what the BIOS says," 2432c33fcabaSmillert "or 'u' to use the geometry that was found on in the label.", 2433c33fcabaSmillert "d"); 2434c33fcabaSmillert } 2435c33fcabaSmillert if (p == NULL) { 2436c33fcabaSmillert fputs("Command aborted\n", stderr); 2437c33fcabaSmillert return; 2438c33fcabaSmillert } 2439c33fcabaSmillert switch (*p) { 2440c33fcabaSmillert case 'b': 2441c33fcabaSmillert case 'B': 2442c33fcabaSmillert if (bgp == NULL) 2443c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2444c33fcabaSmillert else { 2445c33fcabaSmillert lp->d_secsize = bgp->d_secsize; 2446c33fcabaSmillert lp->d_nsectors = bgp->d_nsectors; 2447c33fcabaSmillert lp->d_ntracks = bgp->d_ntracks; 2448c33fcabaSmillert lp->d_ncylinders = bgp->d_ncylinders; 2449c33fcabaSmillert lp->d_secpercyl = bgp->d_secpercyl; 2450c33fcabaSmillert lp->d_secperunit = bgp->d_secperunit; 2451c33fcabaSmillert } 2452c33fcabaSmillert break; 2453c33fcabaSmillert case 'd': 2454c33fcabaSmillert case 'D': 2455c33fcabaSmillert if (dgp == NULL) 2456c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2457c33fcabaSmillert else { 2458c33fcabaSmillert lp->d_secsize = dgp->d_secsize; 2459c33fcabaSmillert lp->d_nsectors = dgp->d_nsectors; 2460c33fcabaSmillert lp->d_ntracks = dgp->d_ntracks; 2461c33fcabaSmillert lp->d_ncylinders = dgp->d_ncylinders; 2462c33fcabaSmillert lp->d_secpercyl = dgp->d_secpercyl; 2463c33fcabaSmillert lp->d_secperunit = dgp->d_secperunit; 2464c33fcabaSmillert } 2465c33fcabaSmillert break; 2466c33fcabaSmillert case 'u': 2467c33fcabaSmillert case 'U': 2468c33fcabaSmillert if (ugp == NULL) 2469c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2470c33fcabaSmillert else { 2471c33fcabaSmillert lp->d_secsize = ugp->d_secsize; 2472c33fcabaSmillert lp->d_nsectors = ugp->d_nsectors; 2473c33fcabaSmillert lp->d_ntracks = ugp->d_ntracks; 2474c33fcabaSmillert lp->d_ncylinders = ugp->d_ncylinders; 2475c33fcabaSmillert lp->d_secpercyl = ugp->d_secpercyl; 2476c33fcabaSmillert lp->d_secperunit = ugp->d_secperunit; 2477c33fcabaSmillert if (dgp != NULL && ugp->d_secsize == dgp->d_secsize && 2478c33fcabaSmillert ugp->d_nsectors == dgp->d_nsectors && 2479c33fcabaSmillert ugp->d_ntracks == dgp->d_ntracks && 2480c33fcabaSmillert ugp->d_ncylinders == dgp->d_ncylinders && 2481c33fcabaSmillert ugp->d_secpercyl == dgp->d_secpercyl && 2482c33fcabaSmillert ugp->d_secperunit == dgp->d_secperunit) 2483c33fcabaSmillert fputs("Note: user geometry is the same as disk " 2484c33fcabaSmillert "geometry.\n", stderr); 2485c33fcabaSmillert } 2486c33fcabaSmillert break; 2487c33fcabaSmillert default: 2488c33fcabaSmillert fputs("You must enter either 'd', 'b', or 'u'.\n", stderr); 2489c33fcabaSmillert break; 2490c33fcabaSmillert } 2491c33fcabaSmillert } 24929afbe9eeSmillert 24939afbe9eeSmillert void 24949afbe9eeSmillert zero_partitions(lp, freep) 24959afbe9eeSmillert struct disklabel *lp; 24969afbe9eeSmillert u_int32_t *freep; 24979afbe9eeSmillert { 24989afbe9eeSmillert int i; 24999afbe9eeSmillert 25009afbe9eeSmillert for (i = 0; i < MAXPARTITIONS; i++) 25019afbe9eeSmillert memset(&lp->d_partitions[i], 0, sizeof(struct partition)); 25029afbe9eeSmillert lp->d_partitions[RAW_PART].p_offset = starting_sector; 25039afbe9eeSmillert lp->d_partitions[RAW_PART].p_size = ending_sector - starting_sector; 25049afbe9eeSmillert editor_countfree(lp, freep); 25059afbe9eeSmillert } 2506