1*528915f5Smillert /* $OpenBSD: editor.c,v 1.54 1999/03/21 17:22:33 millert Exp $ */ 26fe57b42Smillert 36fe57b42Smillert /* 45362a395Smillert * Copyright (c) 1997-1999 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*528915f5Smillert static char rcsid[] = "$OpenBSD: editor.c,v 1.54 1999/03/21 17:22:33 millert Exp $"; 326fe57b42Smillert #endif /* not lint */ 336fe57b42Smillert 346fe57b42Smillert #include <sys/types.h> 356fe57b42Smillert #include <sys/param.h> 366fe57b42Smillert #define DKTYPENAMES 376fe57b42Smillert #include <sys/disklabel.h> 386fe57b42Smillert 396fe57b42Smillert #include <ufs/ffs/fs.h> 406fe57b42Smillert 416fe57b42Smillert #include <ctype.h> 426fe57b42Smillert #include <err.h> 436fe57b42Smillert #include <errno.h> 446fe57b42Smillert #include <string.h> 45803ff7d5Smillert #include <libgen.h> 466fe57b42Smillert #include <stdio.h> 476fe57b42Smillert #include <stdlib.h> 486fe57b42Smillert #include <unistd.h> 496fe57b42Smillert 504793b14cSmillert #include "pathnames.h" 514793b14cSmillert 526fe57b42Smillert /* flags for getuint() */ 536fe57b42Smillert #define DO_CONVERSIONS 0x00000001 546fe57b42Smillert #define DO_ROUNDING 0x00000002 556fe57b42Smillert 56f98aebd4Smillert #ifndef NUMBOOT 57f98aebd4Smillert #define NUMBOOT 0 58f98aebd4Smillert #endif 59f98aebd4Smillert 6096a888c6Smillert /* structure to describe a portion of a disk */ 6196a888c6Smillert struct diskchunk { 6296a888c6Smillert u_int32_t start; 6396a888c6Smillert u_int32_t stop; 6496a888c6Smillert }; 6596a888c6Smillert 663f843443Smillert /* used when sorting mountpoints in mpsave() */ 673f843443Smillert struct mountinfo { 683f843443Smillert char *mountpoint; 693f843443Smillert int partno; 703f843443Smillert }; 713f843443Smillert 726fe57b42Smillert void edit_parms __P((struct disklabel *, u_int32_t *)); 73bd6726faSmillert int editor __P((struct disklabel *, int, char *, char *)); 74bd6726faSmillert void editor_add __P((struct disklabel *, char **, u_int32_t *, char *)); 756fe57b42Smillert void editor_change __P((struct disklabel *, u_int32_t *, char *)); 76c0bdc608Smillert void editor_countfree __P((struct disklabel *, u_int32_t *)); 77bd6726faSmillert void editor_delete __P((struct disklabel *, char **, u_int32_t *, char *)); 78bd6726faSmillert void editor_display __P((struct disklabel *, char **, u_int32_t *, char)); 79617e6e4aSmillert void editor_help __P((char *)); 80bd6726faSmillert void editor_modify __P((struct disklabel *, char **, u_int32_t *, char *)); 81bd6726faSmillert void editor_name __P((struct disklabel *, char **, char *)); 826fe57b42Smillert char *getstring __P((struct disklabel *, char *, char *, char *)); 834b9a3bdaSmillert u_int32_t getuint __P((struct disklabel *, int, char *, char *, u_int32_t, u_int32_t, u_int32_t, int)); 846fe57b42Smillert int has_overlap __P((struct disklabel *, u_int32_t *, int)); 856fe57b42Smillert void make_contiguous __P((struct disklabel *)); 8696a888c6Smillert u_int32_t next_offset __P((struct disklabel *, struct partition *)); 876fe57b42Smillert int partition_cmp __P((const void *, const void *)); 88a7e61405Smillert struct partition **sort_partitions __P((struct disklabel *, u_int16_t *)); 89803ff7d5Smillert void getdisktype __P((struct disklabel *, char *, char *)); 9096a888c6Smillert void find_bounds __P((struct disklabel *)); 91e8e8bdb7Sart void set_bounds __P((struct disklabel *, u_int32_t *)); 9296a888c6Smillert struct diskchunk *free_chunks __P((struct disklabel *)); 93bd6726faSmillert char ** mpcopy __P((char **, char **)); 943f843443Smillert int micmp __P((const void *, const void *)); 95bd6726faSmillert int mpequal __P((char **, char **)); 96bd6726faSmillert int mpsave __P((struct disklabel *, char **, char *, char *)); 9724a2c1a4Smillert int get_bsize __P((struct disklabel *, int)); 9824a2c1a4Smillert int get_cpg __P((struct disklabel *, int)); 9924a2c1a4Smillert int get_fsize __P((struct disklabel *, int)); 10024a2c1a4Smillert int get_fstype __P((struct disklabel *, int)); 10124a2c1a4Smillert int get_mp __P((struct disklabel *, char **, int)); 10224a2c1a4Smillert int get_offset __P((struct disklabel *, int)); 10324a2c1a4Smillert int get_size __P((struct disklabel *, int, u_int32_t *, int)); 10496a888c6Smillert 10596a888c6Smillert static u_int32_t starting_sector; 10696a888c6Smillert static u_int32_t ending_sector; 1076fe57b42Smillert 1086fe57b42Smillert /* from disklabel.c */ 1096fe57b42Smillert int checklabel __P((struct disklabel *)); 1106fe57b42Smillert void display __P((FILE *, struct disklabel *)); 111bd6726faSmillert void display_partition __P((FILE *, struct disklabel *, char **, int, char, int)); 112af98caf3Sderaadt int width_partition __P((struct disklabel *, int)); 113af98caf3Sderaadt 1146fe57b42Smillert struct disklabel *readlabel __P((int)); 1156fe57b42Smillert struct disklabel *makebootarea __P((char *, struct disklabel *, int)); 1166fe57b42Smillert int writelabel __P((int, char *, struct disklabel *)); 1176fe57b42Smillert extern char *bootarea, *specname; 11869220492Smillert extern int donothing; 1194793b14cSmillert #ifdef DOSLABEL 1204793b14cSmillert struct dos_partition *dosdp; /* DOS partition, if found */ 1214793b14cSmillert #endif 1226fe57b42Smillert 1236fe57b42Smillert /* 1246fe57b42Smillert * Simple partition editor. Primarily intended for new labels. 1256fe57b42Smillert */ 1266fe57b42Smillert int 127bd6726faSmillert editor(lp, f, dev, fstabfile) 1286fe57b42Smillert struct disklabel *lp; 1296fe57b42Smillert int f; 130803ff7d5Smillert char *dev; 131bd6726faSmillert char *fstabfile; 1326fe57b42Smillert { 1336fe57b42Smillert struct disklabel lastlabel, tmplabel, label = *lp; 13496a888c6Smillert struct partition *pp; 13596a888c6Smillert u_int32_t freesectors; 1366fe57b42Smillert FILE *fp; 1376fe57b42Smillert char buf[BUFSIZ], *cmd, *arg; 138bd6726faSmillert char **mountpoints = NULL, **omountpoints, **tmpmountpoints; 139bd6726faSmillert 140bd6726faSmillert /* Alloc and init mount point info */ 141bd6726faSmillert if (fstabfile) { 142bd6726faSmillert if (!(mountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 143bd6726faSmillert !(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 144bd6726faSmillert !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *)))) 145bd6726faSmillert errx(4, "out of memory"); 146bd6726faSmillert } 1476fe57b42Smillert 14896a888c6Smillert /* Don't allow disk type of "unknown" */ 149803ff7d5Smillert getdisktype(&label, "You need to specify a type for this disk.", dev); 1506fe57b42Smillert 15196a888c6Smillert /* How big is the OpenBSD portion of the disk? */ 15296a888c6Smillert find_bounds(&label); 15396a888c6Smillert 15496a888c6Smillert /* Set freesectors based on bounds and initial label */ 155c0bdc608Smillert editor_countfree(&label, &freesectors); 15696a888c6Smillert 15796a888c6Smillert /* Make sure there is no partition overlap. */ 15896a888c6Smillert if (has_overlap(&label, &freesectors, 1)) 1596fe57b42Smillert errx(1, "can't run when there is partition overlap."); 1606fe57b42Smillert 16196a888c6Smillert /* If we don't have a 'c' partition, create one. */ 16296a888c6Smillert pp = &label.d_partitions[2]; 16396a888c6Smillert if (label.d_npartitions < 3 || pp->p_size == 0) { 16496a888c6Smillert puts("No 'c' partition found, adding one that spans the disk."); 16596a888c6Smillert if (label.d_npartitions < 3) 16696a888c6Smillert label.d_npartitions = 3; 16796a888c6Smillert pp->p_offset = 0; 16896a888c6Smillert pp->p_size = label.d_secperunit; 16996a888c6Smillert pp->p_fstype = FS_UNUSED; 17096a888c6Smillert pp->p_fsize = pp->p_frag = pp->p_cpg = 0; 17196a888c6Smillert } 1720f820bbbSmillert 1736fe57b42Smillert #ifdef CYLCHECK 1746fe57b42Smillert puts("This platform requires that partition offsets/sizes be on cylinder boundaries.\nPartition offsets/sizes will be rounded to the nearest cylinder automatically."); 1756fe57b42Smillert #endif 1766fe57b42Smillert 177bd6726faSmillert /* Set d_bbsize and d_sbsize as necessary */ 17855403f76Smillert if (strcmp(label.d_packname, "fictitious") == 0) { 17955403f76Smillert if (label.d_bbsize == 0) 18055403f76Smillert label.d_bbsize = BBSIZE; 18155403f76Smillert if (label.d_sbsize == 0) 18255403f76Smillert label.d_sbsize = SBSIZE; 18355403f76Smillert } 184f98aebd4Smillert 185440b1d70Smillert /* Interleave must be >= 1 */ 186440b1d70Smillert if (label.d_interleave == 0) 187440b1d70Smillert label.d_interleave = 1; 188440b1d70Smillert 18996a888c6Smillert puts("\nInitial label editor (enter '?' for help at any prompt)"); 1906fe57b42Smillert lastlabel = label; 1916fe57b42Smillert for (;;) { 1926fe57b42Smillert fputs("> ", stdout); 1936fe57b42Smillert fflush(stdout); 1946fe57b42Smillert rewind(stdin); 1956e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1966e0becc5Smillert putchar('\n'); 1976e0becc5Smillert buf[0] = 'q'; 1986e0becc5Smillert buf[1] = '\0'; 1996e0becc5Smillert } 200260513deSmillert if ((cmd = strtok(buf, " \t\r\n")) == NULL) 201260513deSmillert continue; 202260513deSmillert arg = strtok(NULL, " \t\r\n"); 2036fe57b42Smillert 2046fe57b42Smillert switch (*cmd) { 2056fe57b42Smillert 2066fe57b42Smillert case '?': 207ea37abd3Sderaadt case 'h': 208617e6e4aSmillert editor_help(arg ? arg : ""); 2096fe57b42Smillert break; 2106fe57b42Smillert 2116fe57b42Smillert case 'a': 2126fe57b42Smillert tmplabel = lastlabel; 2136fe57b42Smillert lastlabel = label; 214bd6726faSmillert if (mountpoints != NULL) { 215bd6726faSmillert mpcopy(tmpmountpoints, omountpoints); 216bd6726faSmillert mpcopy(omountpoints, mountpoints); 217bd6726faSmillert } 218bd6726faSmillert editor_add(&label, mountpoints, &freesectors, arg); 21996a888c6Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 22096a888c6Smillert lastlabel = tmplabel; 221bd6726faSmillert if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints)) 222bd6726faSmillert mpcopy(omountpoints, tmpmountpoints); 22396a888c6Smillert break; 22496a888c6Smillert 22596a888c6Smillert case 'b': 22696a888c6Smillert tmplabel = lastlabel; 22796a888c6Smillert lastlabel = label; 228e8e8bdb7Sart set_bounds(&label, &freesectors); 2296fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2306fe57b42Smillert lastlabel = tmplabel; 2316fe57b42Smillert break; 2326fe57b42Smillert 2336fe57b42Smillert case 'c': 2346fe57b42Smillert tmplabel = lastlabel; 2356fe57b42Smillert lastlabel = label; 23696a888c6Smillert editor_change(&label, &freesectors, arg); 2376fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2386fe57b42Smillert lastlabel = tmplabel; 2396fe57b42Smillert break; 2406fe57b42Smillert 2416fe57b42Smillert case 'd': 2426fe57b42Smillert tmplabel = lastlabel; 2436fe57b42Smillert lastlabel = label; 244bd6726faSmillert if (mountpoints != NULL) { 245bd6726faSmillert mpcopy(tmpmountpoints, omountpoints); 246bd6726faSmillert mpcopy(omountpoints, mountpoints); 247bd6726faSmillert } 248bd6726faSmillert editor_delete(&label, mountpoints, &freesectors, arg); 2496fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2506fe57b42Smillert lastlabel = tmplabel; 251bd6726faSmillert if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints)) 252bd6726faSmillert mpcopy(omountpoints, tmpmountpoints); 2536fe57b42Smillert break; 2546fe57b42Smillert 2556fe57b42Smillert case 'm': 2566fe57b42Smillert tmplabel = lastlabel; 2576fe57b42Smillert lastlabel = label; 258bd6726faSmillert if (mountpoints != NULL) { 259bd6726faSmillert mpcopy(tmpmountpoints, omountpoints); 260bd6726faSmillert mpcopy(omountpoints, mountpoints); 261bd6726faSmillert } 262bd6726faSmillert editor_modify(&label, mountpoints, &freesectors, arg); 2636fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2646fe57b42Smillert lastlabel = tmplabel; 265bd6726faSmillert if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints)) 266bd6726faSmillert mpcopy(omountpoints, tmpmountpoints); 267bd6726faSmillert break; 268bd6726faSmillert 269bd6726faSmillert case 'n': 270bd6726faSmillert if (mountpoints == NULL) { 271bd6726faSmillert fputs("This option is not valid when run " 272bd6726faSmillert "without the -F flag.\n", stderr); 273bd6726faSmillert break; 274bd6726faSmillert } 275bd6726faSmillert mpcopy(tmpmountpoints, omountpoints); 276bd6726faSmillert mpcopy(omountpoints, mountpoints); 277bd6726faSmillert editor_name(&label, mountpoints, arg); 278bd6726faSmillert if (mpequal(omountpoints, tmpmountpoints)) 279bd6726faSmillert mpcopy(omountpoints, tmpmountpoints); 2806fe57b42Smillert break; 2816fe57b42Smillert 2826fe57b42Smillert case 'p': 283bd6726faSmillert editor_display(&label, mountpoints, &freesectors, 284bd6726faSmillert arg ? *arg : 0); 2856fe57b42Smillert break; 2866fe57b42Smillert 287508086e9Smillert case 'M': { 288508086e9Smillert sig_t opipe = signal(SIGPIPE, SIG_IGN); 289508086e9Smillert char *pager; 2905d12b01bSderaadt extern char manpage[]; 2915d12b01bSderaadt 292508086e9Smillert if ((pager = getenv("PAGER")) == NULL) 293508086e9Smillert pager = _PATH_LESS; 294508086e9Smillert if ((fp = popen(pager, "w")) != NULL) { 2955d12b01bSderaadt (void) fwrite(manpage, strlen(manpage), 1, fp); 2965d12b01bSderaadt pclose(fp); 297508086e9Smillert } else 298508086e9Smillert warn("unable to execute %s", pager); 299508086e9Smillert 300508086e9Smillert (void)signal(SIGPIPE, opipe); 3015d12b01bSderaadt break; 302508086e9Smillert } 3035d12b01bSderaadt 3046fe57b42Smillert case 'q': 30569220492Smillert if (donothing) { 30669220492Smillert puts("In no change mode, not writing label."); 30769220492Smillert return(1); 30869220492Smillert } 309bd6726faSmillert /* Save mountpoint info if there is any. */ 310bd6726faSmillert if (mountpoints != NULL) 311bd6726faSmillert mpsave(&label, mountpoints, dev, fstabfile); 3126fe57b42Smillert if (memcmp(lp, &label, sizeof(label)) == 0) { 313bd6726faSmillert puts("No label changes."); 3146fe57b42Smillert return(1); 3156fe57b42Smillert } 3166fe57b42Smillert do { 317bd6726faSmillert arg = getstring(&label, "Save changes?", 3186fe57b42Smillert "Save changes you have made to the label?", 3196fe57b42Smillert "n"); 32096a888c6Smillert } while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n'); 32196a888c6Smillert if (arg && tolower(*arg) == 'y') { 3226fe57b42Smillert *lp = label; 3236fe57b42Smillert if (writelabel(f, bootarea, lp) == 0) 3246fe57b42Smillert return(0); 3256fe57b42Smillert } 3266fe57b42Smillert return(1); 3276fe57b42Smillert /* NOTREACHED */ 3286fe57b42Smillert break; 3296fe57b42Smillert 330c0bdc608Smillert case 'r': 331c0bdc608Smillert /* Recalculate free space */ 332c0bdc608Smillert editor_countfree(&label, &freesectors); 333c0bdc608Smillert puts("Recalculated free space."); 334c0bdc608Smillert break; 335c0bdc608Smillert 3366fe57b42Smillert case 's': 3376fe57b42Smillert if (arg == NULL) { 338260513deSmillert arg = getstring(lp, "Filename", 3396fe57b42Smillert "Name of the file to save label into.", 3406fe57b42Smillert NULL); 34196a888c6Smillert if (arg == NULL && *arg == '\0') 3426fe57b42Smillert break; 3436fe57b42Smillert } 3446fe57b42Smillert if ((fp = fopen(arg, "w")) == NULL) { 3456fe57b42Smillert warn("cannot open %s", arg); 3466fe57b42Smillert } else { 3476fe57b42Smillert display(fp, &label); 3486fe57b42Smillert (void)fclose(fp); 3496fe57b42Smillert } 3506fe57b42Smillert break; 3516fe57b42Smillert 3526fe57b42Smillert case 'u': 353bd6726faSmillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0 && 354bd6726faSmillert mountpoints != NULL && 355bd6726faSmillert mpequal(mountpoints, omountpoints)) { 3566fe57b42Smillert puts("Nothing to undo!"); 3576fe57b42Smillert } else { 3586fe57b42Smillert tmplabel = label; 3596fe57b42Smillert label = lastlabel; 3606fe57b42Smillert lastlabel = tmplabel; 361c0bdc608Smillert /* Recalculate free space */ 362c0bdc608Smillert editor_countfree(&label, &freesectors); 363bd6726faSmillert /* Restore mountpoints */ 364bd6726faSmillert if (mountpoints != NULL) 365bd6726faSmillert mpcopy(mountpoints, omountpoints); 3666fe57b42Smillert puts("Last change undone."); 3676fe57b42Smillert } 3686fe57b42Smillert break; 3696fe57b42Smillert 370040947cfSmillert case 'w': 371bd6726faSmillert if (donothing) { 372040947cfSmillert puts("In no change mode, not writing label."); 373bd6726faSmillert break; 374bd6726faSmillert } 375bd6726faSmillert /* Save mountpoint info if there is any. */ 376bd6726faSmillert if (mountpoints != NULL) 377bd6726faSmillert mpsave(&label, mountpoints, dev, fstabfile); 378bd6726faSmillert /* Save label if it has changed. */ 379bd6726faSmillert if (memcmp(lp, &label, sizeof(label)) == 0) 380bd6726faSmillert puts("No label changes."); 381040947cfSmillert else if (writelabel(f, bootarea, &label) != 0) 382040947cfSmillert warnx("unable to write label"); 3835af08e9cSmillert else 3845af08e9cSmillert *lp = label; 385040947cfSmillert break; 386040947cfSmillert 3876fe57b42Smillert case 'x': 3886fe57b42Smillert return(1); 3896fe57b42Smillert break; 3906fe57b42Smillert 3916fe57b42Smillert case '\n': 3926fe57b42Smillert break; 3936fe57b42Smillert 3946fe57b42Smillert case 'e': 3956fe57b42Smillert tmplabel = lastlabel; 3966fe57b42Smillert lastlabel = label; 39796a888c6Smillert edit_parms(&label, &freesectors); 3986fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 3996fe57b42Smillert lastlabel = tmplabel; 4006fe57b42Smillert break; 4016fe57b42Smillert 4026fe57b42Smillert default: 4036fe57b42Smillert printf("Unknown option: %c ('?' for help)\n", *cmd); 4046fe57b42Smillert break; 4056fe57b42Smillert } 4066fe57b42Smillert } 4076fe57b42Smillert } 4086fe57b42Smillert 4096fe57b42Smillert /* 4106fe57b42Smillert * Add a new partition. 4116fe57b42Smillert */ 4126fe57b42Smillert void 413bd6726faSmillert editor_add(lp, mp, freep, p) 4146fe57b42Smillert struct disklabel *lp; 415bd6726faSmillert char **mp; 4166fe57b42Smillert u_int32_t *freep; 4176fe57b42Smillert char *p; 4186fe57b42Smillert { 41996a888c6Smillert struct partition *pp; 42096a888c6Smillert struct diskchunk *chunks; 4216fe57b42Smillert char buf[BUFSIZ]; 4226fe57b42Smillert int i, partno; 42396a888c6Smillert u_int32_t ui, old_offset, old_size; 4246fe57b42Smillert 4256fe57b42Smillert /* XXX - prompt user to steal space from another partition instead */ 4266fe57b42Smillert if (*freep == 0) { 4276fe57b42Smillert fputs("No space left, you need to shrink a partition\n", 4286fe57b42Smillert stderr); 4296fe57b42Smillert return; 4306fe57b42Smillert } 4316fe57b42Smillert 4326fe57b42Smillert /* XXX - make more like other editor_* */ 4336fe57b42Smillert if (p != NULL) { 4346fe57b42Smillert partno = p[0] - 'a'; 435e6ab932bSmillert if (partno < 0 || partno == 2 || partno >= MAXPARTITIONS) { 4366fe57b42Smillert fprintf(stderr, 437e6ab932bSmillert "Partition must be between 'a' and '%c' " 438e6ab932bSmillert "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1); 4396fe57b42Smillert return; 44096a888c6Smillert } else if (lp->d_partitions[partno].p_fstype != FS_UNUSED && 441f6299b35Sderaadt lp->d_partitions[partno].p_size != 0) { 442f6299b35Sderaadt fprintf(stderr, 443f6299b35Sderaadt "Partition '%c' exists. Delete it first.\n", 444f6299b35Sderaadt p[0]); 445f6299b35Sderaadt return; 4466fe57b42Smillert } 4476fe57b42Smillert } else { 4489c5f1350Smillert /* Find first unused partition that is not 'c' */ 4496fe57b42Smillert for (partno = 0; partno < MAXPARTITIONS; partno++, p++) { 4509c5f1350Smillert if (lp->d_partitions[partno].p_size == 0 && partno != 2) 4516fe57b42Smillert break; 4526fe57b42Smillert } 4536fe57b42Smillert if (partno < MAXPARTITIONS) { 4546fe57b42Smillert buf[0] = partno + 'a'; 4556fe57b42Smillert buf[1] = '\0'; 4566fe57b42Smillert p = &buf[0]; 4576fe57b42Smillert } else 4586fe57b42Smillert p = NULL; 4596fe57b42Smillert for (;;) { 4606fe57b42Smillert p = getstring(lp, "partition", 4616fe57b42Smillert "The letter of the new partition, a - p.", p); 46296a888c6Smillert if (p == NULL) 46396a888c6Smillert return; 4646fe57b42Smillert partno = p[0] - 'a'; 46596a888c6Smillert if (lp->d_partitions[partno].p_fstype != FS_UNUSED && 46696a888c6Smillert lp->d_partitions[partno].p_size != 0) { 46796a888c6Smillert fprintf(stderr, 46896a888c6Smillert "Partition '%c' already exists.\n", p[0]); 46996a888c6Smillert } else if (partno >= 0 && partno < MAXPARTITIONS) 4706fe57b42Smillert break; 4716fe57b42Smillert fprintf(stderr, 4726fe57b42Smillert "Partition must be between 'a' and '%c'.\n", 4736fe57b42Smillert 'a' + MAXPARTITIONS - 1); 4746fe57b42Smillert } 4756fe57b42Smillert } 47696a888c6Smillert 47796a888c6Smillert /* Increase d_npartitions if necesary */ 47896a888c6Smillert if (partno >= lp->d_npartitions) 47996a888c6Smillert lp->d_npartitions = partno + 1; 48096a888c6Smillert 48196a888c6Smillert /* Set defaults */ 4826fe57b42Smillert pp = &lp->d_partitions[partno]; 4836fe57b42Smillert if (partno >= lp->d_npartitions) 4846fe57b42Smillert lp->d_npartitions = partno + 1; 4856fe57b42Smillert memset(pp, 0, sizeof(*pp)); 48696a888c6Smillert pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS; 4876fe57b42Smillert pp->p_fsize = 1024; 4886fe57b42Smillert pp->p_frag = 8; 4896fe57b42Smillert pp->p_cpg = 16; 49096a888c6Smillert pp->p_size = *freep; 49196a888c6Smillert pp->p_offset = next_offset(lp, pp); /* must be computed last */ 492f98aebd4Smillert #if NUMBOOT == 1 493f98aebd4Smillert /* Don't clobber boot blocks */ 494f98aebd4Smillert if (pp->p_offset == 0) { 4958dddfaa0Smillert pp->p_offset = lp->d_secpercyl; 4968dddfaa0Smillert pp->p_size -= lp->d_secpercyl; 497f98aebd4Smillert } 498f98aebd4Smillert #endif 49996a888c6Smillert old_offset = pp->p_offset; 50096a888c6Smillert old_size = pp->p_size; 50196a888c6Smillert 50296a888c6Smillert getoff1: 50396a888c6Smillert /* Get offset */ 50424a2c1a4Smillert if (get_offset(lp, partno) != 0) { 50596a888c6Smillert pp->p_size = 0; /* effective delete */ 50696a888c6Smillert return; 50796a888c6Smillert } 50896a888c6Smillert 50996a888c6Smillert /* Recompute recommended size based on new offset */ 51096a888c6Smillert ui = pp->p_fstype; 51196a888c6Smillert pp->p_fstype = FS_UNUSED; 51296a888c6Smillert chunks = free_chunks(lp); 51396a888c6Smillert for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 51496a888c6Smillert if (pp->p_offset >= chunks[i].start && 51596a888c6Smillert pp->p_offset < chunks[i].stop) { 51696a888c6Smillert pp->p_size = chunks[i].stop - pp->p_offset; 51796a888c6Smillert break; 51896a888c6Smillert } 51996a888c6Smillert } 52096a888c6Smillert pp->p_fstype = ui; 52196a888c6Smillert 52296a888c6Smillert /* Get size */ 52324a2c1a4Smillert if (get_size(lp, partno, freep, 1) != 0 || pp->p_size == 0) { 52496a888c6Smillert pp->p_size = 0; /* effective delete */ 52596a888c6Smillert return; 52696a888c6Smillert } 52796a888c6Smillert 52896a888c6Smillert /* Check for overlap */ 52996a888c6Smillert if (has_overlap(lp, freep, 0)) { 5304793b14cSmillert printf("\nPlease re-enter an offset and size for partition " 5314793b14cSmillert "%c.\n", 'a' + partno); 53296a888c6Smillert pp->p_offset = old_offset; 53396a888c6Smillert pp->p_size = old_size; 53496a888c6Smillert goto getoff1; /* Yeah, I know... */ 53596a888c6Smillert } 5366fe57b42Smillert 53724a2c1a4Smillert /* Get filesystem type */ 53824a2c1a4Smillert if (get_fstype(lp, partno) != 0) { 53996a888c6Smillert pp->p_size = 0; /* effective delete */ 54096a888c6Smillert return; 54196a888c6Smillert } 5426fe57b42Smillert 5436fe57b42Smillert if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) { 54424a2c1a4Smillert /* Get fsize */ 54524a2c1a4Smillert if (get_fsize(lp, partno) != 0) { 54696a888c6Smillert pp->p_size = 0; /* effective delete */ 54796a888c6Smillert return; 5486fe57b42Smillert } 5496fe57b42Smillert 55024a2c1a4Smillert /* Get bsize */ 55124a2c1a4Smillert if (get_bsize(lp, partno) != 0) { 55296a888c6Smillert pp->p_size = 0; /* effective delete */ 55396a888c6Smillert return; 5546fe57b42Smillert } 5556fe57b42Smillert 5566fe57b42Smillert if (pp->p_fstype == FS_BSDFFS) { 5576fe57b42Smillert /* get cpg */ 55824a2c1a4Smillert if (get_cpg(lp, partno) != 0) { 55996a888c6Smillert pp->p_size = 0; /* effective delete */ 56096a888c6Smillert return; 5616fe57b42Smillert } 5626fe57b42Smillert } 56324a2c1a4Smillert 564bd6726faSmillert /* get mount point */ 56524a2c1a4Smillert if (get_mp(lp, mp, partno) != 0) { 566bd6726faSmillert pp->p_size = 0; /* effective delete */ 567bd6726faSmillert return; 568bd6726faSmillert } 5696fe57b42Smillert } 57096a888c6Smillert /* Update free sector count and make sure things stay contiguous. */ 5716fe57b42Smillert *freep -= pp->p_size; 57296a888c6Smillert if (pp->p_size + pp->p_offset > ending_sector || 57396a888c6Smillert has_overlap(lp, freep, -1)) 5746fe57b42Smillert make_contiguous(lp); 5756fe57b42Smillert } 5766fe57b42Smillert 5776fe57b42Smillert /* 578bd6726faSmillert * Set the mountpoint of an existing partition ('name'). 579bd6726faSmillert */ 580bd6726faSmillert void 581bd6726faSmillert editor_name(lp, mp, p) 582bd6726faSmillert struct disklabel *lp; 583bd6726faSmillert char **mp; 584bd6726faSmillert char *p; 585bd6726faSmillert { 586bd6726faSmillert struct partition *pp; 587bd6726faSmillert int partno; 588bd6726faSmillert 589bd6726faSmillert /* Change which partition? */ 590bd6726faSmillert if (p == NULL) { 591bd6726faSmillert p = getstring(lp, "partition to name", 592bd6726faSmillert "The letter of the partition to name, a - p.", NULL); 593bd6726faSmillert } 594bd6726faSmillert if (p == NULL) { 595bd6726faSmillert fputs("Command aborted\n", stderr); 596bd6726faSmillert return; 597bd6726faSmillert } 598bd6726faSmillert partno = p[0] - 'a'; 599bd6726faSmillert pp = &lp->d_partitions[partno]; 600bd6726faSmillert if (partno < 0 || partno >= lp->d_npartitions) { 601bd6726faSmillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 602bd6726faSmillert 'a' + lp->d_npartitions - 1); 603bd6726faSmillert return; 604bd6726faSmillert } else if (partno >= lp->d_npartitions || 605bd6726faSmillert (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) { 606bd6726faSmillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno); 607bd6726faSmillert return; 608bd6726faSmillert } 609bd6726faSmillert 610bd6726faSmillert /* Not all fstypes can be named */ 611bd6726faSmillert if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP || 612bd6726faSmillert pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER) { 613bd6726faSmillert fprintf(stderr, "You cannot name a filesystem of type %s.\n", 614bd6726faSmillert fstypesnames[lp->d_partitions[partno].p_fstype]); 615bd6726faSmillert return; 616bd6726faSmillert } 617bd6726faSmillert 618ddaff619Smillert get_mp(lp, mp, partno); 619bd6726faSmillert } 620bd6726faSmillert 621bd6726faSmillert /* 6226fe57b42Smillert * Change an existing partition. 6236fe57b42Smillert */ 6246fe57b42Smillert void 625bd6726faSmillert editor_modify(lp, mp, freep, p) 6266fe57b42Smillert struct disklabel *lp; 627bd6726faSmillert char **mp; 6286fe57b42Smillert u_int32_t *freep; 6296fe57b42Smillert char *p; 6306fe57b42Smillert { 6316fe57b42Smillert struct partition origpart, *pp; 6326fe57b42Smillert u_int32_t ui; 6336fe57b42Smillert int partno; 6346fe57b42Smillert 6356fe57b42Smillert /* Change which partition? */ 6366fe57b42Smillert if (p == NULL) { 6376fe57b42Smillert p = getstring(lp, "partition to modify", 6386fe57b42Smillert "The letter of the partition to modify, a - p.", NULL); 6396fe57b42Smillert } 64096a888c6Smillert if (p == NULL) { 64196a888c6Smillert fputs("Command aborted\n", stderr); 64296a888c6Smillert return; 64396a888c6Smillert } 6446fe57b42Smillert partno = p[0] - 'a'; 6456fe57b42Smillert pp = &lp->d_partitions[partno]; 6466fe57b42Smillert origpart = lp->d_partitions[partno]; 6476fe57b42Smillert if (partno < 0 || partno >= lp->d_npartitions) { 6486fe57b42Smillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 6496fe57b42Smillert 'a' + lp->d_npartitions - 1); 6506fe57b42Smillert return; 6516fe57b42Smillert } else if (partno >= lp->d_npartitions || 6526fe57b42Smillert (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) { 6536fe57b42Smillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno); 6546fe57b42Smillert return; 6556fe57b42Smillert } 6566fe57b42Smillert 6576fe57b42Smillert /* Get filesystem type */ 65824a2c1a4Smillert if (get_fstype(lp, partno) != 0) { 65924a2c1a4Smillert *pp = origpart; /* undo changes */ 66096a888c6Smillert return; 66196a888c6Smillert } 6626fe57b42Smillert 6636fe57b42Smillert /* Did they disable/enable the partition? */ 664229f463eSmillert if ((pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) && 665229f463eSmillert origpart.p_fstype != FS_UNUSED && origpart.p_fstype != FS_BOOT) 6666fe57b42Smillert *freep += origpart.p_size; 667229f463eSmillert else if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT && 668229f463eSmillert (origpart.p_fstype == FS_UNUSED || origpart.p_fstype == FS_BOOT)) { 6696fe57b42Smillert if (pp->p_size > *freep) { 6706fe57b42Smillert fprintf(stderr, 67196a888c6Smillert "Warning, need %u sectors but there are only %u " 6726fe57b42Smillert "free. Setting size to %u.\n", pp->p_size, *freep, 6736fe57b42Smillert *freep); 6746fe57b42Smillert pp->p_fstype = *freep; 6756fe57b42Smillert *freep = 0; 6766fe57b42Smillert } else 6776fe57b42Smillert *freep -= pp->p_size; /* have enough space */ 6786fe57b42Smillert } 6796fe57b42Smillert 6806fe57b42Smillert getoff2: 6816fe57b42Smillert /* Get offset */ 68224a2c1a4Smillert if (get_offset(lp, partno) != 0) { 68396a888c6Smillert *pp = origpart; /* undo changes */ 68496a888c6Smillert return; 6856fe57b42Smillert } 6866fe57b42Smillert 6876fe57b42Smillert /* Get size */ 68824a2c1a4Smillert if (get_size(lp, partno, freep, 0) != 0 || pp->p_size == 0) { 68924a2c1a4Smillert pp->p_size = 0; /* effective delete */ 69096a888c6Smillert return; 6916fe57b42Smillert } 6926fe57b42Smillert 6936fe57b42Smillert /* Check for overlap and restore if not resolved */ 6946fe57b42Smillert if (has_overlap(lp, freep, 0)) { 6956fe57b42Smillert puts("\nPlease re-enter an offset and size"); 6966fe57b42Smillert pp->p_offset = origpart.p_offset; 6976fe57b42Smillert pp->p_size = origpart.p_size; 6986fe57b42Smillert goto getoff2; /* Yeah, I know... */ 6996fe57b42Smillert } 7006fe57b42Smillert 7016fe57b42Smillert if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) { 7026fe57b42Smillert /* get fsize */ 70324a2c1a4Smillert if (get_fsize(lp, partno) != 0) { 70496a888c6Smillert *pp = origpart; /* undo changes */ 70596a888c6Smillert return; 7066fe57b42Smillert } 7076fe57b42Smillert 7086fe57b42Smillert /* get bsize */ 70924a2c1a4Smillert if (get_bsize(lp, partno) != 0) { 71096a888c6Smillert *pp = origpart; /* undo changes */ 71196a888c6Smillert return; 7126fe57b42Smillert } 7136fe57b42Smillert 7146fe57b42Smillert if (pp->p_fstype == FS_BSDFFS) { 7156fe57b42Smillert /* get cpg */ 71624a2c1a4Smillert if (get_cpg(lp, partno) != 0) { 71796a888c6Smillert *pp = origpart; /* undo changes */ 71896a888c6Smillert return; 7196fe57b42Smillert } 7206fe57b42Smillert } 7216fe57b42Smillert } 7226fe57b42Smillert 723bd6726faSmillert /* get mount point */ 72424a2c1a4Smillert if (get_mp(lp, mp, partno) != 0) { 72524a2c1a4Smillert *pp = origpart; /* undo changes */ 726bd6726faSmillert return; 727bd6726faSmillert } 728bd6726faSmillert 7296fe57b42Smillert /* Make sure things stay contiguous. */ 73096a888c6Smillert if (pp->p_size + pp->p_offset > ending_sector || 73196a888c6Smillert has_overlap(lp, freep, -1)) 7326fe57b42Smillert make_contiguous(lp); 7336fe57b42Smillert } 7346fe57b42Smillert 7356fe57b42Smillert /* 7366fe57b42Smillert * Delete an existing partition. 7376fe57b42Smillert */ 7386fe57b42Smillert void 739bd6726faSmillert editor_delete(lp, mp, freep, p) 7406fe57b42Smillert struct disklabel *lp; 741bd6726faSmillert char **mp; 7426fe57b42Smillert u_int32_t *freep; 7436fe57b42Smillert char *p; 7446fe57b42Smillert { 7456fe57b42Smillert int c; 7466fe57b42Smillert 7476fe57b42Smillert if (p == NULL) { 7486fe57b42Smillert p = getstring(lp, "partition to delete", 749945ae268Smillert "The letter of the partition to delete, a - p, or '*'.", 750945ae268Smillert NULL); 7516fe57b42Smillert } 75296a888c6Smillert if (p == NULL) { 75396a888c6Smillert fputs("Command aborted\n", stderr); 75496a888c6Smillert return; 75596a888c6Smillert } 756945ae268Smillert if (p[0] == '*') { 757945ae268Smillert for (c = 0; c < lp->d_npartitions; c++) { 758945ae268Smillert if (c == 2) 759945ae268Smillert continue; 760945ae268Smillert 761945ae268Smillert /* Update free sector count. */ 762945ae268Smillert if (lp->d_partitions[c].p_fstype != FS_UNUSED && 763945ae268Smillert lp->d_partitions[c].p_fstype != FS_BOOT && 764945ae268Smillert lp->d_partitions[c].p_size != 0) 765945ae268Smillert *freep += lp->d_partitions[c].p_size; 766945ae268Smillert 767945ae268Smillert (void)memset(&lp->d_partitions[c], 0, 768945ae268Smillert sizeof(lp->d_partitions[c])); 769945ae268Smillert } 770945ae268Smillert return; 771945ae268Smillert } 7726fe57b42Smillert c = p[0] - 'a'; 7736fe57b42Smillert if (c < 0 || c >= lp->d_npartitions) 7746fe57b42Smillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 7756fe57b42Smillert 'a' + lp->d_npartitions - 1); 7766fe57b42Smillert else if (c >= lp->d_npartitions || (lp->d_partitions[c].p_fstype == 7776fe57b42Smillert FS_UNUSED && lp->d_partitions[c].p_size == 0)) 7786fe57b42Smillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + c); 7796fe57b42Smillert else if (c == 2) 780617e6e4aSmillert fputs( 781617e6e4aSmillert "You may not delete the 'c' partition. The 'c' partition must exist and\n" 782617e6e4aSmillert "should span the entire disk. By default it is of type 'unused' and so\n" 783617e6e4aSmillert "does not take up any space.\n", stderr); 7846fe57b42Smillert else { 78596a888c6Smillert /* Update free sector count. */ 786e49c5d78Smillert if (lp->d_partitions[c].p_offset < ending_sector && 787e49c5d78Smillert lp->d_partitions[c].p_offset >= starting_sector && 788e49c5d78Smillert lp->d_partitions[c].p_fstype != FS_UNUSED && 789229f463eSmillert lp->d_partitions[c].p_fstype != FS_BOOT && 7906fe57b42Smillert lp->d_partitions[c].p_size != 0) 7916fe57b42Smillert *freep += lp->d_partitions[c].p_size; 7926fe57b42Smillert 7936fe57b42Smillert /* Really delete it (as opposed to just setting to "unused") */ 7946fe57b42Smillert (void)memset(&lp->d_partitions[c], 0, 7956fe57b42Smillert sizeof(lp->d_partitions[c])); 7966fe57b42Smillert } 797bd6726faSmillert if (mp != NULL && mp[c] != NULL) { 798bd6726faSmillert free(mp[c]); 799bd6726faSmillert mp[c] = NULL; 800bd6726faSmillert } 8016fe57b42Smillert } 8026fe57b42Smillert 8036fe57b42Smillert /* 8046fe57b42Smillert * Simplified display() for use with the builtin editor. 8056fe57b42Smillert */ 8066fe57b42Smillert void 807bd6726faSmillert editor_display(lp, mp, freep, unit) 8086fe57b42Smillert struct disklabel *lp; 809bd6726faSmillert char **mp; 8106fe57b42Smillert u_int32_t *freep; 8116fe57b42Smillert char unit; 8126fe57b42Smillert { 8136fe57b42Smillert int i; 814af98caf3Sderaadt int width; 8156fe57b42Smillert 8166fe57b42Smillert printf("device: %s\n", specname); 8170f820bbbSmillert printf("type: %s\n", dktypenames[lp->d_type]); 8186fe57b42Smillert printf("disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename); 8196fe57b42Smillert printf("label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname); 8206fe57b42Smillert printf("bytes/sector: %ld\n", (long)lp->d_secsize); 8216fe57b42Smillert printf("sectors/track: %ld\n", (long)lp->d_nsectors); 8226fe57b42Smillert printf("tracks/cylinder: %ld\n", (long)lp->d_ntracks); 8236fe57b42Smillert printf("sectors/cylinder: %ld\n", (long)lp->d_secpercyl); 8246fe57b42Smillert printf("cylinders: %ld\n", (long)lp->d_ncylinders); 8256fe57b42Smillert printf("total sectors: %ld\n", (long)lp->d_secperunit); 8266fe57b42Smillert printf("free sectors: %u\n", *freep); 8276fe57b42Smillert printf("rpm: %ld\n", (long)lp->d_rpm); 8286fe57b42Smillert printf("\n%d partitions:\n", lp->d_npartitions); 829af98caf3Sderaadt width = width_partition(lp, unit); 830af98caf3Sderaadt printf("# %*.*s %*.*s fstype [fsize bsize cpg]\n", 831af98caf3Sderaadt width, width, "size", width, width, "offset"); 8326fe57b42Smillert for (i = 0; i < lp->d_npartitions; i++) 833bd6726faSmillert display_partition(stdout, lp, mp, i, unit, width); 8346fe57b42Smillert } 8356fe57b42Smillert 8366fe57b42Smillert /* 8376fe57b42Smillert * Find the next reasonable starting offset and returns it. 83896a888c6Smillert * Assumes there is a least one free sector left (returns 0 if not). 8396fe57b42Smillert */ 8406fe57b42Smillert u_int32_t 84196a888c6Smillert next_offset(lp, pp) 8426fe57b42Smillert struct disklabel *lp; 84396a888c6Smillert struct partition *pp; 8446fe57b42Smillert { 845f0b4d0a9Smillert struct partition **spp; 84696a888c6Smillert struct diskchunk *chunks; 847f0b4d0a9Smillert u_int16_t npartitions; 84896a888c6Smillert u_int32_t new_offset, new_size; 84996a888c6Smillert int i, good_offset; 8506fe57b42Smillert 851a7e61405Smillert /* Get a sorted list of the partitions */ 85296a888c6Smillert if ((spp = sort_partitions(lp, &npartitions)) == NULL) 85396a888c6Smillert return(0); 854f0b4d0a9Smillert 85596a888c6Smillert new_offset = starting_sector; 856f0b4d0a9Smillert for (i = 0; i < npartitions; i++ ) { 85796a888c6Smillert /* Skip the partition for which we are finding an offset */ 85896a888c6Smillert if (pp == spp[i]) 85996a888c6Smillert continue; 86096a888c6Smillert 8616fe57b42Smillert /* 8626fe57b42Smillert * Is new_offset inside this partition? If so, 86396a888c6Smillert * make it the next sector after the partition ends. 8646fe57b42Smillert */ 8654793b14cSmillert if (spp[i]->p_offset + spp[i]->p_size < ending_sector && 8664793b14cSmillert ((new_offset >= spp[i]->p_offset && 86796a888c6Smillert new_offset < spp[i]->p_offset + spp[i]->p_size) || 86896a888c6Smillert (new_offset + pp->p_size >= spp[i]->p_offset && new_offset 8694793b14cSmillert + pp->p_size <= spp[i]->p_offset + spp[i]->p_size))) 870f0b4d0a9Smillert new_offset = spp[i]->p_offset + spp[i]->p_size; 8716fe57b42Smillert } 8726fe57b42Smillert 87396a888c6Smillert /* Did we find a suitable offset? */ 87496a888c6Smillert for (good_offset = 1, i = 0; i < npartitions; i++ ) { 87596a888c6Smillert if (new_offset + pp->p_size >= spp[i]->p_offset && 87696a888c6Smillert new_offset + pp->p_size <= spp[i]->p_offset + spp[i]->p_size) { 87796a888c6Smillert /* Nope */ 87896a888c6Smillert good_offset = 0; 87996a888c6Smillert break; 88096a888c6Smillert } 88196a888c6Smillert } 88296a888c6Smillert 88396a888c6Smillert /* Specified size is too big, find something that fits */ 88496a888c6Smillert if (!good_offset) { 88596a888c6Smillert chunks = free_chunks(lp); 88696a888c6Smillert new_size = 0; 88796a888c6Smillert for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 88896a888c6Smillert if (chunks[i].stop - chunks[i].start > new_size) { 88996a888c6Smillert new_size = chunks[i].stop - chunks[i].start; 89096a888c6Smillert new_offset = chunks[i].start; 89196a888c6Smillert } 89296a888c6Smillert } 8934793b14cSmillert /* XXX - should do something intelligent if new_size == 0 */ 89496a888c6Smillert pp->p_size = new_size; 89596a888c6Smillert } 89696a888c6Smillert 897f0b4d0a9Smillert (void)free(spp); 8986fe57b42Smillert return(new_offset); 8996fe57b42Smillert } 9006fe57b42Smillert 9016fe57b42Smillert /* 9026fe57b42Smillert * Change the size of an existing partition. 9036fe57b42Smillert */ 9046fe57b42Smillert void 9056fe57b42Smillert editor_change(lp, freep, p) 9066fe57b42Smillert struct disklabel *lp; 9076fe57b42Smillert u_int32_t *freep; 9086fe57b42Smillert char *p; 9096fe57b42Smillert { 9106fe57b42Smillert int partno; 9116fe57b42Smillert u_int32_t newsize; 9124b9a3bdaSmillert struct partition *pp; 9136fe57b42Smillert 9146fe57b42Smillert if (p == NULL) { 9156fe57b42Smillert p = getstring(lp, "partition to change size", 9166fe57b42Smillert "The letter of the partition to change size, a - p.", NULL); 9176fe57b42Smillert } 91896a888c6Smillert if (p == NULL) { 91996a888c6Smillert fputs("Command aborted\n", stderr); 92096a888c6Smillert return; 92196a888c6Smillert } 9226fe57b42Smillert partno = p[0] - 'a'; 9236fe57b42Smillert if (partno < 0 || partno >= lp->d_npartitions) { 9246fe57b42Smillert fprintf(stderr, "Partition must be between 'a' and '%c'.\n", 9256fe57b42Smillert 'a' + lp->d_npartitions - 1); 9266fe57b42Smillert return; 9276fe57b42Smillert } else if (partno >= lp->d_npartitions || 928229f463eSmillert lp->d_partitions[partno].p_size == 0) { 9296fe57b42Smillert fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno); 9306fe57b42Smillert return; 9316fe57b42Smillert } 9324b9a3bdaSmillert pp = &lp->d_partitions[partno]; 9336fe57b42Smillert 9346fe57b42Smillert printf("Partition %c is currently %u sectors in size (%u free).\n", 9354b9a3bdaSmillert partno + 'a', pp->p_size, *freep); 936229f463eSmillert /* XXX - make maxsize lp->d_secperunit if FS_UNUSED/FS_BOOT? */ 9376fe57b42Smillert newsize = getuint(lp, partno, "new size", "Size of the partition. " 9386fe57b42Smillert "You may also say +/- amount for a relative change.", 9394b9a3bdaSmillert pp->p_size, pp->p_size + *freep, pp->p_offset, DO_CONVERSIONS | 9404b9a3bdaSmillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 94196a888c6Smillert if (newsize == UINT_MAX - 1) { 94296a888c6Smillert fputs("Command aborted\n", stderr); 94396a888c6Smillert return; 94496a888c6Smillert } else if (newsize == UINT_MAX) { 9456fe57b42Smillert fputs("Invalid entry\n", stderr); 9466fe57b42Smillert return; 9474b9a3bdaSmillert } else if (newsize == pp->p_size) 9486fe57b42Smillert return; 9496fe57b42Smillert 9504b9a3bdaSmillert if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT) { 9514b9a3bdaSmillert if (newsize > pp->p_size) { 9524b9a3bdaSmillert if (newsize - pp->p_size > *freep) { 9536fe57b42Smillert fprintf(stderr, 9546fe57b42Smillert "Only %u sectors free, you asked for %u\n", 9554b9a3bdaSmillert *freep, newsize - pp->p_size); 9566fe57b42Smillert return; 9576fe57b42Smillert } 9584b9a3bdaSmillert *freep -= newsize - pp->p_size; 9594b9a3bdaSmillert } else if (newsize < pp->p_size) { 9604b9a3bdaSmillert *freep += pp->p_size - newsize; 9616fe57b42Smillert } 9626fe57b42Smillert } else { 96396a888c6Smillert if (partno == 2 && newsize + 9644b9a3bdaSmillert pp->p_offset > lp->d_secperunit) { 9656fe57b42Smillert fputs("'c' partition may not be larger than the disk\n", 9666fe57b42Smillert stderr); 9676fe57b42Smillert return; 9686fe57b42Smillert } 9696fe57b42Smillert } 9704b9a3bdaSmillert pp->p_size = newsize; 9714b9a3bdaSmillert if (newsize + pp->p_offset > ending_sector || 97296a888c6Smillert has_overlap(lp, freep, -1)) 9736fe57b42Smillert make_contiguous(lp); 9746fe57b42Smillert } 9756fe57b42Smillert 9766fe57b42Smillert void 9776fe57b42Smillert make_contiguous(lp) 9786fe57b42Smillert struct disklabel *lp; 9796fe57b42Smillert { 9806fe57b42Smillert struct partition **spp; 9816fe57b42Smillert u_int16_t npartitions; 9826fe57b42Smillert int i; 9836fe57b42Smillert 984a7e61405Smillert /* Get a sorted list of the partitions */ 98596a888c6Smillert if ((spp = sort_partitions(lp, &npartitions)) == NULL) 98696a888c6Smillert return; 9876fe57b42Smillert 9886fe57b42Smillert /* 989a7e61405Smillert * Make everything contiguous but don't muck with start of the first one 99096a888c6Smillert * or partitions not in the BSD part of the label. 9916fe57b42Smillert */ 99296a888c6Smillert for (i = 1; i < npartitions; i++) { 99396a888c6Smillert if (spp[i]->p_offset >= starting_sector || 99496a888c6Smillert spp[i]->p_offset < ending_sector) 99596a888c6Smillert spp[i]->p_offset = 99696a888c6Smillert spp[i - 1]->p_offset + spp[i - 1]->p_size; 99796a888c6Smillert } 998f0b4d0a9Smillert 999f0b4d0a9Smillert (void)free(spp); 10006fe57b42Smillert } 10016fe57b42Smillert 10026fe57b42Smillert /* 10036fe57b42Smillert * Sort the partitions based on starting offset. 10046fe57b42Smillert * This assumes there can be no overlap. 10056fe57b42Smillert */ 10066fe57b42Smillert int 10076fe57b42Smillert partition_cmp(e1, e2) 10086fe57b42Smillert const void *e1, *e2; 10096fe57b42Smillert { 10106fe57b42Smillert struct partition *p1 = *(struct partition **)e1; 10116fe57b42Smillert struct partition *p2 = *(struct partition **)e2; 10126fe57b42Smillert 10136fe57b42Smillert return((int)(p1->p_offset - p2->p_offset)); 10146fe57b42Smillert } 10156fe57b42Smillert 10166fe57b42Smillert char * 10176fe57b42Smillert getstring(lp, prompt, helpstring, oval) 10186fe57b42Smillert struct disklabel *lp; 10196fe57b42Smillert char *prompt; 10206fe57b42Smillert char *helpstring; 10216fe57b42Smillert char *oval; 10226fe57b42Smillert { 10236fe57b42Smillert static char buf[BUFSIZ]; 10246fe57b42Smillert int n; 10256fe57b42Smillert 10266fe57b42Smillert buf[0] = '\0'; 10276fe57b42Smillert do { 10286fe57b42Smillert printf("%s: [%s] ", prompt, oval ? oval : ""); 10296fe57b42Smillert fflush(stdout); 10306fe57b42Smillert rewind(stdin); 10316e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1032260513deSmillert buf[0] = '\0'; 103396a888c6Smillert if (feof(stdin)) { 103496a888c6Smillert putchar('\n'); 103596a888c6Smillert return(NULL); 103696a888c6Smillert } 10376e0becc5Smillert } 10386fe57b42Smillert n = strlen(buf); 10396fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 10406fe57b42Smillert buf[--n] = '\0'; 10416fe57b42Smillert if (buf[0] == '?') 10426fe57b42Smillert puts(helpstring); 10436fe57b42Smillert else if (oval != NULL && buf[0] == '\0') { 10446fe57b42Smillert (void)strncpy(buf, oval, sizeof(buf) - 1); 10456fe57b42Smillert buf[sizeof(buf) - 1] = '\0'; 10466fe57b42Smillert } 10476fe57b42Smillert } while (buf[0] == '?'); 10486fe57b42Smillert 10496fe57b42Smillert return(&buf[0]); 10506fe57b42Smillert } 10516fe57b42Smillert 10526fe57b42Smillert /* 10536fe57b42Smillert * Returns UINT_MAX on error 105424a2c1a4Smillert * Usually only called by helper functions. 10556fe57b42Smillert */ 10566fe57b42Smillert u_int32_t 10574b9a3bdaSmillert getuint(lp, partno, prompt, helpstring, oval, maxval, offset, flags) 10586fe57b42Smillert struct disklabel *lp; 10596fe57b42Smillert int partno; 10606fe57b42Smillert char *prompt; 10616fe57b42Smillert char *helpstring; 10626fe57b42Smillert u_int32_t oval; 10636fe57b42Smillert u_int32_t maxval; /* XXX - used inconsistently */ 10644b9a3bdaSmillert u_int32_t offset; 10656fe57b42Smillert int flags; 10666fe57b42Smillert { 10676fe57b42Smillert char buf[BUFSIZ], *endptr, *p, operator = '\0'; 10686fe57b42Smillert u_int32_t rval = oval; 10696fe57b42Smillert size_t n; 10706fe57b42Smillert int mult = 1; 107196a888c6Smillert double d; 10726fe57b42Smillert 10734b9a3bdaSmillert /* We only care about the remainder */ 10744b9a3bdaSmillert offset = offset % lp->d_secpercyl; 10754b9a3bdaSmillert 10766fe57b42Smillert buf[0] = '\0'; 10776fe57b42Smillert do { 10786fe57b42Smillert printf("%s: [%u] ", prompt, oval); 10796fe57b42Smillert fflush(stdout); 10806fe57b42Smillert rewind(stdin); 10816e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 10826e0becc5Smillert buf[0] = '\0'; 108396a888c6Smillert if (feof(stdin)) { 108496a888c6Smillert putchar('\n'); 108596a888c6Smillert return(UINT_MAX - 1); 108696a888c6Smillert } 10876e0becc5Smillert } 10886fe57b42Smillert n = strlen(buf); 10896fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 10906fe57b42Smillert buf[--n] = '\0'; 10916fe57b42Smillert if (buf[0] == '?') 10926fe57b42Smillert puts(helpstring); 10936fe57b42Smillert } while (buf[0] == '?'); 10946fe57b42Smillert 10956fe57b42Smillert if (buf[0] == '*' && buf[1] == '\0') { 10966fe57b42Smillert rval = maxval; 10976fe57b42Smillert } else { 10986fe57b42Smillert /* deal with units */ 10996fe57b42Smillert if (buf[0] != '\0' && n > 0) { 11006fe57b42Smillert if ((flags & DO_CONVERSIONS)) { 110196a888c6Smillert switch (tolower(buf[n-1])) { 11026fe57b42Smillert 11036fe57b42Smillert case 'c': 11046fe57b42Smillert mult = lp->d_secpercyl; 11056fe57b42Smillert buf[--n] = '\0'; 11066fe57b42Smillert break; 11076fe57b42Smillert case 'b': 11086fe57b42Smillert mult = -lp->d_secsize; 11096fe57b42Smillert buf[--n] = '\0'; 11106fe57b42Smillert break; 11116fe57b42Smillert case 'k': 11126fe57b42Smillert mult = 1024 / lp->d_secsize; 11136fe57b42Smillert buf[--n] = '\0'; 11146fe57b42Smillert break; 11156fe57b42Smillert case 'm': 11166fe57b42Smillert mult = 1048576 / lp->d_secsize; 11176fe57b42Smillert buf[--n] = '\0'; 11186fe57b42Smillert break; 11191a51a1eeSmillert case 'g': 11201a51a1eeSmillert mult = 1073741824 / lp->d_secsize; 11211a51a1eeSmillert buf[--n] = '\0'; 11221a51a1eeSmillert break; 11236fe57b42Smillert } 112496a888c6Smillert } 11256fe57b42Smillert 11266fe57b42Smillert /* Did they give us an operator? */ 11276fe57b42Smillert p = &buf[0]; 11286fe57b42Smillert if (*p == '+' || *p == '-') 11296fe57b42Smillert operator = *p++; 11306fe57b42Smillert 11316fe57b42Smillert endptr = p; 113296a888c6Smillert errno = 0; 113396a888c6Smillert d = strtod(p, &endptr); 113496a888c6Smillert if (errno == ERANGE) 113596a888c6Smillert rval = UINT_MAX; /* too big/small */ 113696a888c6Smillert else if (*endptr != '\0') { 11376fe57b42Smillert errno = EINVAL; /* non-numbers in str */ 11386fe57b42Smillert rval = UINT_MAX; 11396fe57b42Smillert } else { 114096a888c6Smillert /* XXX - should check for overflow */ 114196a888c6Smillert if (mult > 0) 114296a888c6Smillert rval = d * mult; 114396a888c6Smillert else 114496a888c6Smillert /* Negative mult means divide (fancy) */ 114596a888c6Smillert rval = d / (-mult); 11466fe57b42Smillert 114796a888c6Smillert /* Apply the operator */ 11486fe57b42Smillert if (operator == '+') 11496fe57b42Smillert rval += oval; 11506fe57b42Smillert else if (operator == '-') 11516fe57b42Smillert rval = oval - rval; 11526fe57b42Smillert } 11536fe57b42Smillert } 11546fe57b42Smillert } 11556fe57b42Smillert if ((flags & DO_ROUNDING) && rval < UINT_MAX) { 1156dbffb156Smillert #ifndef CYLCHECK 115796a888c6Smillert /* Round to nearest cylinder unless given in sectors */ 1158dbffb156Smillert if (mult != 1) 1159dbffb156Smillert #endif 1160dbffb156Smillert { 1161dbffb156Smillert u_int32_t cyls; 1162dbffb156Smillert 1163dbffb156Smillert /* If we round up past the end, round down instead */ 11646fe57b42Smillert cyls = (u_int32_t)((rval / (double)lp->d_secpercyl) 11656fe57b42Smillert + 0.5); 11664b9a3bdaSmillert if (cyls != 0 && lp->d_secpercyl != 0) { 11674b9a3bdaSmillert if ((cyls * lp->d_secpercyl) - offset > maxval) 1168dbffb156Smillert cyls--; 1169dbffb156Smillert 11704b9a3bdaSmillert if (rval != (cyls * lp->d_secpercyl) - offset) { 11714b9a3bdaSmillert rval = (cyls * lp->d_secpercyl) - offset; 11726fe57b42Smillert printf("Rounding to nearest cylinder: %u\n", 11736fe57b42Smillert rval); 11746fe57b42Smillert } 11756fe57b42Smillert } 11766fe57b42Smillert } 11774b9a3bdaSmillert } 11786fe57b42Smillert 11796fe57b42Smillert return(rval); 11806fe57b42Smillert } 11816fe57b42Smillert 11826fe57b42Smillert /* 11836fe57b42Smillert * Check for partition overlap in lp and prompt the user 11846fe57b42Smillert * to resolve the overlap if any is found. Returns 1 11856fe57b42Smillert * if unable to resolve, else 0. 11866fe57b42Smillert */ 11876fe57b42Smillert int 11886fe57b42Smillert has_overlap(lp, freep, resolve) 11896fe57b42Smillert struct disklabel *lp; 11906fe57b42Smillert u_int32_t *freep; 11916fe57b42Smillert int resolve; 11926fe57b42Smillert { 11936fe57b42Smillert struct partition **spp; 11946fe57b42Smillert u_int16_t npartitions; 1195e6aa8bafSmillert int c, i, j; 1196e6aa8bafSmillert char buf[BUFSIZ]; 11976fe57b42Smillert 1198a7e61405Smillert /* Get a sorted list of the partitions */ 1199a7e61405Smillert spp = sort_partitions(lp, &npartitions); 12006fe57b42Smillert 1201a7e61405Smillert if (npartitions < 2) { 1202a7e61405Smillert (void)free(spp); 12036fe57b42Smillert return(0); /* nothing to do */ 12046fe57b42Smillert } 12056fe57b42Smillert 12066fe57b42Smillert /* Now that we have things sorted by starting sector check overlap */ 12076fe57b42Smillert for (i = 0; i < npartitions; i++) { 12086fe57b42Smillert for (j = i + 1; j < npartitions; j++) { 12096fe57b42Smillert /* `if last_sec_in_part + 1 > first_sec_in_next_part' */ 12106fe57b42Smillert if (spp[i]->p_offset + spp[i]->p_size > spp[j]->p_offset) { 121196a888c6Smillert /* Don't print, just return */ 121296a888c6Smillert if (resolve == -1) { 121396a888c6Smillert (void)free(spp); 121496a888c6Smillert return(1); 121596a888c6Smillert } 121696a888c6Smillert 12176fe57b42Smillert /* Overlap! Convert to real part numbers. */ 12186fe57b42Smillert i = ((char *)spp[i] - (char *)lp->d_partitions) 12196fe57b42Smillert / sizeof(**spp); 12206fe57b42Smillert j = ((char *)spp[j] - (char *)lp->d_partitions) 12216fe57b42Smillert / sizeof(**spp); 12226fe57b42Smillert printf("\nError, partitions %c and %c overlap:\n", 12236fe57b42Smillert 'a' + i, 'a' + j); 12246fe57b42Smillert puts(" size offset fstype [fsize bsize cpg]"); 1225bd6726faSmillert display_partition(stdout, lp, NULL, i, 0, 0); 1226bd6726faSmillert display_partition(stdout, lp, NULL, j, 0, 0); 12276fe57b42Smillert 12286fe57b42Smillert /* Did they ask us to resolve it ourselves? */ 122996a888c6Smillert if (resolve != 1) { 1230f0b4d0a9Smillert (void)free(spp); 12316fe57b42Smillert return(1); 1232f0b4d0a9Smillert } 12336fe57b42Smillert 1234e6aa8bafSmillert /* Get partition to disable or ^D */ 1235e6aa8bafSmillert do { 1236616cd1c4Smillert printf("Disable which one? (^D to abort) [%c %c] ", 12376fe57b42Smillert 'a' + i, 'a' + j); 1238e6aa8bafSmillert buf[0] = '\0'; 1239616cd1c4Smillert if (!fgets(buf, sizeof(buf), stdin)) { 1240616cd1c4Smillert putchar('\n'); 1241e6aa8bafSmillert return(1); /* ^D */ 1242616cd1c4Smillert } 1243e6aa8bafSmillert c = buf[0] - 'a'; 1244e6aa8bafSmillert } while (buf[1] != '\n' && buf[1] != '\0' && 1245e6aa8bafSmillert c != i && c != j); 1246e6aa8bafSmillert 1247e6aa8bafSmillert /* Mark the selected one as unused */ 12486fe57b42Smillert lp->d_partitions[c].p_fstype = FS_UNUSED; 12496fe57b42Smillert *freep += lp->d_partitions[c].p_size; 1250e6aa8bafSmillert (void)free(spp); 1251e6aa8bafSmillert return(has_overlap(lp, freep, resolve)); 12526fe57b42Smillert } 12536fe57b42Smillert } 12546fe57b42Smillert } 1255f0b4d0a9Smillert 1256f0b4d0a9Smillert (void)free(spp); 1257e6aa8bafSmillert return(0); 12586fe57b42Smillert } 12596fe57b42Smillert 12606fe57b42Smillert void 12616fe57b42Smillert edit_parms(lp, freep) 12626fe57b42Smillert struct disklabel *lp; 12636fe57b42Smillert u_int32_t *freep; 12646fe57b42Smillert { 12656fe57b42Smillert char *p; 12666fe57b42Smillert u_int32_t ui; 126796a888c6Smillert struct disklabel oldlabel = *lp; 12686fe57b42Smillert 1269ea37abd3Sderaadt printf("Changing device parameters for %s:\n", specname); 12706fe57b42Smillert 12710f820bbbSmillert /* disk type */ 12720f820bbbSmillert for (;;) { 12730f820bbbSmillert p = getstring(lp, "disk type", 127441282a2aSmillert "What kind of disk is this? Usually SCSI, ESDI, ST506, or " 127541282a2aSmillert "floppy (use ESDI for IDE).", dktypenames[lp->d_type]); 127696a888c6Smillert if (p == NULL) { 127796a888c6Smillert fputs("Command aborted\n", stderr); 127896a888c6Smillert return; 127996a888c6Smillert } 128041282a2aSmillert if (strcasecmp(p, "IDE") == 0) 128141282a2aSmillert ui = DTYPE_ESDI; 128241282a2aSmillert else 128341282a2aSmillert for (ui = 1; ui < DKMAXTYPES && 128441282a2aSmillert strcasecmp(p, dktypenames[ui]); ui++) 12850f820bbbSmillert ; 12860f820bbbSmillert if (ui < DKMAXTYPES) { 12870f820bbbSmillert break; 12880f820bbbSmillert } else { 12890f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", p); 12900f820bbbSmillert fputs("Valid types are: ", stdout); 12910f820bbbSmillert for (ui = 1; ui < DKMAXTYPES; ui++) { 12920f820bbbSmillert printf("\"%s\"", dktypenames[ui]); 12930f820bbbSmillert if (ui < DKMAXTYPES - 1) 12940f820bbbSmillert fputs(", ", stdout); 12950f820bbbSmillert } 12960f820bbbSmillert putchar('\n'); 12970f820bbbSmillert } 12980f820bbbSmillert } 12990f820bbbSmillert lp->d_type = ui; 13000f820bbbSmillert 13016fe57b42Smillert /* pack/label id */ 13026fe57b42Smillert p = getstring(lp, "label name", 13036fe57b42Smillert "15 char string that describes this label, usually the disk name.", 13046fe57b42Smillert lp->d_packname); 130596a888c6Smillert if (p == NULL) { 130696a888c6Smillert fputs("Command aborted\n", stderr); 130796a888c6Smillert *lp = oldlabel; /* undo damage */ 130896a888c6Smillert return; 130996a888c6Smillert } 13106fe57b42Smillert strncpy(lp->d_packname, p, sizeof(lp->d_packname) - 1); 13116fe57b42Smillert lp->d_packname[sizeof(lp->d_packname) - 1] = '\0'; 13126fe57b42Smillert 13136fe57b42Smillert /* sectors/track */ 13146fe57b42Smillert for (;;) { 13156fe57b42Smillert ui = getuint(lp, 0, "sectors/track", 13166fe57b42Smillert "The Numer of sectors per track.", lp->d_nsectors, 13174b9a3bdaSmillert lp->d_nsectors, 0, 0); 131896a888c6Smillert if (ui == UINT_MAX - 1) { 131996a888c6Smillert fputs("Command aborted\n", stderr); 132096a888c6Smillert *lp = oldlabel; /* undo damage */ 132196a888c6Smillert return; 132296a888c6Smillert } if (ui == UINT_MAX) 13236fe57b42Smillert fputs("Invalid entry\n", stderr); 13246fe57b42Smillert else 13256fe57b42Smillert break; 13266fe57b42Smillert } 13276fe57b42Smillert lp->d_nsectors = ui; 13286fe57b42Smillert 13296fe57b42Smillert /* tracks/cylinder */ 13306fe57b42Smillert for (;;) { 13316fe57b42Smillert ui = getuint(lp, 0, "tracks/cylinder", 13326fe57b42Smillert "The number of tracks per cylinder.", lp->d_ntracks, 13334b9a3bdaSmillert lp->d_ntracks, 0, 0); 133496a888c6Smillert if (ui == UINT_MAX - 1) { 133596a888c6Smillert fputs("Command aborted\n", stderr); 133696a888c6Smillert *lp = oldlabel; /* undo damage */ 133796a888c6Smillert return; 133896a888c6Smillert } else if (ui == UINT_MAX) 13396fe57b42Smillert fputs("Invalid entry\n", stderr); 13406fe57b42Smillert else 13416fe57b42Smillert break; 13426fe57b42Smillert } 13436fe57b42Smillert lp->d_ntracks = ui; 13446fe57b42Smillert 13456fe57b42Smillert /* sectors/cylinder */ 1346148b6188Smillert for (;;) { 1347148b6188Smillert ui = getuint(lp, 0, "sectors/cylinder", 1348148b6188Smillert "The number of sectors per cylinder (Usually sectors/track " 13494b9a3bdaSmillert "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl, 13504b9a3bdaSmillert 0, 0); 135196a888c6Smillert if (ui == UINT_MAX - 1) { 135296a888c6Smillert fputs("Command aborted\n", stderr); 135396a888c6Smillert *lp = oldlabel; /* undo damage */ 135496a888c6Smillert return; 135596a888c6Smillert } else if (ui == UINT_MAX) 1356148b6188Smillert fputs("Invalid entry\n", stderr); 1357148b6188Smillert else 1358148b6188Smillert break; 1359148b6188Smillert } 1360148b6188Smillert lp->d_secpercyl = ui; 13616fe57b42Smillert 13626fe57b42Smillert /* number of cylinders */ 13636fe57b42Smillert for (;;) { 13646fe57b42Smillert ui = getuint(lp, 0, "number of cylinders", 13656fe57b42Smillert "The total number of cylinders on the disk.", 13664b9a3bdaSmillert lp->d_ncylinders, lp->d_ncylinders, 0, 0); 136796a888c6Smillert if (ui == UINT_MAX - 1) { 136896a888c6Smillert fputs("Command aborted\n", stderr); 136996a888c6Smillert *lp = oldlabel; /* undo damage */ 137096a888c6Smillert return; 137196a888c6Smillert } else if (ui == UINT_MAX) 13726fe57b42Smillert fputs("Invalid entry\n", stderr); 13736fe57b42Smillert else 13746fe57b42Smillert break; 13756fe57b42Smillert } 13766fe57b42Smillert lp->d_ncylinders = ui; 13776fe57b42Smillert 13786fe57b42Smillert /* total sectors */ 13796fe57b42Smillert for (;;) { 13806fe57b42Smillert ui = getuint(lp, 0, "total sectors", 13816fe57b42Smillert "The total number of sectors on the disk.", 13826fe57b42Smillert lp->d_secperunit ? lp->d_secperunit : 13836fe57b42Smillert lp->d_ncylinders * lp->d_ncylinders, 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); 139196a888c6Smillert else if (ui > lp->d_secperunit && 139296a888c6Smillert ending_sector == lp->d_secperunit) { 13936fe57b42Smillert /* grow free count */ 13946fe57b42Smillert *freep += ui - lp->d_secperunit; 1395f98aebd4Smillert puts("You may want to increase the size of the 'c' " 1396f98aebd4Smillert "partition."); 13976fe57b42Smillert break; 139896a888c6Smillert } else if (ui < lp->d_secperunit && 139996a888c6Smillert ending_sector == lp->d_secperunit) { 14006fe57b42Smillert /* shrink free count */ 14016fe57b42Smillert if (lp->d_secperunit - ui > *freep) 14026fe57b42Smillert fprintf(stderr, 14036fe57b42Smillert "Not enough free space to shrink by %u " 14046fe57b42Smillert "sectors (only %u sectors left)\n", 14056fe57b42Smillert lp->d_secperunit - ui, *freep); 14066fe57b42Smillert else { 14076fe57b42Smillert *freep -= lp->d_secperunit - ui; 14086fe57b42Smillert break; 14096fe57b42Smillert } 14106fe57b42Smillert } else 14116fe57b42Smillert break; 14126fe57b42Smillert } 141396a888c6Smillert /* Adjust ending_sector if necesary. */ 141496a888c6Smillert if (ending_sector > ui) 141596a888c6Smillert ending_sector = ui; 14166fe57b42Smillert lp->d_secperunit = ui; 14176fe57b42Smillert 14186fe57b42Smillert /* rpm */ 14196fe57b42Smillert for (;;) { 14206fe57b42Smillert ui = getuint(lp, 0, "rpm", 1421a7e61405Smillert "The rotational speed of the disk in revolutions per minute.", 14224b9a3bdaSmillert lp->d_rpm, lp->d_rpm, 0, 0); 142396a888c6Smillert if (ui == UINT_MAX - 1) { 142496a888c6Smillert fputs("Command aborted\n", stderr); 142596a888c6Smillert *lp = oldlabel; /* undo damage */ 142696a888c6Smillert return; 142796a888c6Smillert } else if (ui == UINT_MAX) 14286fe57b42Smillert fputs("Invalid entry\n", stderr); 14296fe57b42Smillert else 14306fe57b42Smillert break; 14316fe57b42Smillert } 14326fe57b42Smillert lp->d_rpm = ui; 1433440b1d70Smillert 1434440b1d70Smillert /* interleave */ 1435440b1d70Smillert for (;;) { 1436440b1d70Smillert ui = getuint(lp, 0, "interleave", 1437440b1d70Smillert "The physical sector interleave, set when formatting. Almost always 1.", 14384b9a3bdaSmillert lp->d_interleave, lp->d_interleave, 0, 0); 1439440b1d70Smillert if (ui == UINT_MAX - 1) { 1440440b1d70Smillert fputs("Command aborted\n", stderr); 1441440b1d70Smillert *lp = oldlabel; /* undo damage */ 1442440b1d70Smillert return; 1443440b1d70Smillert } else if (ui == UINT_MAX || ui == 0) 1444440b1d70Smillert fputs("Invalid entry\n", stderr); 1445440b1d70Smillert else 1446440b1d70Smillert break; 1447440b1d70Smillert } 1448440b1d70Smillert lp->d_interleave = ui; 14496fe57b42Smillert } 1450a7e61405Smillert 1451a7e61405Smillert struct partition ** 1452a7e61405Smillert sort_partitions(lp, npart) 1453a7e61405Smillert struct disklabel *lp; 1454a7e61405Smillert u_int16_t *npart; 1455a7e61405Smillert { 1456a7e61405Smillert u_int16_t npartitions; 1457a7e61405Smillert struct partition **spp; 1458a7e61405Smillert int i; 1459a7e61405Smillert 1460a7e61405Smillert /* How many "real" partitions do we have? */ 1461a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1462a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1463a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 1464a7e61405Smillert lp->d_partitions[i].p_size != 0) 1465a7e61405Smillert npartitions++; 1466a7e61405Smillert } 146796a888c6Smillert if (npartitions == 0) { 146896a888c6Smillert *npart = 0; 146996a888c6Smillert return(NULL); 147096a888c6Smillert } 1471a7e61405Smillert 1472a7e61405Smillert /* Create an array of pointers to the partition data */ 1473a7e61405Smillert if ((spp = malloc(sizeof(struct partition *) * npartitions)) == NULL) 1474a7e61405Smillert errx(4, "out of memory"); 1475a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1476a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1477a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 1478a7e61405Smillert lp->d_partitions[i].p_size != 0) 1479a7e61405Smillert spp[npartitions++] = &lp->d_partitions[i]; 1480a7e61405Smillert } 1481a7e61405Smillert 1482a7e61405Smillert /* 1483a7e61405Smillert * Sort the partitions based on starting offset. 1484a7e61405Smillert * This is safe because we guarantee no overlap. 1485a7e61405Smillert */ 1486a7e61405Smillert if (npartitions > 1) 1487a7e61405Smillert if (heapsort((void *)spp, npartitions, sizeof(spp[0]), 1488a7e61405Smillert partition_cmp)) 1489a7e61405Smillert err(4, "failed to sort partition table"); 1490a7e61405Smillert 1491a7e61405Smillert *npart = npartitions; 1492a7e61405Smillert return(spp); 1493a7e61405Smillert } 14940f820bbbSmillert 14950f820bbbSmillert /* 14960f820bbbSmillert * Get a valid disk type if necessary. 14970f820bbbSmillert */ 14980f820bbbSmillert void 1499803ff7d5Smillert getdisktype(lp, banner, dev) 15000f820bbbSmillert struct disklabel *lp; 15010f820bbbSmillert char *banner; 1502803ff7d5Smillert char *dev; 15030f820bbbSmillert { 15040f820bbbSmillert int i; 1505803ff7d5Smillert char *s, *def = "SCSI"; 1506803ff7d5Smillert struct dtypes { 1507803ff7d5Smillert char *dev; 1508803ff7d5Smillert char *type; 1509803ff7d5Smillert } dtypes[] = { 1510803ff7d5Smillert "sd", "SCSI", 1511508086e9Smillert "rz", "SCSI", 1512803ff7d5Smillert "wd", "IDE", 1513803ff7d5Smillert "fd", "FLOPPY", 1514803ff7d5Smillert "xd", "SMD", 1515803ff7d5Smillert "xy", "SMD", 1516803ff7d5Smillert "hd", "HP-IB", 1517803ff7d5Smillert "ccd", "CCD", 1518803ff7d5Smillert "vnd", "VND", 1519803ff7d5Smillert "svnd", "VND", 1520803ff7d5Smillert NULL, NULL 1521803ff7d5Smillert }; 1522803ff7d5Smillert 1523803ff7d5Smillert if ((s = basename(dev)) != NULL) { 1524803ff7d5Smillert if (*s == 'r') 1525803ff7d5Smillert s++; 1526803ff7d5Smillert i = strcspn(s, "0123456789"); 1527803ff7d5Smillert s[i] = '\0'; 1528803ff7d5Smillert dev = s; 1529803ff7d5Smillert for (i = 0; dtypes[i].dev != NULL; i++) { 1530803ff7d5Smillert if (strcmp(dev, dtypes[i].dev) == 0) { 1531803ff7d5Smillert def = dtypes[i].type; 1532803ff7d5Smillert break; 1533803ff7d5Smillert } 1534803ff7d5Smillert } 1535803ff7d5Smillert } 15360f820bbbSmillert 15370f820bbbSmillert if (lp->d_type > DKMAXTYPES || lp->d_type == 0) { 15380f820bbbSmillert puts(banner); 15390f820bbbSmillert puts("Possible values are:"); 1540eb5dd924Sderaadt printf("\"IDE\", "); 15410f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15420f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15430f820bbbSmillert if (i < DKMAXTYPES - 1) 15440f820bbbSmillert fputs(", ", stdout); 15450f820bbbSmillert } 15460f820bbbSmillert putchar('\n'); 15470f820bbbSmillert 15480f820bbbSmillert for (;;) { 15490f820bbbSmillert s = getstring(lp, "Disk type", 1550803ff7d5Smillert "What kind of disk is this? Usually SCSI, IDE, " 1551803ff7d5Smillert "ESDI, CCD, ST506, or floppy.", def); 155296a888c6Smillert if (s == NULL) 155396a888c6Smillert continue; 15545b412421Smillert if (strcasecmp(s, "IDE") == 0) { 15555b412421Smillert lp->d_type = DTYPE_ESDI; 15565b412421Smillert return; 15575b412421Smillert } 15580f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) 15590f820bbbSmillert if (strcasecmp(s, dktypenames[i]) == 0) { 15600f820bbbSmillert lp->d_type = i; 15610f820bbbSmillert return; 15620f820bbbSmillert } 15630f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", s); 15640f820bbbSmillert fputs("Valid types are: ", stdout); 15650f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15660f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15670f820bbbSmillert if (i < DKMAXTYPES - 1) 15680f820bbbSmillert fputs(", ", stdout); 15690f820bbbSmillert } 15700f820bbbSmillert putchar('\n'); 15710f820bbbSmillert } 15720f820bbbSmillert } 15730f820bbbSmillert } 157496a888c6Smillert 157596a888c6Smillert /* 157696a888c6Smillert * Get beginning and ending sectors of the OpenBSD portion of the disk 157796a888c6Smillert * from the user. 15784793b14cSmillert * XXX - should mention MBR values if DOSLABEL 157996a888c6Smillert */ 158096a888c6Smillert void 1581e8e8bdb7Sart set_bounds(lp, freep) 158296a888c6Smillert struct disklabel *lp; 1583e8e8bdb7Sart u_int32_t *freep; 158496a888c6Smillert { 158596a888c6Smillert u_int32_t ui, start_temp; 158696a888c6Smillert 158796a888c6Smillert /* Starting sector */ 158896a888c6Smillert do { 158996a888c6Smillert ui = getuint(lp, 0, "Starting sector", 159096a888c6Smillert "The start of the OpenBSD portion of the disk.", 15914b9a3bdaSmillert starting_sector, lp->d_secperunit, 0, 0); 159296a888c6Smillert if (ui == UINT_MAX - 1) { 159396a888c6Smillert fputs("Command aborted\n", stderr); 159496a888c6Smillert return; 159596a888c6Smillert } 159696a888c6Smillert } while (ui >= lp->d_secperunit); 159796a888c6Smillert start_temp = ui; 159896a888c6Smillert 15994793b14cSmillert /* Size */ 160096a888c6Smillert do { 1601f98aebd4Smillert ui = getuint(lp, 0, "Size ('*' for entire disk)", 1602f98aebd4Smillert "The size of the OpenBSD portion of the disk ('*' for the " 1603f98aebd4Smillert "entire disk).", ending_sector - starting_sector, 16044b9a3bdaSmillert lp->d_secperunit - start_temp, 0, 0); 160596a888c6Smillert if (ui == UINT_MAX - 1) { 160696a888c6Smillert fputs("Command aborted\n", stderr); 160796a888c6Smillert return; 160896a888c6Smillert } 1609f98aebd4Smillert } while (ui > lp->d_secperunit - start_temp); 16104793b14cSmillert ending_sector = start_temp + ui; 161196a888c6Smillert starting_sector = start_temp; 1612e8e8bdb7Sart 1613e8e8bdb7Sart /* Recalculate the free sectors */ 1614c0bdc608Smillert editor_countfree(lp, freep); 161596a888c6Smillert } 161696a888c6Smillert 161796a888c6Smillert /* 161896a888c6Smillert * Return a list of the "chunks" of free space available 161996a888c6Smillert */ 162096a888c6Smillert struct diskchunk * 162196a888c6Smillert free_chunks(lp) 162296a888c6Smillert struct disklabel *lp; 162396a888c6Smillert { 162496a888c6Smillert u_int16_t npartitions; 162596a888c6Smillert struct partition **spp; 162696a888c6Smillert static struct diskchunk chunks[MAXPARTITIONS + 2]; 162796a888c6Smillert int i, numchunks; 162896a888c6Smillert 162996a888c6Smillert /* Sort the partitions based on offset */ 163096a888c6Smillert spp = sort_partitions(lp, &npartitions); 163196a888c6Smillert 163296a888c6Smillert /* If there are no partitions, it's all free. */ 163396a888c6Smillert if (spp == NULL) { 163496a888c6Smillert chunks[0].start = 0; 163596a888c6Smillert chunks[0].stop = ending_sector; 163696a888c6Smillert chunks[1].start = chunks[1].stop = 0; 163796a888c6Smillert return(chunks); 163896a888c6Smillert } 163996a888c6Smillert 164096a888c6Smillert /* Find chunks of free space */ 164196a888c6Smillert numchunks = 0; 164296a888c6Smillert if (spp && spp[0]->p_offset > 0) { 164396a888c6Smillert chunks[0].start = 0; 164496a888c6Smillert chunks[0].stop = spp[0]->p_offset; 164596a888c6Smillert numchunks++; 164696a888c6Smillert } 164796a888c6Smillert for (i = 0; i < npartitions; i++) { 164896a888c6Smillert if (i + 1 < npartitions) { 164996a888c6Smillert if (spp[i]->p_offset + spp[i]->p_size < spp[i+1]->p_offset) { 165096a888c6Smillert chunks[numchunks].start = 165196a888c6Smillert spp[i]->p_offset + spp[i]->p_size; 165296a888c6Smillert chunks[numchunks].stop = spp[i+1]->p_offset; 165396a888c6Smillert numchunks++; 165496a888c6Smillert } 165596a888c6Smillert } else { 165696a888c6Smillert /* Last partition */ 165765ce672dScsapuntz if (spp[i]->p_offset + spp[i]->p_size < ending_sector) { 165896a888c6Smillert 165996a888c6Smillert chunks[numchunks].start = 166096a888c6Smillert spp[i]->p_offset + spp[i]->p_size; 166165ce672dScsapuntz chunks[numchunks].stop = ending_sector; 166296a888c6Smillert numchunks++; 166396a888c6Smillert } 166496a888c6Smillert } 166596a888c6Smillert } 166696a888c6Smillert 166796a888c6Smillert /* Terminate and return */ 166896a888c6Smillert chunks[numchunks].start = chunks[numchunks].stop = 0; 166996a888c6Smillert (void)free(spp); 167096a888c6Smillert return(chunks); 167196a888c6Smillert } 16724793b14cSmillert 16734793b14cSmillert /* 16744793b14cSmillert * What is the OpenBSD portion of the disk? Uses the MBR if applicable. 16754793b14cSmillert */ 16764793b14cSmillert void 16774793b14cSmillert find_bounds(lp) 16784793b14cSmillert struct disklabel *lp; 16794793b14cSmillert { 1680f98aebd4Smillert struct partition *pp = &lp->d_partitions[2]; 16814793b14cSmillert 16824793b14cSmillert /* Defaults */ 16834793b14cSmillert /* XXX - reserve a cylinder for hp300? */ 16844793b14cSmillert starting_sector = 0; 16854793b14cSmillert ending_sector = lp->d_secperunit; 16864793b14cSmillert 16874793b14cSmillert #ifdef DOSLABEL 1688*528915f5Smillert /* 1689*528915f5Smillert * If we have an MBR, use values from the {Open,Free,Net}BSD partition. 1690*528915f5Smillert */ 1691aaa7b57dSderaadt if (dosdp && pp->p_size && 1692aaa7b57dSderaadt (dosdp->dp_typ == DOSPTYP_OPENBSD || 1693aaa7b57dSderaadt dosdp->dp_typ == DOSPTYP_FREEBSD || 1694aaa7b57dSderaadt dosdp->dp_typ == DOSPTYP_NETBSD)) { 1695*528915f5Smillert u_int32_t i, new_end; 1696*528915f5Smillert 1697*528915f5Smillert /* Set start and end based on the fdisk partition bounds */ 16984793b14cSmillert starting_sector = get_le(&dosdp->dp_start); 16994793b14cSmillert ending_sector = starting_sector + get_le(&dosdp->dp_size); 1700*528915f5Smillert 1701*528915f5Smillert /* 1702*528915f5Smillert * If there are any BSD or SWAP partitions beyond ending_sector 1703*528915f5Smillert * we extend ending_sector to include them. This is done 1704*528915f5Smillert * because the BIOS geometry is generally different from the 1705*528915f5Smillert * disk geometry. 1706*528915f5Smillert */ 1707*528915f5Smillert for (i = new_end = 0; i < lp->d_npartitions; i++) { 1708*528915f5Smillert pp = &lp->d_partitions[i]; 1709*528915f5Smillert if ((pp->p_fstype == FS_BSDFFS || 1710*528915f5Smillert pp->p_fstype == FS_SWAP) && 1711*528915f5Smillert pp->p_size + pp->p_offset > new_end) 1712*528915f5Smillert new_end = pp->p_size + pp->p_offset; 1713*528915f5Smillert } 1714*528915f5Smillert if (new_end > ending_sector) 1715*528915f5Smillert ending_sector = new_end; 1716*528915f5Smillert 1717508086e9Smillert printf("\nTreating sectors %u-%u as the OpenBSD portion of the " 17184793b14cSmillert "disk.\nYou can use the 'b' command to change this.\n", 17194793b14cSmillert starting_sector, ending_sector); 17204793b14cSmillert } 17214793b14cSmillert #endif 17224793b14cSmillert } 1723c0bdc608Smillert 1724c0bdc608Smillert /* 1725c0bdc608Smillert * Calculate free space. 1726c0bdc608Smillert */ 1727c0bdc608Smillert void 1728c0bdc608Smillert editor_countfree(lp, freep) 1729c0bdc608Smillert struct disklabel *lp; 1730c0bdc608Smillert u_int32_t *freep; 1731c0bdc608Smillert { 1732c0bdc608Smillert struct partition *pp; 1733c0bdc608Smillert int i; 1734c0bdc608Smillert 1735c0bdc608Smillert *freep = ending_sector - starting_sector; 1736c0bdc608Smillert for (i = 0; i < lp->d_npartitions; i++) { 1737c0bdc608Smillert pp = &lp->d_partitions[i]; 1738c0bdc608Smillert if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT && 1739c0bdc608Smillert pp->p_size > 0 && 1740c0bdc608Smillert pp->p_offset + pp->p_size <= ending_sector && 1741c0bdc608Smillert pp->p_offset >= starting_sector) 1742c0bdc608Smillert *freep -= pp->p_size; 1743c0bdc608Smillert } 1744c0bdc608Smillert } 1745617e6e4aSmillert 1746617e6e4aSmillert void 1747617e6e4aSmillert editor_help(arg) 1748617e6e4aSmillert char *arg; 1749617e6e4aSmillert { 1750617e6e4aSmillert 1751617e6e4aSmillert /* XXX - put these strings in a table instead? */ 1752617e6e4aSmillert switch (*arg) { 1753617e6e4aSmillert case 'p': 1754617e6e4aSmillert puts( 1755617e6e4aSmillert "The 'p' command prints the current disk label. By default, it prints the\n" 1756617e6e4aSmillert "size and offset in sectors (a sector is usually 512 bytes). The 'p' command\n" 1757617e6e4aSmillert "takes an optional units argument. Possible values are 'b' for bytes, 'c'\n" 1758617e6e4aSmillert "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n"); 1759617e6e4aSmillert break; 1760617e6e4aSmillert case 'M': 1761617e6e4aSmillert puts( 1762617e6e4aSmillert "The 'M' command pipes the entire OpenBSD manual page for disklabel though\n" 1763508086e9Smillert "the pager specified by the PAGER environment variable or 'less' if PAGER is\n" 1764508086e9Smillert "not set. It is especially useful during install when the normal system\n" 1765508086e9Smillert "manual is not available.\n"); 1766617e6e4aSmillert break; 1767617e6e4aSmillert case 'e': 1768617e6e4aSmillert puts( 1769617e6e4aSmillert "The 'e' command is used to edit the disk drive parameters. These include\n" 1770617e6e4aSmillert "the number of sectors/track, tracks/cylinder, sectors/cylinder, number of\n" 1771617e6e4aSmillert "cylinders on the disk , total sectors on the disk, rpm, interleave, disk\n" 1772617e6e4aSmillert "type, and a descriptive label string. You should not change these unless\n" 1773617e6e4aSmillert "you know what you are doing\n"); 1774617e6e4aSmillert break; 1775617e6e4aSmillert case 'a': 1776617e6e4aSmillert puts( 1777617e6e4aSmillert "The 'a' command adds new partitions to the disk. It takes as an optional\n" 1778617e6e4aSmillert "argument the partition letter to add. If you do not specify a partition\n" 1779617e6e4aSmillert "letter, you will be prompted for it; the next available letter will be the\n" 1780617e6e4aSmillert "default answer\n"); 1781617e6e4aSmillert break; 1782617e6e4aSmillert case 'b': 1783617e6e4aSmillert puts( 1784617e6e4aSmillert "The 'b' command is used to change the boundaries of the OpenBSD portion of\n" 1785617e6e4aSmillert "the disk. This is only useful on disks with an fdisk partition. By default,\n" 1786617e6e4aSmillert "on a disk with an fdisk partition, the boundaries are set to be the first\n" 1787617e6e4aSmillert "and last sectors of the OpenBSD fdisk partition. You should only change\n" 1788617e6e4aSmillert "these if your fdisk partition table is incorrect or you have a disk larger\n" 1789617e6e4aSmillert "than 8gig, since 8gig is the maximum size an fdisk partition can be. You\n" 1790617e6e4aSmillert "may enter '*' at the 'Size' prompt to indicate the entire size of the disk\n" 1791617e6e4aSmillert "(minus the starting sector). Use this option with care; if you extend the\n" 1792617e6e4aSmillert "boundaries such that they overlap with another operating system you will\n" 1793617e6e4aSmillert "corrupt the other operating system's data.\n"); 1794617e6e4aSmillert break; 1795617e6e4aSmillert case 'c': 1796617e6e4aSmillert puts( 1797617e6e4aSmillert "The 'c' command is used to change the size of an existing partition. It\n" 1798617e6e4aSmillert "takes as an optional argument the partition letter to change. If you do not\n" 1799617e6e4aSmillert "specify a partition letter, you will be prompted for one. You may add a '+'\n" 1800617e6e4aSmillert "or '-' prefix to the new size to increase or decrease the existing value\n" 1801617e6e4aSmillert "instead of entering an absolute value. You may also use a suffix to indicate\n" 1802617e6e4aSmillert "the units the values is in terms of. Possible suffixes are 'b' for bytes,\n" 1803617e6e4aSmillert "'c' for cylinders, 'k' for kilobytes, 'm' for megabytes, 'g' for gigabytes or\n" 1804617e6e4aSmillert "no suffix for sectors (usually 512 bytes). You may also enter '*' to change\n" 1805617e6e4aSmillert "the size to be the total number of free sectors remaining.\n"); 1806617e6e4aSmillert break; 1807617e6e4aSmillert case 'd': 1808617e6e4aSmillert puts( 1809617e6e4aSmillert "The 'd' command is used to delete an existing partition. It takes as an\n" 1810617e6e4aSmillert "optional argument the partition letter to change. If you do not specify a\n" 1811617e6e4aSmillert "partition letter, you will be prompted for one. You may not delete the ``c''\n" 1812617e6e4aSmillert "partition as 'c' must always exist and by default is marked as 'unused' (so\n" 1813617e6e4aSmillert "it does not take up any space).\n"); 1814617e6e4aSmillert break; 1815617e6e4aSmillert case 'm': 1816617e6e4aSmillert puts( 1817617e6e4aSmillert "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" 1818617e6e4aSmillert "partition letter, you will be prompted for one. This option allows the user\n" 1819617e6e4aSmillert "to change the filesystem type, starting offset, partition size, block fragment\n" 1820617e6e4aSmillert "size, block size, and cylinders per group for the specified partition (not all\n" 1821617e6e4aSmillert "parameters are configurable for non-BSD partitions).\n"); 1822617e6e4aSmillert break; 1823bd6726faSmillert case 'n': 1824bd6726faSmillert puts( 1825bd6726faSmillert "The 'm' command is used to set the mount point for a partition (ie: name it).\n" 1826bd6726faSmillert "It takes as an optional argument the partition letter to name. If you do\n" 1827bd6726faSmillert "not specify a partition letter, you will be prompted for one. This option\n" 1828bd6726faSmillert "is only valid if disklabel was invoked with the -F flag.\n"); 1829bd6726faSmillert break; 1830617e6e4aSmillert case 'r': 1831617e6e4aSmillert puts( 1832617e6e4aSmillert "The 'r' command is used to recalculate the free space available. This option\n" 1833617e6e4aSmillert "should really not be necessary under normal circumstances but can be useful if\n" 1834617e6e4aSmillert "disklabel gets confused.\n"); 1835617e6e4aSmillert break; 1836617e6e4aSmillert case 'u': 1837617e6e4aSmillert puts( 1838617e6e4aSmillert "The 'u' command will undo (or redo) the last change. Entering 'u' once will\n" 1839617e6e4aSmillert "undo your last change. Entering it again will restore the change.\n"); 1840617e6e4aSmillert break; 1841617e6e4aSmillert case 's': 1842617e6e4aSmillert puts( 1843617e6e4aSmillert "The 's' command is used to save a copy of the label to a file in ascii format\n" 1844617e6e4aSmillert "(suitable for loading via disklabel's [-R] option). It takes as an optional\n" 1845617e6e4aSmillert "argument the filename to save the label to. If you do not specify a filename,\n" 1846617e6e4aSmillert "you will be prompted for one.\n"); 1847617e6e4aSmillert break; 1848617e6e4aSmillert case 'w': 1849617e6e4aSmillert puts( 1850617e6e4aSmillert "The 'w' command will write the current label to disk. This option will\n" 1851617e6e4aSmillert "commit any changes to the on-disk label.\n"); 1852617e6e4aSmillert break; 1853617e6e4aSmillert case 'q': 1854617e6e4aSmillert puts( 1855617e6e4aSmillert "The 'q' command quits the label editor. If any changes have been made you\n" 1856617e6e4aSmillert "will be asked whether or not to save the changes to the on-disk label.\n"); 1857617e6e4aSmillert break; 1858617e6e4aSmillert case 'x': 1859617e6e4aSmillert puts( 1860617e6e4aSmillert "The 'x' command exits the label editor without saving any changes to the\n" 1861617e6e4aSmillert "on-disk label.\n"); 1862617e6e4aSmillert break; 1863617e6e4aSmillert default: 1864617e6e4aSmillert puts("Available commands:"); 1865617e6e4aSmillert puts("\tp [unit] - print label."); 1866617e6e4aSmillert puts("\tM - show entire OpenBSD man page for disklabel."); 1867617e6e4aSmillert puts("\te - edit drive parameters."); 1868617e6e4aSmillert puts("\ta [part] - add new partition."); 1869617e6e4aSmillert puts("\tb - set OpenBSD disk boundaries."); 1870617e6e4aSmillert puts("\tc [part] - change partition size."); 1871617e6e4aSmillert puts("\td [part] - delete partition."); 1872617e6e4aSmillert puts("\tm [part] - modify existing partition."); 1873bd6726faSmillert puts("\tn [part] - set the mount point for a partition."); 1874617e6e4aSmillert puts("\tr - recalculate free space."); 1875617e6e4aSmillert puts("\tu - undo last change."); 1876617e6e4aSmillert puts("\ts [path] - save label to file."); 1877617e6e4aSmillert puts("\tw - write label to disk."); 1878617e6e4aSmillert puts("\tq - quit and save changes."); 1879617e6e4aSmillert puts("\tx - exit without saving changes."); 1880617e6e4aSmillert puts("\t? [cmnd] - this message or command specific help."); 1881617e6e4aSmillert puts( 1882617e6e4aSmillert "Numeric parameters may use suffixes to indicate units:\n\t" 1883617e6e4aSmillert "'b' for bytes, 'c' for cylinders, 'k' for kilobytes, 'm' for megabytes,\n\t" 1884617e6e4aSmillert "'g' for gigabytes or no suffix for sectors (usually 512 bytes).\n\t" 1885617e6e4aSmillert "Non-sector units will be rounded to the nearest cylinder.\n" 1886617e6e4aSmillert "Entering '?' at most prompts will give you (simple) context sensitive help."); 1887617e6e4aSmillert break; 1888617e6e4aSmillert } 1889617e6e4aSmillert } 1890bd6726faSmillert 1891bd6726faSmillert char ** 1892bd6726faSmillert mpcopy(to, from) 1893bd6726faSmillert char **to; 1894bd6726faSmillert char **from; 1895bd6726faSmillert { 1896bd6726faSmillert int i; 1897bd6726faSmillert 1898bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1899bd6726faSmillert if (from[i] != NULL) { 1900bd6726faSmillert to[i] = realloc(to[i], strlen(from[i]) + 1); 1901bd6726faSmillert if (to[i] == NULL) 1902bd6726faSmillert errx(4, "out of memory"); 1903bd6726faSmillert (void)strcpy(to[i], from[i]); 1904bd6726faSmillert } else if (to[i] != NULL) { 1905bd6726faSmillert free(to[i]); 1906bd6726faSmillert to[i] = NULL; 1907bd6726faSmillert } 1908bd6726faSmillert } 1909bd6726faSmillert return(to); 1910bd6726faSmillert } 1911bd6726faSmillert 1912bd6726faSmillert int 1913bd6726faSmillert mpequal(mp1, mp2) 1914bd6726faSmillert char **mp1; 1915bd6726faSmillert char **mp2; 1916bd6726faSmillert { 1917bd6726faSmillert int i; 1918bd6726faSmillert 1919bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1920bd6726faSmillert if (mp1[i] == NULL && mp2[i] == NULL) 1921bd6726faSmillert continue; 1922bd6726faSmillert 1923bd6726faSmillert if ((mp1[i] != NULL && mp2[i] == NULL) || 1924bd6726faSmillert (mp1[i] == NULL && mp2[i] != NULL) || 1925bd6726faSmillert (strcmp(mp1[i], mp2[i]) != 0)) 1926bd6726faSmillert return(0); 1927bd6726faSmillert } 1928bd6726faSmillert return(1); 1929bd6726faSmillert } 1930bd6726faSmillert 1931bd6726faSmillert int 1932bd6726faSmillert mpsave(lp, mp, cdev, fstabfile) 1933bd6726faSmillert struct disklabel *lp; 1934bd6726faSmillert char **mp; 1935bd6726faSmillert char *cdev; 1936bd6726faSmillert char *fstabfile; 1937bd6726faSmillert { 1938bd6726faSmillert int i, mpset; 1939bd6726faSmillert char bdev[MAXPATHLEN], *p; 19403f843443Smillert struct mountinfo mi[MAXPARTITIONS]; 1941bd6726faSmillert FILE *fp; 1942bd6726faSmillert 19433f843443Smillert memset(&mi, 0, sizeof(mi)); 19443f843443Smillert 1945bd6726faSmillert for (i = 0, mpset = 0; i < MAXPARTITIONS; i++) { 1946bd6726faSmillert if (mp[i] != NULL) { 19473f843443Smillert mi[i].mountpoint = mp[i]; 19483f843443Smillert mi[i].partno = i; 1949bd6726faSmillert mpset = 1; 1950bd6726faSmillert } 1951bd6726faSmillert } 19523f843443Smillert /* Exit if there is nothing to do... */ 1953bd6726faSmillert if (!mpset) 19543f843443Smillert return(0); 1955bd6726faSmillert 1956bd6726faSmillert /* Convert cdev to bdev */ 1957bd6726faSmillert if (strncmp(_PATH_DEV, cdev, sizeof(_PATH_DEV) - 1) == 0 && 1958bd6726faSmillert cdev[sizeof(_PATH_DEV) - 1] == 'r') { 1959bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV, 1960bd6726faSmillert &cdev[sizeof(_PATH_DEV)]); 1961bd6726faSmillert } else { 1962bd6726faSmillert if ((p = strrchr(cdev, '/')) == NULL || *(++p) != 'r') 1963bd6726faSmillert return(1); 1964bd6726faSmillert *p = '\0'; 1965bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", cdev, p + 1); 1966bd6726faSmillert *p = 'r'; 1967bd6726faSmillert } 1968bd6726faSmillert bdev[strlen(bdev) - 1] = '\0'; 1969bd6726faSmillert 19703f843443Smillert /* Sort mountpoints so we don't try to mount /usr/local before /usr */ 19713f843443Smillert qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp); 19723f843443Smillert 1973bd6726faSmillert if ((fp = fopen(fstabfile, "w")) == NULL) 1974bd6726faSmillert return(1); 1975bd6726faSmillert 19763f843443Smillert for (i = 0; i < MAXPARTITIONS && mi[i].mountpoint != NULL; i++) { 19773f843443Smillert fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 'a' + mi[i].partno, 19783f843443Smillert mi[i].mountpoint, 1979bd6726faSmillert fstypesnames[lp->d_partitions[i].p_fstype], 1980bd6726faSmillert i == 0 ? 1 : 2); 1981bd6726faSmillert } 1982bd6726faSmillert fclose(fp); 1983bd6726faSmillert printf("Wrote fstab entries to %s\n", fstabfile); 1984bd6726faSmillert return(0); 1985bd6726faSmillert } 198624a2c1a4Smillert 198724a2c1a4Smillert int 198824a2c1a4Smillert get_offset(lp, partno) 198924a2c1a4Smillert struct disklabel *lp; 199024a2c1a4Smillert int partno; 199124a2c1a4Smillert { 199224a2c1a4Smillert u_int32_t ui; 199324a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 199424a2c1a4Smillert 199524a2c1a4Smillert for (;;) { 199624a2c1a4Smillert ui = getuint(lp, partno, "offset", 199724a2c1a4Smillert "Starting sector for this partition.", pp->p_offset, 199824a2c1a4Smillert pp->p_offset, 0, DO_CONVERSIONS | 199924a2c1a4Smillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 200024a2c1a4Smillert if (ui == UINT_MAX - 1) { 200124a2c1a4Smillert fputs("Command aborted\n", stderr); 200224a2c1a4Smillert return(1); 200324a2c1a4Smillert } else if (ui == UINT_MAX) 200424a2c1a4Smillert fputs("Invalid entry\n", stderr); 200524a2c1a4Smillert else if (ui < starting_sector) 200624a2c1a4Smillert fprintf(stderr, "The OpenBSD portion of the disk starts" 200724a2c1a4Smillert " at sector %u, you tried to add a partition at %u." 200824a2c1a4Smillert " You can use the 'b' command to change the size " 200924a2c1a4Smillert "of the OpenBSD portion.\n" , starting_sector, ui); 201024a2c1a4Smillert else if (ui >= ending_sector) 201124a2c1a4Smillert fprintf(stderr, "The OpenBSD portion of the disk ends " 201224a2c1a4Smillert "at sector %u, you tried to add a partition at %u." 201324a2c1a4Smillert " You can use the 'b' command to change the size " 201424a2c1a4Smillert "of the OpenBSD portion.\n", ending_sector, ui); 201524a2c1a4Smillert else 201624a2c1a4Smillert break; 201724a2c1a4Smillert } 201824a2c1a4Smillert pp->p_offset = ui; 201924a2c1a4Smillert return(0); 202024a2c1a4Smillert } 202124a2c1a4Smillert 202224a2c1a4Smillert int 202324a2c1a4Smillert get_size(lp, partno, freep, new) 202424a2c1a4Smillert struct disklabel *lp; 202524a2c1a4Smillert int partno; 202624a2c1a4Smillert u_int32_t *freep; 202724a2c1a4Smillert int new; 202824a2c1a4Smillert { 202924a2c1a4Smillert u_int32_t ui; 203024a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 203124a2c1a4Smillert 203224a2c1a4Smillert for (;;) { 203324a2c1a4Smillert ui = getuint(lp, partno, "size", "Size of the partition.", 203424a2c1a4Smillert pp->p_size, *freep, pp->p_offset, DO_CONVERSIONS | 203524a2c1a4Smillert ((pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_SWAP) ? 203624a2c1a4Smillert DO_ROUNDING : 0)); 203724a2c1a4Smillert if (ui == UINT_MAX - 1) { 203824a2c1a4Smillert fputs("Command aborted\n", stderr); 203924a2c1a4Smillert return(1); 204024a2c1a4Smillert } else if (ui == UINT_MAX) { 204124a2c1a4Smillert fputs("Invalid entry\n", stderr); 204224a2c1a4Smillert continue; 204324a2c1a4Smillert } 204424a2c1a4Smillert if (new) { 204524a2c1a4Smillert if (ui > *freep) 204624a2c1a4Smillert /* XXX - steal space from another partition */ 204724a2c1a4Smillert fprintf(stderr,"Sorry, there are only %u " 204824a2c1a4Smillert "sectors left\n", *freep); 204924a2c1a4Smillert else if (pp->p_offset + ui > ending_sector) 205024a2c1a4Smillert fprintf(stderr, "The OpenBSD portion of the " 205124a2c1a4Smillert "disk ends at sector %u, you tried to add " 205224a2c1a4Smillert "a partition ending at sector %u. You can " 205324a2c1a4Smillert "use the 'b' command to change the size of " 205424a2c1a4Smillert "the OpenBSD portion.\n", 205524a2c1a4Smillert ending_sector, pp->p_offset + ui); 205624a2c1a4Smillert else 205724a2c1a4Smillert break; /* ok */ 205824a2c1a4Smillert } else { 205924a2c1a4Smillert if (ui == pp->p_size) 206024a2c1a4Smillert break; /* no change */ 206124a2c1a4Smillert if (partno == 2 && ui + pp->p_offset > lp->d_secperunit) { 206224a2c1a4Smillert fputs("'c' partition may not be larger than the disk\n", 206324a2c1a4Smillert stderr); 206424a2c1a4Smillert } else if (pp->p_fstype == FS_UNUSED || 206524a2c1a4Smillert pp->p_fstype == FS_BOOT) { 206624a2c1a4Smillert /* don't care what's free */ 206724a2c1a4Smillert pp->p_size = ui; 206824a2c1a4Smillert break; 206924a2c1a4Smillert } else { 207024a2c1a4Smillert if (ui > pp->p_size + *freep) 207124a2c1a4Smillert /* XXX - steal from another partition */ 207224a2c1a4Smillert fprintf(stderr, 207324a2c1a4Smillert "Size may not be larger than %u " 207424a2c1a4Smillert "sectors\n", pp->p_size + *freep); 207524a2c1a4Smillert else { 207624a2c1a4Smillert *freep += pp->p_size - ui; 207724a2c1a4Smillert pp->p_size = ui; 207824a2c1a4Smillert break; /* ok */ 207924a2c1a4Smillert } 208024a2c1a4Smillert } 208124a2c1a4Smillert } 208224a2c1a4Smillert } 208324a2c1a4Smillert pp->p_size = ui; 208424a2c1a4Smillert return(0); 208524a2c1a4Smillert } 208624a2c1a4Smillert 208724a2c1a4Smillert int 208824a2c1a4Smillert get_fsize(lp, partno) 208924a2c1a4Smillert struct disklabel *lp; 209024a2c1a4Smillert int partno; 209124a2c1a4Smillert { 209224a2c1a4Smillert u_int32_t ui; 209324a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 209424a2c1a4Smillert 209524a2c1a4Smillert for (;;) { 209624a2c1a4Smillert ui = getuint(lp, partno, "fragment size", 209724a2c1a4Smillert "Size of fs block fragments. Usually 1024 or 512.", 209824a2c1a4Smillert pp->p_fsize, pp->p_fsize, 0, 0); 209924a2c1a4Smillert if (ui == UINT_MAX - 1) { 210024a2c1a4Smillert fputs("Command aborted\n", stderr); 210124a2c1a4Smillert return(1); 210224a2c1a4Smillert } else if (ui == UINT_MAX) 210324a2c1a4Smillert fputs("Invalid entry\n", stderr); 210424a2c1a4Smillert else 210524a2c1a4Smillert break; 210624a2c1a4Smillert } 210724a2c1a4Smillert if (ui == 0) 210824a2c1a4Smillert puts("Zero fragment size implies zero block size"); 210924a2c1a4Smillert pp->p_fsize = ui; 211024a2c1a4Smillert return(0); 211124a2c1a4Smillert } 211224a2c1a4Smillert 211324a2c1a4Smillert int 211424a2c1a4Smillert get_bsize(lp, partno) 211524a2c1a4Smillert struct disklabel *lp; 211624a2c1a4Smillert int partno; 211724a2c1a4Smillert { 211824a2c1a4Smillert u_int32_t ui; 211924a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 212024a2c1a4Smillert 212124a2c1a4Smillert /* Avoid dividing by zero... */ 212224a2c1a4Smillert if (pp->p_fsize == 0) { 212324a2c1a4Smillert pp->p_frag = 0; 212424a2c1a4Smillert return(1); 212524a2c1a4Smillert } 212624a2c1a4Smillert 212724a2c1a4Smillert for (;;) { 212824a2c1a4Smillert ui = getuint(lp, partno, "block size", 212924a2c1a4Smillert "Size of filesystem blocks. Usually 8192 or 4096.", 213024a2c1a4Smillert pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag, 213124a2c1a4Smillert 0, 0); 213224a2c1a4Smillert 213324a2c1a4Smillert /* sanity checks */ 213424a2c1a4Smillert if (ui == UINT_MAX - 1) { 213524a2c1a4Smillert fputs("Command aborted\n", stderr); 213624a2c1a4Smillert return(1); 213724a2c1a4Smillert } else if (ui == UINT_MAX) 213824a2c1a4Smillert fputs("Invalid entry\n", stderr); 213924a2c1a4Smillert else if (ui < getpagesize()) 214024a2c1a4Smillert fprintf(stderr, 214124a2c1a4Smillert "Error: block size must be at least as big " 214224a2c1a4Smillert "as page size (%d).\n", getpagesize()); 214324a2c1a4Smillert else if (ui % pp->p_fsize != 0) 214424a2c1a4Smillert fputs("Error: block size must be a multiple of the " 214524a2c1a4Smillert "fragment size.\n", stderr); 214624a2c1a4Smillert else if (ui / pp->p_fsize < 1) 214724a2c1a4Smillert fputs("Error: block size must be at least as big as " 214824a2c1a4Smillert "fragment size.\n", stderr); 214924a2c1a4Smillert else 215024a2c1a4Smillert break; 215124a2c1a4Smillert } 215224a2c1a4Smillert pp->p_frag = ui / pp->p_fsize; 215324a2c1a4Smillert return(0); 215424a2c1a4Smillert } 215524a2c1a4Smillert 215624a2c1a4Smillert int 215724a2c1a4Smillert get_cpg(lp, partno) 215824a2c1a4Smillert struct disklabel *lp; 215924a2c1a4Smillert int partno; 216024a2c1a4Smillert { 216124a2c1a4Smillert u_int32_t ui; 216224a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 216324a2c1a4Smillert 216424a2c1a4Smillert for (;;) { 216524a2c1a4Smillert ui = getuint(lp, partno, "cpg", 216624a2c1a4Smillert "Number of filesystem cylinders per group." 216724a2c1a4Smillert " Usually 16 or 8.", 216824a2c1a4Smillert pp->p_cpg ? pp->p_cpg : 16, 16, 0, 0); 216924a2c1a4Smillert if (ui == UINT_MAX - 1) { 217024a2c1a4Smillert fputs("Command aborted\n", stderr); 217124a2c1a4Smillert return(1); 217224a2c1a4Smillert } else if (ui == UINT_MAX) 217324a2c1a4Smillert fputs("Invalid entry\n", stderr); 217424a2c1a4Smillert else 217524a2c1a4Smillert break; 217624a2c1a4Smillert } 217724a2c1a4Smillert pp->p_cpg = ui; 217824a2c1a4Smillert return(0); 217924a2c1a4Smillert } 218024a2c1a4Smillert 218124a2c1a4Smillert int 218224a2c1a4Smillert get_fstype(lp, partno) 218324a2c1a4Smillert struct disklabel *lp; 218424a2c1a4Smillert int partno; 218524a2c1a4Smillert { 218624a2c1a4Smillert char *p; 218724a2c1a4Smillert u_int32_t ui; 218824a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 218924a2c1a4Smillert 219024a2c1a4Smillert if (pp->p_fstype < FSMAXTYPES) { 219124a2c1a4Smillert p = getstring(lp, "FS type", 219224a2c1a4Smillert "Filesystem type (usually 4.2BSD or swap)", 219324a2c1a4Smillert fstypenames[pp->p_fstype]); 219424a2c1a4Smillert if (p == NULL) { 219524a2c1a4Smillert fputs("Command aborted\n", stderr); 219624a2c1a4Smillert return(1); 219724a2c1a4Smillert } 219824a2c1a4Smillert for (ui = 0; ui < FSMAXTYPES; ui++) { 219924a2c1a4Smillert if (!strcasecmp(p, fstypenames[ui])) { 220024a2c1a4Smillert pp->p_fstype = ui; 220124a2c1a4Smillert break; 220224a2c1a4Smillert } 220324a2c1a4Smillert } 220424a2c1a4Smillert if (ui >= FSMAXTYPES) { 220524a2c1a4Smillert printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p); 220624a2c1a4Smillert pp->p_fstype = FS_OTHER; 220724a2c1a4Smillert } 220824a2c1a4Smillert } else { 220924a2c1a4Smillert for (;;) { 221024a2c1a4Smillert ui = getuint(lp, partno, "FS type (decimal)", 221124a2c1a4Smillert "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", 221224a2c1a4Smillert pp->p_fstype, pp->p_fstype, 0, 0); 221324a2c1a4Smillert if (ui == UINT_MAX - 1) { 221424a2c1a4Smillert fputs("Command aborted\n", stderr); 221524a2c1a4Smillert return(1); 221624a2c1a4Smillert } if (ui == UINT_MAX) 221724a2c1a4Smillert fputs("Invalid entry\n", stderr); 221824a2c1a4Smillert else 221924a2c1a4Smillert break; 222024a2c1a4Smillert } 222124a2c1a4Smillert pp->p_fstype = ui; 222224a2c1a4Smillert } 222324a2c1a4Smillert return(0); 222424a2c1a4Smillert } 222524a2c1a4Smillert 222624a2c1a4Smillert int 222724a2c1a4Smillert get_mp(lp, mp, partno) 222824a2c1a4Smillert struct disklabel *lp; 222924a2c1a4Smillert char **mp; 223024a2c1a4Smillert int partno; 223124a2c1a4Smillert { 223224a2c1a4Smillert char *p; 223324a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 223424a2c1a4Smillert 223524a2c1a4Smillert if (mp != NULL && pp->p_fstype != FS_UNUSED && 223624a2c1a4Smillert pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT && 223724a2c1a4Smillert pp->p_fstype != FS_OTHER) { 2238ddaff619Smillert for (;;) { 223924a2c1a4Smillert p = getstring(lp, "mount point", 224024a2c1a4Smillert "Where to mount this filesystem (ie: / /var /usr)", 224124a2c1a4Smillert mp[partno] ? mp[partno] : "none"); 224224a2c1a4Smillert if (p == NULL) { 224324a2c1a4Smillert fputs("Command aborted\n", stderr); 224424a2c1a4Smillert return(1); 224524a2c1a4Smillert } 2246ddaff619Smillert if (strcasecmp(p, "none") == 0) { 224724a2c1a4Smillert if (mp[partno] != NULL) { 224824a2c1a4Smillert free(mp[partno]); 224924a2c1a4Smillert mp[partno] = NULL; 225024a2c1a4Smillert } 2251ddaff619Smillert break; 2252ddaff619Smillert } 2253ddaff619Smillert if (*p == '/') { 2254ddaff619Smillert /* XXX - might as well realloc */ 2255ddaff619Smillert if (mp[partno] != NULL) 2256ddaff619Smillert free(mp[partno]); 225724a2c1a4Smillert if ((mp[partno] = strdup(p)) == NULL) 225824a2c1a4Smillert errx(4, "out of memory"); 2259ddaff619Smillert break; 2260ddaff619Smillert } 2261ddaff619Smillert fputs("Mount points must start with '/'\n", stderr); 226224a2c1a4Smillert } 226324a2c1a4Smillert } 226424a2c1a4Smillert return(0); 226524a2c1a4Smillert } 22663f843443Smillert 22673f843443Smillert int 22683f843443Smillert micmp(a1, a2) 22693f843443Smillert const void *a1; 22703f843443Smillert const void *a2; 22713f843443Smillert { 22723f843443Smillert struct mountinfo *mi1 = (struct mountinfo *)a1; 22733f843443Smillert struct mountinfo *mi2 = (struct mountinfo *)a2; 22743f843443Smillert 22753f843443Smillert /* We want all the NULLs at the end... */ 22763f843443Smillert if (mi1->mountpoint == NULL && mi2->mountpoint == NULL) 22773f843443Smillert return(0); 22783f843443Smillert else if (mi1->mountpoint == NULL) 22793f843443Smillert return(1); 22803f843443Smillert else if (mi2->mountpoint == NULL) 22813f843443Smillert return(-1); 22823f843443Smillert else 22833f843443Smillert return(strcmp(mi1->mountpoint, mi2->mountpoint)); 22843f843443Smillert } 2285