1*ab30cb2fSdoug /* $OpenBSD: editor.c,v 1.288 2014/10/11 03:08:26 doug Exp $ */ 26fe57b42Smillert 36fe57b42Smillert /* 42d8451b0Smillert * Copyright (c) 1997-2000 Todd C. Miller <Todd.Miller@courtesan.com> 56fe57b42Smillert * 606f01696Smillert * Permission to use, copy, modify, and distribute this software for any 706f01696Smillert * purpose with or without fee is hereby granted, provided that the above 806f01696Smillert * copyright notice and this permission notice appear in all copies. 96fe57b42Smillert * 10328f1f07Smillert * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11328f1f07Smillert * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12328f1f07Smillert * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13328f1f07Smillert * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14328f1f07Smillert * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15328f1f07Smillert * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16328f1f07Smillert * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 176fe57b42Smillert */ 186fe57b42Smillert 196fe57b42Smillert #include <sys/types.h> 206fe57b42Smillert #include <sys/param.h> 21c33fcabaSmillert #include <sys/stat.h> 22c33fcabaSmillert #include <sys/ioctl.h> 2391f4f7d8Sdlg #include <sys/dkio.h> 248dde8bb6Sotto #include <sys/sysctl.h> 256fe57b42Smillert #define DKTYPENAMES 266fe57b42Smillert #include <sys/disklabel.h> 276fe57b42Smillert 286fe57b42Smillert #include <ufs/ffs/fs.h> 296fe57b42Smillert 306fe57b42Smillert #include <ctype.h> 316fe57b42Smillert #include <err.h> 326fe57b42Smillert #include <errno.h> 336fe57b42Smillert #include <string.h> 34803ff7d5Smillert #include <libgen.h> 356fe57b42Smillert #include <stdio.h> 366fe57b42Smillert #include <stdlib.h> 376fe57b42Smillert #include <unistd.h> 386fe57b42Smillert 39f21a098bSotto #include "extern.h" 404793b14cSmillert #include "pathnames.h" 414793b14cSmillert 42117239d3Skrw /* flags for getuint64() */ 436fe57b42Smillert #define DO_CONVERSIONS 0x00000001 446fe57b42Smillert #define DO_ROUNDING 0x00000002 456fe57b42Smillert 46f98aebd4Smillert #ifndef NUMBOOT 47f98aebd4Smillert #define NUMBOOT 0 48f98aebd4Smillert #endif 49f98aebd4Smillert 5096a888c6Smillert /* structure to describe a portion of a disk */ 5196a888c6Smillert struct diskchunk { 521e0ad43cSotto u_int64_t start; 531e0ad43cSotto u_int64_t stop; 5496a888c6Smillert }; 5596a888c6Smillert 563f843443Smillert /* used when sorting mountpoints in mpsave() */ 573f843443Smillert struct mountinfo { 583f843443Smillert char *mountpoint; 593f843443Smillert int partno; 603f843443Smillert }; 613f843443Smillert 62557f712bSkrw /* used when allocating all space according to recommendations */ 63557f712bSkrw 64557f712bSkrw struct space_allocation { 65eafadddfSkrw u_int64_t minsz; /* starts as blocks, xlated to sectors. */ 66eafadddfSkrw u_int64_t maxsz; /* starts as blocks, xlated to sectors. */ 67557f712bSkrw int rate; /* % of extra space to use */ 68557f712bSkrw char *mp; 69557f712bSkrw }; 70557f712bSkrw 718dde8bb6Sotto /* entries for swap and var are changed by editor_allocspace() */ 728dde8bb6Sotto const struct space_allocation alloc_big[] = { 7392adb55fSderaadt { MEG(80), GIG(1), 5, "/" }, 74559340afSotto { MEG(80), MEG(256), 10, "swap" }, 754ab111d2Sderaadt { MEG(120), GIG(4), 8, "/tmp" }, 7692adb55fSderaadt { MEG(80), GIG(4), 13, "/var" }, 7721a0d117Sderaadt { MEG(900), GIG(2), 5, "/usr" }, 7892adb55fSderaadt { MEG(512), GIG(1), 3, "/usr/X11R6" }, 796e1f4775Sotto { GIG(2), GIG(10), 10, "/usr/local" }, 802cb42124Sotto { GIG(1), GIG(2), 2, "/usr/src" }, 81001bee15Sotto #ifdef STATICLINKING 82001bee15Sotto { MEG(2600), GIG(3), 4, "/usr/obj" }, 83001bee15Sotto #else 842cb42124Sotto { MEG(1300), GIG(2), 4, "/usr/obj" }, 85001bee15Sotto #endif 86559340afSotto { GIG(1), GIG(300), 40, "/home" } 874ab111d2Sderaadt /* Anything beyond this leave for the user to decide */ 888dde8bb6Sotto }; 898dde8bb6Sotto 908dde8bb6Sotto const struct space_allocation alloc_medium[] = { 91905e8239Sderaadt { MEG(800), GIG(2), 5, "/" }, 928dde8bb6Sotto { MEG(80), MEG(256), 10, "swap" }, 93905e8239Sderaadt { MEG(900), GIG(3), 78, "/usr" }, 94905e8239Sderaadt { MEG(256), GIG(2), 7, "/home" } 958dde8bb6Sotto }; 968dde8bb6Sotto 978dde8bb6Sotto const struct space_allocation alloc_small[] = { 9892adb55fSderaadt { MEG(700), GIG(4), 95, "/" }, 998dde8bb6Sotto { MEG(1), MEG(256), 5, "swap" } 1008dde8bb6Sotto }; 1018dde8bb6Sotto 1028dde8bb6Sotto const struct space_allocation alloc_stupid[] = { 1038dde8bb6Sotto { MEG(1), MEG(2048), 100, "/" } 1048dde8bb6Sotto }; 1058dde8bb6Sotto 106b2813ff1Sderaadt #ifndef nitems 107b2813ff1Sderaadt #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 108b2813ff1Sderaadt #endif 109b2813ff1Sderaadt 1108a862940Sderaadt const struct { 1118a862940Sderaadt const struct space_allocation *table; 1128a862940Sderaadt int sz; 1138a862940Sderaadt } alloc_table[] = { 1148dde8bb6Sotto { alloc_big, nitems(alloc_big) }, 1158dde8bb6Sotto { alloc_medium, nitems(alloc_medium) }, 1168dde8bb6Sotto { alloc_small, nitems(alloc_small) }, 1178dde8bb6Sotto { alloc_stupid, nitems(alloc_stupid) } 118557f712bSkrw }; 119557f712bSkrw 1209fdcb4d6Skrw void edit_parms(struct disklabel *); 1216aaa4aabSotto void editor_resize(struct disklabel *, char *); 12234ae4198Skrw void editor_add(struct disklabel *, char *); 1239fdcb4d6Skrw void editor_change(struct disklabel *, char *); 1249fdcb4d6Skrw u_int64_t editor_countfree(struct disklabel *); 12534ae4198Skrw void editor_delete(struct disklabel *, char *); 1264d812bb6Slum void editor_help(void); 12734ae4198Skrw void editor_modify(struct disklabel *, char *); 12834ae4198Skrw void editor_name(struct disklabel *, char *); 129c72b5b24Smillert char *getstring(char *, char *, char *); 130117239d3Skrw u_int64_t getuint64(struct disklabel *, char *, char *, u_int64_t, u_int64_t, 131430e1380Skrw u_int64_t, int); 1321f0f871dSkrw int has_overlap(struct disklabel *); 133c72b5b24Smillert int partition_cmp(const void *, const void *); 1340fbd3c97Skrw struct partition **sort_partitions(struct disklabel *); 135c72b5b24Smillert void getdisktype(struct disklabel *, char *, char *); 13687023ed9Skrw void find_bounds(struct disklabel *); 1379fdcb4d6Skrw void set_bounds(struct disklabel *); 13869a6ffbcSjsing void set_duid(struct disklabel *); 139c72b5b24Smillert struct diskchunk *free_chunks(struct disklabel *); 140c72b5b24Smillert int micmp(const void *, const void *); 141c72b5b24Smillert int mpequal(char **, char **); 142c72b5b24Smillert int get_bsize(struct disklabel *, int); 143c72b5b24Smillert int get_fsize(struct disklabel *, int); 144c72b5b24Smillert int get_fstype(struct disklabel *, int); 14534ae4198Skrw int get_mp(struct disklabel *, int); 146604d3bdeSkrw int get_offset(struct disklabel *, int); 1479fdcb4d6Skrw int get_size(struct disklabel *, int); 14887023ed9Skrw void get_geometry(int, struct disklabel **); 14987023ed9Skrw void set_geometry(struct disklabel *, struct disklabel *, struct disklabel *, 15087023ed9Skrw char *); 1519fdcb4d6Skrw void zero_partitions(struct disklabel *); 15214192793Skrw u_int64_t max_partition_size(struct disklabel *, int); 15334ae4198Skrw void display_edit(struct disklabel *, char, u_int64_t); 154e07939ebSderaadt int64_t getphysmem(void); 155e07939ebSderaadt void psize(u_int64_t sz, char unit, struct disklabel *lp); 15696a888c6Smillert 1571e0ad43cSotto static u_int64_t starting_sector; 1581e0ad43cSotto static u_int64_t ending_sector; 1592d8451b0Smillert static int expert; 160fc6e9c48Sotto static int overlap; 1616fe57b42Smillert 1626fe57b42Smillert /* 1634d4a335eSkrw * Simple partition editor. 1646fe57b42Smillert */ 1656fe57b42Smillert int 166d6d80bb0Skrw editor(int f) 1676fe57b42Smillert { 168d6d80bb0Skrw struct disklabel origlabel, lastlabel, tmplabel, newlab = lab; 1697e28fb0fSderaadt struct disklabel *disk_geop = NULL; 17096a888c6Smillert struct partition *pp; 1716fe57b42Smillert FILE *fp; 1726fe57b42Smillert char buf[BUFSIZ], *cmd, *arg; 17334ae4198Skrw char **omountpoints = NULL; 1744f3bbbf0Skrw char **origmountpoints = NULL, **tmpmountpoints = NULL; 1757e28fb0fSderaadt int i, error = 0; 176bd6726faSmillert 177bd6726faSmillert /* Alloc and init mount point info */ 17834ae4198Skrw if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 1794f3bbbf0Skrw !(origmountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 180bd6726faSmillert !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *)))) 181bd6726faSmillert errx(4, "out of memory"); 1826fe57b42Smillert 18396a888c6Smillert /* Don't allow disk type of "unknown" */ 184430e1380Skrw getdisktype(&newlab, "You need to specify a type for this disk.", 185430e1380Skrw specname); 1866fe57b42Smillert 18787023ed9Skrw /* Get the on-disk geometries if possible */ 18887023ed9Skrw get_geometry(f, &disk_geop); 189c33fcabaSmillert 190d09f3941Smillert /* How big is the OpenBSD portion of the disk? */ 191d6d80bb0Skrw find_bounds(&newlab); 192d09f3941Smillert 19396a888c6Smillert /* Make sure there is no partition overlap. */ 194d6d80bb0Skrw if (has_overlap(&newlab)) 1956fe57b42Smillert errx(1, "can't run when there is partition overlap."); 1966fe57b42Smillert 19796a888c6Smillert /* If we don't have a 'c' partition, create one. */ 198d6d80bb0Skrw pp = &newlab.d_partitions[RAW_PART]; 199d6d80bb0Skrw if (newlab.d_npartitions < 3 || DL_GETPSIZE(pp) == 0) { 20096a888c6Smillert puts("No 'c' partition found, adding one that spans the disk."); 201d6d80bb0Skrw if (newlab.d_npartitions < 3) 202d6d80bb0Skrw newlab.d_npartitions = 3; 20334af67a3Sotto DL_SETPOFFSET(pp, 0); 204d6d80bb0Skrw DL_SETPSIZE(pp, DL_GETDSIZE(&newlab)); 20596a888c6Smillert pp->p_fstype = FS_UNUSED; 206ddfcbf38Sotto pp->p_fragblock = pp->p_cpg = 0; 20796a888c6Smillert } 2080f820bbbSmillert 209fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 210479754bbSbluhm if ((newlab.d_flags & D_VENDOR) && !aflag) { 211fc1a4cc6Sderaadt puts("This platform requires that partition offsets/sizes " 212fc1a4cc6Sderaadt "be on cylinder boundaries.\n" 213fc1a4cc6Sderaadt "Partition offsets/sizes will be rounded to the " 214fc1a4cc6Sderaadt "nearest cylinder automatically."); 215fc1a4cc6Sderaadt } 2166fe57b42Smillert #endif 2176fe57b42Smillert 218bd6726faSmillert /* Set d_bbsize and d_sbsize as necessary */ 219d6d80bb0Skrw if (newlab.d_bbsize == 0) 220d6d80bb0Skrw newlab.d_bbsize = BBSIZE; 221d6d80bb0Skrw if (newlab.d_sbsize == 0) 222d6d80bb0Skrw newlab.d_sbsize = SBSIZE; 223f98aebd4Smillert 22493160b9bSkrw /* Save the (U|u)ndo labels and mountpoints. */ 22593160b9bSkrw mpcopy(origmountpoints, mountpoints); 226d6d80bb0Skrw origlabel = newlab; 227d6d80bb0Skrw lastlabel = newlab; 22834ae4198Skrw 22934ae4198Skrw puts("Label editor (enter '?' for help at any prompt)"); 2306fe57b42Smillert for (;;) { 2316fe57b42Smillert fputs("> ", stdout); 2326e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 2336e0becc5Smillert putchar('\n'); 2346e0becc5Smillert buf[0] = 'q'; 2356e0becc5Smillert buf[1] = '\0'; 2366e0becc5Smillert } 237260513deSmillert if ((cmd = strtok(buf, " \t\r\n")) == NULL) 238260513deSmillert continue; 239260513deSmillert arg = strtok(NULL, " \t\r\n"); 2406fe57b42Smillert 2414f3bbbf0Skrw if ((*cmd != 'u') && (*cmd != 'U')) { 2424f3bbbf0Skrw /* 2434f3bbbf0Skrw * Save undo info in case the command tries to make 2444f3bbbf0Skrw * changes but decides not to. 2454f3bbbf0Skrw */ 2464f3bbbf0Skrw tmplabel = lastlabel; 247d6d80bb0Skrw lastlabel = newlab; 2484f3bbbf0Skrw mpcopy(tmpmountpoints, omountpoints); 2494f3bbbf0Skrw mpcopy(omountpoints, mountpoints); 2504f3bbbf0Skrw } 2516fe57b42Smillert 2524f3bbbf0Skrw switch (*cmd) { 2536fe57b42Smillert case '?': 254ea37abd3Sderaadt case 'h': 2554d812bb6Slum editor_help(); 2566fe57b42Smillert break; 2576fe57b42Smillert 258557f712bSkrw case 'A': 259d6d80bb0Skrw if (ioctl(f, DIOCGPDINFO, &newlab) == 0) { 260ef5288d7Skrw ++aflag; 261d6d80bb0Skrw editor_allocspace(&newlab); 262ef5288d7Skrw --aflag; 263ab20a3eaSkrw } else 264d6d80bb0Skrw newlab = lastlabel; 265557f712bSkrw break; 2666fe57b42Smillert case 'a': 267d6d80bb0Skrw editor_add(&newlab, arg); 26896a888c6Smillert break; 26996a888c6Smillert 27096a888c6Smillert case 'b': 271d6d80bb0Skrw set_bounds(&newlab); 2726fe57b42Smillert break; 2736fe57b42Smillert 2746fe57b42Smillert case 'c': 275d6d80bb0Skrw editor_change(&newlab, arg); 2766fe57b42Smillert break; 2776fe57b42Smillert 2789afbe9eeSmillert case 'D': 279d6d80bb0Skrw if (ioctl(f, DIOCGPDINFO, &newlab) == 0) { 28071bba4ecSkrw dflag = 1; 28193160b9bSkrw for (i=0; i<MAXPARTITIONS; i++) { 28293160b9bSkrw free(mountpoints[i]); 28393160b9bSkrw mountpoints[i] = NULL; 28493160b9bSkrw } 28593160b9bSkrw } else 286cdd7eb76Smillert warn("unable to get default partition table"); 2879afbe9eeSmillert break; 2889afbe9eeSmillert 2896fe57b42Smillert case 'd': 290d6d80bb0Skrw editor_delete(&newlab, arg); 2916fe57b42Smillert break; 2926fe57b42Smillert 2939afbe9eeSmillert case 'e': 294d6d80bb0Skrw edit_parms(&newlab); 2959afbe9eeSmillert break; 2969afbe9eeSmillert 297c33fcabaSmillert case 'g': 298d6d80bb0Skrw set_geometry(&newlab, disk_geop, &lab, arg); 299c33fcabaSmillert break; 300c33fcabaSmillert 3010d63cfbaSjsing case 'i': 302d6d80bb0Skrw set_duid(&newlab); 3030d63cfbaSjsing break; 3040d63cfbaSjsing 3056fe57b42Smillert case 'm': 306d6d80bb0Skrw editor_modify(&newlab, arg); 307bd6726faSmillert break; 308bd6726faSmillert 309bd6726faSmillert case 'n': 3105c79e1cfSkrw if (!fstabfile) { 311bd6726faSmillert fputs("This option is not valid when run " 31284d0bb16Sderaadt "without the -f flag.\n", stderr); 313bd6726faSmillert break; 314bd6726faSmillert } 315d6d80bb0Skrw editor_name(&newlab, arg); 3166fe57b42Smillert break; 3176fe57b42Smillert 3186fe57b42Smillert case 'p': 319d6d80bb0Skrw display_edit(&newlab, arg ? *arg : 0, 320d6d80bb0Skrw editor_countfree(&newlab)); 3216fe57b42Smillert break; 3226fe57b42Smillert 323aff3f969Sotto case 'l': 324d6d80bb0Skrw display(stdout, &newlab, arg ? *arg : 0, 0); 325aff3f969Sotto break; 326aff3f969Sotto 327508086e9Smillert case 'M': { 328508086e9Smillert sig_t opipe = signal(SIGPIPE, SIG_IGN); 32945decb36Sderaadt char *pager, *comm = NULL; 330e7936562Sderaadt extern const u_char manpage[]; 33108f8e31fSotto extern const int manpage_sz; 3325d12b01bSderaadt 333489bd112Spjanzen if ((pager = getenv("PAGER")) == NULL || *pager == '\0') 334508086e9Smillert pager = _PATH_LESS; 33508f8e31fSotto 33645decb36Sderaadt if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 && 33745decb36Sderaadt (fp = popen(comm, "w")) != NULL) { 33808f8e31fSotto (void) fwrite(manpage, manpage_sz, 1, fp); 3395d12b01bSderaadt pclose(fp); 340508086e9Smillert } else 341508086e9Smillert warn("unable to execute %s", pager); 342508086e9Smillert 34345decb36Sderaadt free(comm); 344508086e9Smillert (void)signal(SIGPIPE, opipe); 3455d12b01bSderaadt break; 346508086e9Smillert } 3475d12b01bSderaadt 3486fe57b42Smillert case 'q': 34969220492Smillert if (donothing) { 35069220492Smillert puts("In no change mode, not writing label."); 3517e28fb0fSderaadt goto done; 35269220492Smillert } 35393160b9bSkrw 35471bba4ecSkrw /* 35593160b9bSkrw * If we haven't changed the original label, and it 35693160b9bSkrw * wasn't a default label or an auto-allocated label, 35793160b9bSkrw * there is no need to do anything before exiting. Note 35893160b9bSkrw * that 'w' will reset dflag and aflag to allow 'q' to 35993160b9bSkrw * exit without further questions. 36071bba4ecSkrw */ 361ab20a3eaSkrw if (!dflag && !aflag && 362d6d80bb0Skrw memcmp(&lab, &newlab, sizeof(newlab)) == 0) { 363bd6726faSmillert puts("No label changes."); 364d6d80bb0Skrw /* Save mountpoint info. */ 365d6d80bb0Skrw mpsave(&newlab); 3667e28fb0fSderaadt goto done; 3676fe57b42Smillert } 3686fe57b42Smillert do { 369d0e67762Smillert arg = getstring("Write new label?", 370d0e67762Smillert "Write the modified label to disk?", 371d0e67762Smillert "y"); 372025f5691Sderaadt } while (arg && tolower((unsigned char)*arg) != 'y' && 373025f5691Sderaadt tolower((unsigned char)*arg) != 'n'); 374025f5691Sderaadt if (arg && tolower((unsigned char)*arg) == 'y') { 375d6d80bb0Skrw if (writelabel(f, bootarea, &newlab) == 0) { 376d6d80bb0Skrw newlab = lab; /* lab now has UID info */ 3777e28fb0fSderaadt goto done; 3786fe57b42Smillert } 379d0e67762Smillert warnx("unable to write label"); 380d0e67762Smillert } 3817e28fb0fSderaadt error = 1; 3827e28fb0fSderaadt goto done; 3836fe57b42Smillert /* NOTREACHED */ 3846fe57b42Smillert break; 3856fe57b42Smillert 3866aaa4aabSotto case 'R': 387fc6e9c48Sotto if (aflag && !overlap) 388d6d80bb0Skrw editor_resize(&newlab, arg); 3896aaa4aabSotto else 3906aaa4aabSotto fputs("Resize only implemented for auto " 391fc6e9c48Sotto "allocated labels\n", stderr); 3926aaa4aabSotto break; 3936aaa4aabSotto 39425f9c360Skrw case 'r': { 39525f9c360Skrw struct diskchunk *chunks; 39625f9c360Skrw int i; 3979fdcb4d6Skrw /* Display free space. */ 398d6d80bb0Skrw chunks = free_chunks(&newlab); 39925f9c360Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; 40025f9c360Skrw i++) 40125f9c360Skrw fprintf(stderr, "Free sectors: %16llu - %16llu " 40225f9c360Skrw "(%16llu)\n", 40325f9c360Skrw chunks[i].start, chunks[i].stop - 1, 40425f9c360Skrw chunks[i].stop - chunks[i].start); 40525f9c360Skrw fprintf(stderr, "Total free sectors: %llu.\n", 406d6d80bb0Skrw editor_countfree(&newlab)); 407c0bdc608Smillert break; 40825f9c360Skrw } 409c0bdc608Smillert 4106fe57b42Smillert case 's': 4116fe57b42Smillert if (arg == NULL) { 412c33fcabaSmillert arg = getstring("Filename", 4136fe57b42Smillert "Name of the file to save label into.", 4146fe57b42Smillert NULL); 415e97229a3Scnst if (arg == NULL || *arg == '\0') 4166fe57b42Smillert break; 4176fe57b42Smillert } 4186fe57b42Smillert if ((fp = fopen(arg, "w")) == NULL) { 4196fe57b42Smillert warn("cannot open %s", arg); 4206fe57b42Smillert } else { 421d6d80bb0Skrw display(fp, &newlab, 0, 1); 4226fe57b42Smillert (void)fclose(fp); 4236fe57b42Smillert } 4246fe57b42Smillert break; 4256fe57b42Smillert 4264f3bbbf0Skrw case 'U': 42793160b9bSkrw /* 428430e1380Skrw * If we allow 'U' repeatedly, information would be 429430e1380Skrw * lost. This way multiple 'U's followed by 'u' will 430430e1380Skrw * undo the 'U's. 43193160b9bSkrw */ 432d6d80bb0Skrw if (memcmp(&newlab, &origlabel, sizeof(newlab)) || 43393160b9bSkrw !mpequal(mountpoints, origmountpoints)) { 434d6d80bb0Skrw tmplabel = newlab; 435d6d80bb0Skrw newlab = origlabel; 4364f3bbbf0Skrw lastlabel = tmplabel; 4374f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 4384f3bbbf0Skrw mpcopy(mountpoints, origmountpoints); 4394f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4404f3bbbf0Skrw } 44193160b9bSkrw puts("Original label and mount points restored."); 4424f3bbbf0Skrw break; 4434f3bbbf0Skrw 4446fe57b42Smillert case 'u': 445d6d80bb0Skrw tmplabel = newlab; 446d6d80bb0Skrw newlab = lastlabel; 4476fe57b42Smillert lastlabel = tmplabel; 4484f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 449bd6726faSmillert mpcopy(mountpoints, omountpoints); 4504f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4516fe57b42Smillert puts("Last change undone."); 4526fe57b42Smillert break; 4536fe57b42Smillert 454040947cfSmillert case 'w': 455bd6726faSmillert if (donothing) { 456040947cfSmillert puts("In no change mode, not writing label."); 457bd6726faSmillert break; 458bd6726faSmillert } 45993160b9bSkrw 46041f684b9Skrw /* Write label to disk. */ 461d6d80bb0Skrw if (writelabel(f, bootarea, &newlab) != 0) 462040947cfSmillert warnx("unable to write label"); 46371bba4ecSkrw else { 464ab20a3eaSkrw dflag = aflag = 0; 465d6d80bb0Skrw newlab = lab; /* lab now has UID info */ 46671bba4ecSkrw } 467040947cfSmillert break; 468040947cfSmillert 4692d8451b0Smillert case 'X': 4702d8451b0Smillert expert = !expert; 4712d8451b0Smillert printf("%s expert mode\n", expert ? "Entering" : 4722d8451b0Smillert "Exiting"); 4732d8451b0Smillert break; 4742d8451b0Smillert 4756fe57b42Smillert case 'x': 4767e28fb0fSderaadt goto done; 4776fe57b42Smillert break; 4786fe57b42Smillert 4799afbe9eeSmillert case 'z': 480d6d80bb0Skrw zero_partitions(&newlab); 4816fe57b42Smillert break; 4826fe57b42Smillert 4839afbe9eeSmillert case '\n': 4846fe57b42Smillert break; 4856fe57b42Smillert 4866fe57b42Smillert default: 4876fe57b42Smillert printf("Unknown option: %c ('?' for help)\n", *cmd); 4886fe57b42Smillert break; 4896fe57b42Smillert } 4904f3bbbf0Skrw 4914f3bbbf0Skrw /* 4924f3bbbf0Skrw * If no changes were made to label or mountpoints, then 4934f3bbbf0Skrw * restore undo info. 4944f3bbbf0Skrw */ 495d6d80bb0Skrw if (memcmp(&newlab, &lastlabel, sizeof(newlab)) == 0 && 49693160b9bSkrw (mpequal(mountpoints, omountpoints))) { 4974f3bbbf0Skrw lastlabel = tmplabel; 4984f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4994f3bbbf0Skrw } 5006fe57b42Smillert } 5017e28fb0fSderaadt done: 502408ab9bcSkrw mpfree(omountpoints); 503408ab9bcSkrw mpfree(origmountpoints); 504408ab9bcSkrw mpfree(tmpmountpoints); 5057e28fb0fSderaadt if (disk_geop) 5067e28fb0fSderaadt free(disk_geop); 5077e28fb0fSderaadt return(error); 5086fe57b42Smillert } 5096fe57b42Smillert 5108dde8bb6Sotto int64_t 5118dde8bb6Sotto getphysmem(void) 5128dde8bb6Sotto { 5138dde8bb6Sotto int64_t physmem; 5148dde8bb6Sotto size_t sz = sizeof(physmem); 5158dde8bb6Sotto int mib[] = { CTL_HW, HW_PHYSMEM64 }; 516e07939ebSderaadt 5178dde8bb6Sotto if (sysctl(mib, 2, &physmem, &sz, NULL, (size_t)0) == -1) 5188dde8bb6Sotto errx(4, "can't get mem size"); 5198dde8bb6Sotto return physmem; 5208dde8bb6Sotto } 5218dde8bb6Sotto 5226fe57b42Smillert /* 523557f712bSkrw * Allocate all disk space according to standard recommendations for a 524557f712bSkrw * root disk. 525557f712bSkrw */ 526557f712bSkrw void 5278dde8bb6Sotto editor_allocspace(struct disklabel *lp_org) 528557f712bSkrw { 5298dde8bb6Sotto struct disklabel *lp, label; 5308dde8bb6Sotto struct space_allocation *alloc; 53134ae4198Skrw struct space_allocation *ap; 532557f712bSkrw struct partition *pp; 53334ae4198Skrw struct diskchunk *chunks; 534eafadddfSkrw u_int64_t chunkstart, chunksize, cylsecs, secs, totsecs, xtrasecs; 53534ae4198Skrw char **partmp; 536a49bdda8Skrw int i, j, lastalloc, index = 0, fragsize, partno; 5378dde8bb6Sotto int64_t physmem; 5388dde8bb6Sotto 53934ae4198Skrw /* How big is the OpenBSD portion of the disk? */ 5408dde8bb6Sotto find_bounds(lp_org); 541557f712bSkrw 542fc6e9c48Sotto overlap = 0; 543fc6e9c48Sotto for (i = 0; i < MAXPARTITIONS; i++) { 544eafadddfSkrw u_int64_t psz, pstart, pend; 545fc6e9c48Sotto 546fc6e9c48Sotto pp = &lp_org->d_partitions[i]; 547fc6e9c48Sotto psz = DL_GETPSIZE(pp); 548fc6e9c48Sotto pstart = DL_GETPOFFSET(pp); 549fc6e9c48Sotto pend = pstart + psz; 550fc6e9c48Sotto if (i != RAW_PART && psz != 0 && 551fc6e9c48Sotto ((pstart >= starting_sector && pstart <= ending_sector) || 552fc6e9c48Sotto (pend > starting_sector && pend < ending_sector))) { 553fc6e9c48Sotto overlap = 1; 554fc6e9c48Sotto break; 555fc6e9c48Sotto } 556fc6e9c48Sotto } 557fc6e9c48Sotto 558930241e9Skrw physmem = getphysmem() / DEV_BSIZE; /* Blocks not sectors here! */ 559fc6e9c48Sotto 5608dde8bb6Sotto cylsecs = lp_org->d_secpercyl; 5618dde8bb6Sotto again: 5628dde8bb6Sotto lp = &label; 5633d98fc8cSkrw for (i=0; i<MAXPARTITIONS; i++) { 5643d98fc8cSkrw free(mountpoints[i]); 5653d98fc8cSkrw mountpoints[i] = NULL; 5663d98fc8cSkrw } 5678dde8bb6Sotto memcpy(lp, lp_org, sizeof(struct disklabel)); 5680a7398ceSderaadt lp->d_npartitions = MAXPARTITIONS; 5698dde8bb6Sotto lastalloc = alloc_table[index].sz; 570*ab30cb2fSdoug alloc = reallocarray(NULL, lastalloc, sizeof(struct space_allocation)); 5718dde8bb6Sotto if (alloc == NULL) 5728dde8bb6Sotto errx(4, "out of memory"); 5738dde8bb6Sotto memcpy(alloc, alloc_table[index].table, 5748dde8bb6Sotto lastalloc * sizeof(struct space_allocation)); 5758dde8bb6Sotto 5768dde8bb6Sotto /* bump max swap based on phys mem, little physmem gets 2x swap */ 5778dde8bb6Sotto if (index == 0) { 578930241e9Skrw if (physmem < MEG(256)) 5798dde8bb6Sotto alloc[1].maxsz = 2 * physmem; 5808dde8bb6Sotto else 5818dde8bb6Sotto alloc[1].maxsz += physmem; 5828dde8bb6Sotto /* bump max /var to make room for 2 crash dumps */ 5838dde8bb6Sotto alloc[3].maxsz += 2 * physmem; 5848dde8bb6Sotto } 5858dde8bb6Sotto 58634ae4198Skrw xtrasecs = totsecs = editor_countfree(lp); 587557f712bSkrw 58834ae4198Skrw for (i = 0; i < lastalloc; i++) { 5895f3e1104Skrw alloc[i].minsz = DL_BLKTOSEC(lp, alloc[i].minsz); 5905f3e1104Skrw alloc[i].maxsz = DL_BLKTOSEC(lp, alloc[i].maxsz); 59134ae4198Skrw if (xtrasecs > alloc[i].minsz) 59234ae4198Skrw xtrasecs -= alloc[i].minsz; 59334ae4198Skrw else 59434ae4198Skrw xtrasecs = 0; 595557f712bSkrw } 596557f712bSkrw 59734ae4198Skrw for (i = 0; i < lastalloc; i++) { 59834ae4198Skrw /* Find next available partition. */ 59934ae4198Skrw for (j = 0; j < MAXPARTITIONS; j++) 60034ae4198Skrw if (DL_GETPSIZE(&lp->d_partitions[j]) == 0) 60134ae4198Skrw break; 602a243d7b5Skrw if (j == MAXPARTITIONS) { 603a243d7b5Skrw /* It did not work out, try next strategy */ 604a243d7b5Skrw free(alloc); 605a243d7b5Skrw if (++index < nitems(alloc_table)) 606a243d7b5Skrw goto again; 607a243d7b5Skrw else 60834ae4198Skrw return; 609a243d7b5Skrw } 610a49bdda8Skrw partno = j; 61134ae4198Skrw pp = &lp->d_partitions[j]; 61234ae4198Skrw partmp = &mountpoints[j]; 61334ae4198Skrw ap = &alloc[i]; 614557f712bSkrw 61534ae4198Skrw /* Figure out the size of the partition. */ 61634ae4198Skrw if (i == lastalloc - 1) { 61734ae4198Skrw if (totsecs > ap->maxsz) 61834ae4198Skrw secs = ap->maxsz; 619557f712bSkrw else 6205f3e1104Skrw secs = totsecs; 6211f5ea549Skrw #ifdef SUN_CYLCHECK 6221f5ea549Skrw goto cylinderalign; 6231f5ea549Skrw #endif 624557f712bSkrw } else { 62534ae4198Skrw secs = ap->minsz; 6265f3e1104Skrw if (xtrasecs > 0) 62734ae4198Skrw secs += (xtrasecs / 100) * ap->rate; 62834ae4198Skrw if (secs > ap->maxsz) 62934ae4198Skrw secs = ap->maxsz; 6301f5ea549Skrw #ifdef SUN_CYLCHECK 6311f5ea549Skrw cylinderalign: 6325f3e1104Skrw secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; 6331f5ea549Skrw #endif 6345f3e1104Skrw totsecs -= secs; 6351f5ea549Skrw #ifdef SUN_CYLCHECK 6365f3e1104Skrw while (totsecs < 0) { 6375f3e1104Skrw secs -= cylsecs; 6385f3e1104Skrw totsecs += cylsecs; 639557f712bSkrw } 6401f5ea549Skrw #endif 641557f712bSkrw } 64234ae4198Skrw 64334ae4198Skrw /* Find largest chunk of free space. */ 64434ae4198Skrw chunks = free_chunks(lp); 64534ae4198Skrw chunkstart = 0; 64634ae4198Skrw chunksize = 0; 64734ae4198Skrw for (j = 0; chunks[j].start != 0 || chunks[j].stop != 0; j++) 64834ae4198Skrw if ((chunks[j].stop - chunks[j].start) > chunksize) { 64934ae4198Skrw chunkstart = chunks[j].start; 65034ae4198Skrw chunksize = chunks[j].stop - chunks[j].start; 651557f712bSkrw } 65234ae4198Skrw #ifdef SUN_CYLCHECK 65334ae4198Skrw if (lp->d_flags & D_VENDOR) { 65434ae4198Skrw /* Align chunk to cylinder boundaries. */ 65534ae4198Skrw chunksize -= chunksize % cylsecs; 6566ab0bb66Skrw chunkstart = ((chunkstart + cylsecs - 1) / cylsecs) * 6576ab0bb66Skrw cylsecs; 65834ae4198Skrw } 65934ae4198Skrw #endif 66034ae4198Skrw /* See if partition can fit into chunk. */ 66134ae4198Skrw if (secs > chunksize) { 66234ae4198Skrw totsecs += secs - chunksize; 66334ae4198Skrw secs = chunksize; 66434ae4198Skrw } 66534ae4198Skrw if (secs < ap->minsz) { 6668dde8bb6Sotto /* It did not work out, try next strategy */ 6678dde8bb6Sotto free(alloc); 6688dde8bb6Sotto if (++index < nitems(alloc_table)) 6698dde8bb6Sotto goto again; 6708dde8bb6Sotto else 6718dde8bb6Sotto return; 672557f712bSkrw } 67334ae4198Skrw 67434ae4198Skrw /* Everything seems ok so configure the partition. */ 6755f3e1104Skrw DL_SETPSIZE(pp, secs); 67634ae4198Skrw DL_SETPOFFSET(pp, chunkstart); 677ef93a5eeSkrw fragsize = (lp->d_secsize == DEV_BSIZE) ? 2048 : 678ef93a5eeSkrw lp->d_secsize; 679c88f83bdSotto if (secs * lp->d_secsize > 128ULL * 1024 * 1024 * 1024) 680c88f83bdSotto fragsize *= 2; 681c88f83bdSotto if (secs * lp->d_secsize > 512ULL * 1024 * 1024 * 1024) 682c88f83bdSotto fragsize *= 2; 683557f712bSkrw #if defined (__sparc__) && !defined(__sparc64__) 684557f712bSkrw /* can't boot from > 8k boot blocks */ 685557f712bSkrw pp->p_fragblock = 6866e312d52Sotto DISKLABELV1_FFS_FRAGBLOCK(i == 0 ? 1024 : fragsize, 8); 687557f712bSkrw #else 6886e312d52Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8); 689557f712bSkrw #endif 690557f712bSkrw pp->p_cpg = 1; 69134ae4198Skrw if (ap->mp[0] != '/') 69234ae4198Skrw pp->p_fstype = FS_SWAP; 69334ae4198Skrw else { 69434ae4198Skrw pp->p_fstype = FS_BSDFFS; 695a49bdda8Skrw get_bsize(lp, partno); 69634ae4198Skrw free(*partmp); 69734ae4198Skrw if ((*partmp = strdup(ap->mp)) == NULL) 698557f712bSkrw errx(4, "out of memory"); 699557f712bSkrw } 700557f712bSkrw } 701557f712bSkrw 7028dde8bb6Sotto free(alloc); 7038dde8bb6Sotto memcpy(lp_org, lp, sizeof(struct disklabel)); 704557f712bSkrw } 705557f712bSkrw 706557f712bSkrw /* 7076aaa4aabSotto * Resize a partition, moving all subsequent partitions 7086aaa4aabSotto */ 7096aaa4aabSotto void 7106aaa4aabSotto editor_resize(struct disklabel *lp, char *p) 7116aaa4aabSotto { 7126aaa4aabSotto struct disklabel label; 7136aaa4aabSotto struct partition *pp, *prev; 714eafadddfSkrw u_int64_t secs, sz, off; 7156aaa4aabSotto #ifdef SUN_CYLCHECK 716eafadddfSkrw u_int64_t cylsecs; 7176aaa4aabSotto #endif 7186aaa4aabSotto int partno, i; 7196aaa4aabSotto 7206aaa4aabSotto label = *lp; 7216aaa4aabSotto 7226aaa4aabSotto /* Change which partition? */ 7236aaa4aabSotto if (p == NULL) { 7246aaa4aabSotto p = getstring("partition to resize", 7256aaa4aabSotto "The letter of the partition to name, a - p.", NULL); 7266aaa4aabSotto } 7276aaa4aabSotto if (p == NULL) { 7286aaa4aabSotto fputs("Command aborted\n", stderr); 7296aaa4aabSotto return; 7306aaa4aabSotto } 7316aaa4aabSotto partno = p[0] - 'a'; 7326aaa4aabSotto if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 7336aaa4aabSotto fprintf(stderr, "Partition must be between 'a' and '%c' " 7346aaa4aabSotto "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 7356aaa4aabSotto return; 7366aaa4aabSotto } 7376aaa4aabSotto 7386aaa4aabSotto pp = &label.d_partitions[partno]; 739fc6e9c48Sotto sz = DL_GETPSIZE(pp); 740fc6e9c48Sotto if (sz == 0) { 741fc6e9c48Sotto fputs("No such partition\n", stderr); 742fc6e9c48Sotto return; 743fc6e9c48Sotto } 744fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) { 745fc6e9c48Sotto fputs("Cannot resize spoofed partition\n", stderr); 746fc6e9c48Sotto return; 747fc6e9c48Sotto } 748117239d3Skrw secs = getuint64(lp, "[+|-]new size (with unit)", 7494659aa0dSotto "new size or amount to grow (+) or shrink (-) partition including unit", 7504659aa0dSotto sz, editor_countfree(lp), 0, DO_CONVERSIONS); 7516aaa4aabSotto 7524659aa0dSotto if (secs <= 0) { 7536aaa4aabSotto fputs("Command aborted\n", stderr); 7546aaa4aabSotto return; 7556aaa4aabSotto } 7566aaa4aabSotto 7576aaa4aabSotto #ifdef SUN_CYLCHECK 7586aaa4aabSotto cylsecs = lp->d_secpercyl; 7596aaa4aabSotto if (secs > 0) 7606aaa4aabSotto secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; 7616aaa4aabSotto else 7626aaa4aabSotto secs = ((secs - cylsecs + 1) / cylsecs) * cylsecs; 7636aaa4aabSotto #endif 7644659aa0dSotto if (DL_GETPOFFSET(pp) + secs > ending_sector) { 7656aaa4aabSotto fputs("Amount too big\n", stderr); 7666aaa4aabSotto return; 7676aaa4aabSotto } 7686aaa4aabSotto 7694659aa0dSotto DL_SETPSIZE(pp, secs); 770e5f81948Sotto get_bsize(&label, partno); 7716aaa4aabSotto 7726aaa4aabSotto /* 7736aaa4aabSotto * Pack partitions above the resized partition, leaving unused 7746aaa4aabSotto * partions alone. 7756aaa4aabSotto */ 7766aaa4aabSotto prev = pp; 7776aaa4aabSotto for (i = partno + 1; i < MAXPARTITIONS; i++) { 7786aaa4aabSotto if (i == RAW_PART) 7796aaa4aabSotto continue; 780fc6e9c48Sotto pp = &label.d_partitions[i]; 781fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) 782fc6e9c48Sotto continue; 783fc6e9c48Sotto sz = DL_GETPSIZE(pp); 7846aaa4aabSotto if (sz == 0) 7856aaa4aabSotto continue; 7866aaa4aabSotto 7876aaa4aabSotto off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev); 7886aaa4aabSotto 7896aaa4aabSotto if (off < ending_sector) { 7906aaa4aabSotto DL_SETPOFFSET(pp, off); 7916aaa4aabSotto if (off + DL_GETPSIZE(pp) > ending_sector) { 7926aaa4aabSotto DL_SETPSIZE(pp, ending_sector - off); 7936aaa4aabSotto fprintf(stderr, 7946aaa4aabSotto "Partition %c shrunk to make room\n", 7956aaa4aabSotto i + 'a'); 7966aaa4aabSotto } 7976aaa4aabSotto } else { 7986aaa4aabSotto fputs("No room left for all partitions\n", stderr); 7996aaa4aabSotto return; 8006aaa4aabSotto } 801e5f81948Sotto get_bsize(&label, i); 8026aaa4aabSotto prev = pp; 8036aaa4aabSotto } 8046aaa4aabSotto *lp = label; 8056aaa4aabSotto } 8066aaa4aabSotto 8076aaa4aabSotto /* 8086fe57b42Smillert * Add a new partition. 8096fe57b42Smillert */ 8106fe57b42Smillert void 81134ae4198Skrw editor_add(struct disklabel *lp, char *p) 8126fe57b42Smillert { 81396a888c6Smillert struct partition *pp; 81496a888c6Smillert struct diskchunk *chunks; 8155caa08b2Skrw char buf[2]; 8166e312d52Sotto int i, partno, fragsize; 817f8ab7229Schl u_int64_t freesectors, new_offset, new_size; 8189fdcb4d6Skrw 8199fdcb4d6Skrw freesectors = editor_countfree(lp); 8206fe57b42Smillert 8216fe57b42Smillert /* XXX - prompt user to steal space from another partition instead */ 822fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 8239fdcb4d6Skrw if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) { 824fc1a4cc6Sderaadt fputs("No space left, you need to shrink a partition " 825fc1a4cc6Sderaadt "(need at least one full cylinder)\n", 826fc1a4cc6Sderaadt stderr); 827fc1a4cc6Sderaadt return; 828fc1a4cc6Sderaadt } 8298390cf28Smillert #endif 8309fdcb4d6Skrw if (freesectors == 0) { 8316fe57b42Smillert fputs("No space left, you need to shrink a partition\n", 8326fe57b42Smillert stderr); 8336fe57b42Smillert return; 8346fe57b42Smillert } 8356fe57b42Smillert 8365caa08b2Skrw if (p == NULL) { 8375caa08b2Skrw /* 8385caa08b2Skrw * Use the first unused partition that is not 'c' as the 8395caa08b2Skrw * default partition in the prompt string. 8405caa08b2Skrw */ 8415caa08b2Skrw pp = &lp->d_partitions[0]; 8425caa08b2Skrw buf[0] = buf[1] = '\0'; 8435caa08b2Skrw for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) { 8445caa08b2Skrw if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) { 8455caa08b2Skrw buf[0] = partno + 'a'; 8465caa08b2Skrw p = &buf[0]; 8476fe57b42Smillert break; 8486fe57b42Smillert } 8495caa08b2Skrw } 850c33fcabaSmillert p = getstring("partition", 8516fe57b42Smillert "The letter of the new partition, a - p.", p); 8526fe57b42Smillert } 8535caa08b2Skrw if (p == NULL) { 8545caa08b2Skrw fputs("Command aborted\n", stderr); 8555caa08b2Skrw return; 8565caa08b2Skrw } 8575caa08b2Skrw partno = p[0] - 'a'; 8585caa08b2Skrw if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) { 8595caa08b2Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 8605caa08b2Skrw "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1); 8615caa08b2Skrw return; 8625caa08b2Skrw } 8635caa08b2Skrw pp = &lp->d_partitions[partno]; 8645caa08b2Skrw 8655caa08b2Skrw if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) { 8665caa08b2Skrw fprintf(stderr, "Partition '%c' exists. Delete it first.\n", 8675caa08b2Skrw p[0]); 8685caa08b2Skrw return; 8696fe57b42Smillert } 87096a888c6Smillert 871caf41f96Skrw /* 872caf41f96Skrw * Increase d_npartitions if necessary. Ensure all new partitions are 873855d4e83Ssobrado * zero'ed to avoid inadvertent overlaps. 874caf41f96Skrw */ 875caf41f96Skrw for(; lp->d_npartitions <= partno; lp->d_npartitions++) 876caf41f96Skrw memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp)); 87796a888c6Smillert 87889f4601dSkrw /* Make sure selected partition is zero'd too. */ 87989f4601dSkrw memset(pp, 0, sizeof(*pp)); 88015c15d8aSkrw chunks = free_chunks(lp); 88115c15d8aSkrw 88215c15d8aSkrw /* 88315c15d8aSkrw * Since we know there's free space, there must be at least one 88415c15d8aSkrw * chunk. So find the largest chunk and assume we want to add the 88515c15d8aSkrw * partition in that free space. 88615c15d8aSkrw */ 88715c15d8aSkrw new_size = new_offset = 0; 88815c15d8aSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 88915c15d8aSkrw if (chunks[i].stop - chunks[i].start > new_size) { 89015c15d8aSkrw new_size = chunks[i].stop - chunks[i].start; 89115c15d8aSkrw new_offset = chunks[i].start; 89215c15d8aSkrw } 89315c15d8aSkrw } 8941e0ad43cSotto DL_SETPSIZE(pp, new_size); 8951e0ad43cSotto DL_SETPOFFSET(pp, new_offset); 89696a888c6Smillert pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS; 897c88f83bdSotto pp->p_cpg = 1; 898c88f83bdSotto 899c88f83bdSotto if (get_offset(lp, partno) == 0 && 900c88f83bdSotto get_size(lp, partno) == 0) { 901d476f177Skrw fragsize = (lp->d_secsize == DEV_BSIZE) ? 2048 : 902d476f177Skrw lp->d_secsize; 903c88f83bdSotto new_size = DL_GETPSIZE(pp) * lp->d_secsize; 904c88f83bdSotto if (new_size > 128ULL * 1024 * 1024 * 1024) 905c88f83bdSotto fragsize *= 2; 906c88f83bdSotto if (new_size > 512ULL * 1024 * 1024 * 1024) 907c88f83bdSotto fragsize *= 2; 9089b84e584Sotto if (fragsize > MAXBSIZE / 8) 9099b84e584Sotto fragsize = MAXBSIZE / 8; 9104a8b9208Stedu #if defined (__sparc__) && !defined(__sparc64__) 911d98d4df7Stedu /* can't boot from > 8k boot blocks */ 912ddfcbf38Sotto pp->p_fragblock = 9136e312d52Sotto DISKLABELV1_FFS_FRAGBLOCK(partno == 0 ? 1024 : fragsize, 8); 914d98d4df7Stedu #else 9156e312d52Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8); 916d98d4df7Stedu #endif 917c88f83bdSotto if (get_fstype(lp, partno) == 0 && 91834ae4198Skrw get_mp(lp, partno) == 0 && 919a4c87e64Skrw get_fsize(lp, partno) == 0 && 920a4c87e64Skrw get_bsize(lp, partno) == 0) 92196a888c6Smillert return; 922c88f83bdSotto } 923a4c87e64Skrw /* Bailed out at some point, so effectively delete the partition. */ 924da2bd3f5Skrw memset(pp, 0, sizeof(*pp)); 9256fe57b42Smillert } 9266fe57b42Smillert 9276fe57b42Smillert /* 928bd6726faSmillert * Set the mountpoint of an existing partition ('name'). 929bd6726faSmillert */ 930bd6726faSmillert void 93134ae4198Skrw editor_name(struct disklabel *lp, char *p) 932bd6726faSmillert { 933bd6726faSmillert struct partition *pp; 934bd6726faSmillert int partno; 935bd6726faSmillert 936bd6726faSmillert /* Change which partition? */ 937bd6726faSmillert if (p == NULL) { 938c33fcabaSmillert p = getstring("partition to name", 939bd6726faSmillert "The letter of the partition to name, a - p.", NULL); 940bd6726faSmillert } 941bd6726faSmillert if (p == NULL) { 942bd6726faSmillert fputs("Command aborted\n", stderr); 943bd6726faSmillert return; 944bd6726faSmillert } 945bd6726faSmillert partno = p[0] - 'a'; 9466c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9476c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9486c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 949bd6726faSmillert return; 95066df1f0cSkrw } 95166df1f0cSkrw pp = &lp->d_partitions[partno]; 95266df1f0cSkrw 95366df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 95466df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 955bd6726faSmillert return; 956bd6726faSmillert } 957bd6726faSmillert 958bd6726faSmillert /* Not all fstypes can be named */ 959bd6726faSmillert if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP || 960bd387921Stodd pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER || 961bd387921Stodd pp->p_fstype == FS_RAID) { 962bd6726faSmillert fprintf(stderr, "You cannot name a filesystem of type %s.\n", 963baa55472Smillert fstypenames[lp->d_partitions[partno].p_fstype]); 964bd6726faSmillert return; 965bd6726faSmillert } 966bd6726faSmillert 96734ae4198Skrw get_mp(lp, partno); 968bd6726faSmillert } 969bd6726faSmillert 970bd6726faSmillert /* 9716fe57b42Smillert * Change an existing partition. 9726fe57b42Smillert */ 9736fe57b42Smillert void 97434ae4198Skrw editor_modify(struct disklabel *lp, char *p) 9756fe57b42Smillert { 9766fe57b42Smillert struct partition origpart, *pp; 977f8ab7229Schl int partno; 9786fe57b42Smillert 9796fe57b42Smillert /* Change which partition? */ 9806fe57b42Smillert if (p == NULL) { 981c33fcabaSmillert p = getstring("partition to modify", 9826fe57b42Smillert "The letter of the partition to modify, a - p.", NULL); 9836fe57b42Smillert } 98496a888c6Smillert if (p == NULL) { 98596a888c6Smillert fputs("Command aborted\n", stderr); 98696a888c6Smillert return; 98796a888c6Smillert } 9886fe57b42Smillert partno = p[0] - 'a'; 9896c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9906c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9916c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 9926fe57b42Smillert return; 99366df1f0cSkrw } 99466df1f0cSkrw pp = &lp->d_partitions[partno]; 99566df1f0cSkrw 99666df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 99766df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 9986fe57b42Smillert return; 9996fe57b42Smillert } 10006fe57b42Smillert 100166df1f0cSkrw origpart = *pp; 100266df1f0cSkrw 1003a4c87e64Skrw if (get_offset(lp, partno) == 0 && 1004a4c87e64Skrw get_size(lp, partno) == 0 && 1005a4c87e64Skrw get_fstype(lp, partno) == 0 && 100634ae4198Skrw get_mp(lp, partno) == 0 && 1007a4c87e64Skrw get_fsize(lp, partno) == 0 && 1008a4c87e64Skrw get_bsize(lp, partno) == 0) 100996a888c6Smillert return; 10106fe57b42Smillert 1011a4c87e64Skrw /* Bailed out at some point, so undo any changes. */ 1012a4c87e64Skrw *pp = origpart; 10136fe57b42Smillert } 10146fe57b42Smillert 10156fe57b42Smillert /* 10166fe57b42Smillert * Delete an existing partition. 10176fe57b42Smillert */ 10186fe57b42Smillert void 101934ae4198Skrw editor_delete(struct disklabel *lp, char *p) 10206fe57b42Smillert { 102166df1f0cSkrw struct partition *pp; 1022135c90d1Skrw int partno; 10236fe57b42Smillert 10246fe57b42Smillert if (p == NULL) { 1025c33fcabaSmillert p = getstring("partition to delete", 1026945ae268Smillert "The letter of the partition to delete, a - p, or '*'.", 1027945ae268Smillert NULL); 10286fe57b42Smillert } 102996a888c6Smillert if (p == NULL) { 103096a888c6Smillert fputs("Command aborted\n", stderr); 103196a888c6Smillert return; 103296a888c6Smillert } 1033945ae268Smillert if (p[0] == '*') { 10349fdcb4d6Skrw zero_partitions(lp); 1035945ae268Smillert return; 1036945ae268Smillert } 1037135c90d1Skrw partno = p[0] - 'a'; 1038135c90d1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 10396c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 10406c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 104133262abfSmiod return; 104266df1f0cSkrw } 1043135c90d1Skrw pp = &lp->d_partitions[partno]; 104466df1f0cSkrw 104566df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 104666df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 104733262abfSmiod return; 104866df1f0cSkrw } 104966df1f0cSkrw 10506fe57b42Smillert /* Really delete it (as opposed to just setting to "unused") */ 1051135c90d1Skrw memset(pp, 0, sizeof(*pp)); 105234ae4198Skrw free(mountpoints[partno]); 105334ae4198Skrw mountpoints[partno] = NULL; 10546fe57b42Smillert } 10556fe57b42Smillert 10566fe57b42Smillert /* 10576fe57b42Smillert * Change the size of an existing partition. 10586fe57b42Smillert */ 10596fe57b42Smillert void 10609fdcb4d6Skrw editor_change(struct disklabel *lp, char *p) 10616fe57b42Smillert { 10624b9a3bdaSmillert struct partition *pp; 106366df1f0cSkrw int partno; 10646fe57b42Smillert 10656fe57b42Smillert if (p == NULL) { 1066c33fcabaSmillert p = getstring("partition to change size", 10676fe57b42Smillert "The letter of the partition to change size, a - p.", NULL); 10686fe57b42Smillert } 106996a888c6Smillert if (p == NULL) { 107096a888c6Smillert fputs("Command aborted\n", stderr); 107196a888c6Smillert return; 107296a888c6Smillert } 10736fe57b42Smillert partno = p[0] - 'a'; 10746c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 10756c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 10766c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 10776fe57b42Smillert return; 10786fe57b42Smillert } 10794b9a3bdaSmillert pp = &lp->d_partitions[partno]; 10806fe57b42Smillert 108166df1f0cSkrw if (DL_GETPSIZE(pp) == 0) { 108266df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 108366df1f0cSkrw return; 108466df1f0cSkrw } 108566df1f0cSkrw 108614192793Skrw printf("Partition %c is currently %llu sectors in size, and can have " 108714192793Skrw "a maximum\nsize of %llu sectors.\n", 108814192793Skrw p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno)); 10897da73705Skrw 109059ccf790Skrw /* Get new size */ 10919fdcb4d6Skrw get_size(lp, partno); 10926fe57b42Smillert } 10936fe57b42Smillert 10946fe57b42Smillert /* 10956fe57b42Smillert * Sort the partitions based on starting offset. 10966fe57b42Smillert * This assumes there can be no overlap. 10976fe57b42Smillert */ 10986fe57b42Smillert int 10998809fabbSderaadt partition_cmp(const void *e1, const void *e2) 11006fe57b42Smillert { 11016fe57b42Smillert struct partition *p1 = *(struct partition **)e1; 11026fe57b42Smillert struct partition *p2 = *(struct partition **)e2; 11031e0ad43cSotto u_int64_t o1 = DL_GETPOFFSET(p1); 11041e0ad43cSotto u_int64_t o2 = DL_GETPOFFSET(p2); 11056fe57b42Smillert 11061e0ad43cSotto if (o1 < o2) 1107651d5bd9Sotto return -1; 11081e0ad43cSotto else if (o1 > o2) 1109651d5bd9Sotto return 1; 1110651d5bd9Sotto else 1111651d5bd9Sotto return 0; 11126fe57b42Smillert } 11136fe57b42Smillert 11146fe57b42Smillert char * 11158809fabbSderaadt getstring(char *prompt, char *helpstring, char *oval) 11166fe57b42Smillert { 11176fe57b42Smillert static char buf[BUFSIZ]; 11186fe57b42Smillert int n; 11196fe57b42Smillert 11206fe57b42Smillert buf[0] = '\0'; 11216fe57b42Smillert do { 11226fe57b42Smillert printf("%s: [%s] ", prompt, oval ? oval : ""); 11236e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1124260513deSmillert buf[0] = '\0'; 112596a888c6Smillert if (feof(stdin)) { 112624c6582eSmillert clearerr(stdin); 112796a888c6Smillert putchar('\n'); 112896a888c6Smillert return(NULL); 112996a888c6Smillert } 11306e0becc5Smillert } 11316fe57b42Smillert n = strlen(buf); 11326fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 11336fe57b42Smillert buf[--n] = '\0'; 11346fe57b42Smillert if (buf[0] == '?') 11356fe57b42Smillert puts(helpstring); 11364fb6ab7cSmillert else if (oval != NULL && buf[0] == '\0') 11374fb6ab7cSmillert strlcpy(buf, oval, sizeof(buf)); 11386fe57b42Smillert } while (buf[0] == '?'); 11396fe57b42Smillert 11406fe57b42Smillert return(&buf[0]); 11416fe57b42Smillert } 11426fe57b42Smillert 11436fe57b42Smillert /* 11441e0ad43cSotto * Returns ULLONG_MAX on error 114524a2c1a4Smillert * Usually only called by helper functions. 11466fe57b42Smillert */ 11471e0ad43cSotto u_int64_t 1148117239d3Skrw getuint64(struct disklabel *lp, char *prompt, char *helpstring, 11491e0ad43cSotto u_int64_t oval, u_int64_t maxval, u_int64_t offset, int flags) 11506fe57b42Smillert { 11516fe57b42Smillert char buf[BUFSIZ], *endptr, *p, operator = '\0'; 11521e0ad43cSotto u_int64_t rval = oval; 1153e04edc8bSkrw int64_t mult = 1; 11546fe57b42Smillert size_t n; 115514cc915fSmillert double d, percent = 1.0; 11566fe57b42Smillert 11574b9a3bdaSmillert /* We only care about the remainder */ 11584b9a3bdaSmillert offset = offset % lp->d_secpercyl; 11594b9a3bdaSmillert 11606fe57b42Smillert buf[0] = '\0'; 11616fe57b42Smillert do { 11621e0ad43cSotto printf("%s: [%llu] ", prompt, oval); 11636e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 11646e0becc5Smillert buf[0] = '\0'; 116596a888c6Smillert if (feof(stdin)) { 116624c6582eSmillert clearerr(stdin); 116796a888c6Smillert putchar('\n'); 11681e0ad43cSotto return(ULLONG_MAX - 1); 116996a888c6Smillert } 11706e0becc5Smillert } 11716fe57b42Smillert n = strlen(buf); 11726fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 11736fe57b42Smillert buf[--n] = '\0'; 11746fe57b42Smillert if (buf[0] == '?') 11756fe57b42Smillert puts(helpstring); 11766fe57b42Smillert } while (buf[0] == '?'); 11776fe57b42Smillert 11786fe57b42Smillert if (buf[0] == '*' && buf[1] == '\0') { 11796fe57b42Smillert rval = maxval; 11806fe57b42Smillert } else { 11816fe57b42Smillert /* deal with units */ 11826fe57b42Smillert if (buf[0] != '\0' && n > 0) { 11836fe57b42Smillert if ((flags & DO_CONVERSIONS)) { 1184025f5691Sderaadt switch (tolower((unsigned char)buf[n-1])) { 11856fe57b42Smillert 11866fe57b42Smillert case 'c': 11876fe57b42Smillert mult = lp->d_secpercyl; 11886fe57b42Smillert buf[--n] = '\0'; 11896fe57b42Smillert break; 11906fe57b42Smillert case 'b': 11913f74e3efSkrw mult = -(int64_t)lp->d_secsize; 11926fe57b42Smillert buf[--n] = '\0'; 11936fe57b42Smillert break; 11946fe57b42Smillert case 'k': 119550c0f47aSkrw if (lp->d_secsize > 1024) 11963f74e3efSkrw mult = -(int64_t)lp->d_secsize / 11973f74e3efSkrw 1024LL; 119850c0f47aSkrw else 1199e04edc8bSkrw mult = 1024LL / lp->d_secsize; 12006fe57b42Smillert buf[--n] = '\0'; 12016fe57b42Smillert break; 12026fe57b42Smillert case 'm': 1203e04edc8bSkrw mult = (1024LL * 1024) / lp->d_secsize; 12046fe57b42Smillert buf[--n] = '\0'; 12056fe57b42Smillert break; 12061a51a1eeSmillert case 'g': 1207e04edc8bSkrw mult = (1024LL * 1024 * 1024) / 1208e04edc8bSkrw lp->d_secsize; 1209e04edc8bSkrw buf[--n] = '\0'; 1210e04edc8bSkrw break; 1211e04edc8bSkrw case 't': 1212e04edc8bSkrw mult = (1024LL * 1024 * 1024 * 1024) / 1213e04edc8bSkrw lp->d_secsize; 12141a51a1eeSmillert buf[--n] = '\0'; 12151a51a1eeSmillert break; 121614cc915fSmillert case '%': 121714cc915fSmillert buf[--n] = '\0'; 12184659aa0dSotto p = &buf[0]; 12194659aa0dSotto if (*p == '+' || *p == '-') 12204659aa0dSotto operator = *p++; 12214659aa0dSotto percent = strtod(p, NULL) / 100.0; 1222605eea5fSkrw snprintf(buf, sizeof(buf), "%llu", 12231e0ad43cSotto DL_GETDSIZE(lp)); 122414cc915fSmillert break; 122514cc915fSmillert case '&': 122614cc915fSmillert buf[--n] = '\0'; 12274659aa0dSotto p = &buf[0]; 12284659aa0dSotto if (*p == '+' || *p == '-') 12294659aa0dSotto operator = *p++; 12304659aa0dSotto percent = strtod(p, NULL) / 100.0; 12311e0ad43cSotto snprintf(buf, sizeof(buf), "%lld", 123214cc915fSmillert maxval); 123314cc915fSmillert break; 12346fe57b42Smillert } 123596a888c6Smillert } 12366fe57b42Smillert 12376fe57b42Smillert /* Did they give us an operator? */ 12386fe57b42Smillert p = &buf[0]; 12396fe57b42Smillert if (*p == '+' || *p == '-') 12406fe57b42Smillert operator = *p++; 12416fe57b42Smillert 12426fe57b42Smillert endptr = p; 124396a888c6Smillert errno = 0; 124496a888c6Smillert d = strtod(p, &endptr); 124596a888c6Smillert if (errno == ERANGE) 12461e0ad43cSotto rval = ULLONG_MAX; /* too big/small */ 124796a888c6Smillert else if (*endptr != '\0') { 12486fe57b42Smillert errno = EINVAL; /* non-numbers in str */ 12491e0ad43cSotto rval = ULLONG_MAX; 12506fe57b42Smillert } else { 125196a888c6Smillert /* XXX - should check for overflow */ 125296a888c6Smillert if (mult > 0) 125314cc915fSmillert rval = d * mult * percent; 125496a888c6Smillert else 125596a888c6Smillert /* Negative mult means divide (fancy) */ 125614cc915fSmillert rval = d / (-mult) * percent; 12576fe57b42Smillert 125896a888c6Smillert /* Apply the operator */ 12596fe57b42Smillert if (operator == '+') 12606fe57b42Smillert rval += oval; 12616fe57b42Smillert else if (operator == '-') 12626fe57b42Smillert rval = oval - rval; 12636fe57b42Smillert } 12646fe57b42Smillert } 12656fe57b42Smillert } 12668390cf28Smillert if ((flags & DO_ROUNDING) && rval != ULLONG_MAX) { 126796a888c6Smillert /* Round to nearest cylinder unless given in sectors */ 12688390cf28Smillert if ( 1269fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 1270fc1a4cc6Sderaadt ((lp->d_flags & D_VENDOR) || mult != 1) && 1271fc1a4cc6Sderaadt #else 12728390cf28Smillert mult != 1 && 1273dbffb156Smillert #endif 12748390cf28Smillert (rval + offset) % lp->d_secpercyl != 0) { 12751e0ad43cSotto u_int64_t cyls; 1276dbffb156Smillert 12778390cf28Smillert /* Round to higher cylinder but no more than maxval */ 12788390cf28Smillert cyls = (rval / lp->d_secpercyl) + 1; 12798390cf28Smillert if ((cyls * lp->d_secpercyl) - offset > maxval) 1280dbffb156Smillert cyls--; 12814b9a3bdaSmillert rval = (cyls * lp->d_secpercyl) - offset; 1282ef5288d7Skrw if (!aflag) 1283ef5288d7Skrw printf("Rounding size to cylinder (%d sectors)" 1284ef5288d7Skrw ": %llu\n", lp->d_secpercyl, rval); 12856fe57b42Smillert } 12864b9a3bdaSmillert } 12876fe57b42Smillert 12886fe57b42Smillert return(rval); 12896fe57b42Smillert } 12906fe57b42Smillert 12916fe57b42Smillert /* 12921f0f871dSkrw * Check for partition overlap in lp and prompt the user to resolve the overlap 12931f0f871dSkrw * if any is found. Returns 1 if unable to resolve, else 0. 12946fe57b42Smillert */ 12956fe57b42Smillert int 12961f0f871dSkrw has_overlap(struct disklabel *lp) 12976fe57b42Smillert { 12986fe57b42Smillert struct partition **spp; 1299e6aa8bafSmillert int c, i, j; 1300e6aa8bafSmillert char buf[BUFSIZ]; 13016fe57b42Smillert 13020fbd3c97Skrw /* Get a sorted list of the in-use partitions. */ 13030fbd3c97Skrw spp = sort_partitions(lp); 13046fe57b42Smillert 13050fbd3c97Skrw /* If there are less than two partitions in use, there is no overlap. */ 13060fbd3c97Skrw if (spp[1] == NULL) 13070fbd3c97Skrw return(0); 13086fe57b42Smillert 13096fe57b42Smillert /* Now that we have things sorted by starting sector check overlap */ 13100fbd3c97Skrw for (i = 0; spp[i] != NULL; i++) { 13110fbd3c97Skrw for (j = i + 1; spp[j] != NULL; j++) { 13126fe57b42Smillert /* `if last_sec_in_part + 1 > first_sec_in_next_part' */ 1313430e1380Skrw if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) > 1314430e1380Skrw DL_GETPOFFSET(spp[j])) { 13156fe57b42Smillert /* Overlap! Convert to real part numbers. */ 13166fe57b42Smillert i = ((char *)spp[i] - (char *)lp->d_partitions) 13176fe57b42Smillert / sizeof(**spp); 13186fe57b42Smillert j = ((char *)spp[j] - (char *)lp->d_partitions) 13196fe57b42Smillert / sizeof(**spp); 1320430e1380Skrw printf("\nError, partitions %c and %c overlap:" 1321430e1380Skrw "\n", 'a' + i, 'a' + j); 1322366bf641Skrw printf("# %16.16s %16.16s fstype " 1323651d5bd9Sotto "[fsize bsize cpg]\n", "size", "offset"); 132434ae4198Skrw display_partition(stdout, lp, i, 0); 132534ae4198Skrw display_partition(stdout, lp, j, 0); 13266fe57b42Smillert 1327e6aa8bafSmillert /* Get partition to disable or ^D */ 1328e6aa8bafSmillert do { 1329430e1380Skrw printf("Disable which one? " 1330430e1380Skrw "(^D to abort) [%c %c] ", 13316fe57b42Smillert 'a' + i, 'a' + j); 1332e6aa8bafSmillert buf[0] = '\0'; 1333616cd1c4Smillert if (!fgets(buf, sizeof(buf), stdin)) { 1334616cd1c4Smillert putchar('\n'); 1335e6aa8bafSmillert return(1); /* ^D */ 1336616cd1c4Smillert } 1337e6aa8bafSmillert c = buf[0] - 'a'; 1338e6aa8bafSmillert } while (buf[1] != '\n' && buf[1] != '\0' && 1339e6aa8bafSmillert c != i && c != j); 1340e6aa8bafSmillert 1341e6aa8bafSmillert /* Mark the selected one as unused */ 13426fe57b42Smillert lp->d_partitions[c].p_fstype = FS_UNUSED; 13431f0f871dSkrw return (has_overlap(lp)); 13446fe57b42Smillert } 13456fe57b42Smillert } 13466fe57b42Smillert } 1347f0b4d0a9Smillert 1348e6aa8bafSmillert return(0); 13496fe57b42Smillert } 13506fe57b42Smillert 13516fe57b42Smillert void 13529fdcb4d6Skrw edit_parms(struct disklabel *lp) 13536fe57b42Smillert { 13546fe57b42Smillert char *p; 13559fdcb4d6Skrw u_int64_t freesectors, ui; 135696a888c6Smillert struct disklabel oldlabel = *lp; 13576fe57b42Smillert 1358ea37abd3Sderaadt printf("Changing device parameters for %s:\n", specname); 13596fe57b42Smillert 13600f820bbbSmillert /* disk type */ 13610f820bbbSmillert for (;;) { 1362c33fcabaSmillert p = getstring("disk type", 136341282a2aSmillert "What kind of disk is this? Usually SCSI, ESDI, ST506, or " 136441282a2aSmillert "floppy (use ESDI for IDE).", dktypenames[lp->d_type]); 136596a888c6Smillert if (p == NULL) { 136696a888c6Smillert fputs("Command aborted\n", stderr); 136796a888c6Smillert return; 136896a888c6Smillert } 136941282a2aSmillert if (strcasecmp(p, "IDE") == 0) 137041282a2aSmillert ui = DTYPE_ESDI; 137141282a2aSmillert else 137241282a2aSmillert for (ui = 1; ui < DKMAXTYPES && 137341282a2aSmillert strcasecmp(p, dktypenames[ui]); ui++) 13740f820bbbSmillert ; 13750f820bbbSmillert if (ui < DKMAXTYPES) { 13760f820bbbSmillert break; 13770f820bbbSmillert } else { 13780f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", p); 13790f820bbbSmillert fputs("Valid types are: ", stdout); 13800f820bbbSmillert for (ui = 1; ui < DKMAXTYPES; ui++) { 13810f820bbbSmillert printf("\"%s\"", dktypenames[ui]); 13820f820bbbSmillert if (ui < DKMAXTYPES - 1) 13830f820bbbSmillert fputs(", ", stdout); 13840f820bbbSmillert } 13850f820bbbSmillert putchar('\n'); 13860f820bbbSmillert } 13870f820bbbSmillert } 13880f820bbbSmillert lp->d_type = ui; 13890f820bbbSmillert 13906fe57b42Smillert /* pack/label id */ 1391c33fcabaSmillert p = getstring("label name", 13926fe57b42Smillert "15 char string that describes this label, usually the disk name.", 13936fe57b42Smillert lp->d_packname); 139496a888c6Smillert if (p == NULL) { 139596a888c6Smillert fputs("Command aborted\n", stderr); 139696a888c6Smillert *lp = oldlabel; /* undo damage */ 139796a888c6Smillert return; 139896a888c6Smillert } 13994fb6ab7cSmillert strncpy(lp->d_packname, p, sizeof(lp->d_packname)); /* checked */ 14006fe57b42Smillert 14016fe57b42Smillert /* sectors/track */ 14026fe57b42Smillert for (;;) { 1403117239d3Skrw ui = getuint64(lp, "sectors/track", 1404cfd24250Skrw "The Number of sectors per track.", lp->d_nsectors, 14054b9a3bdaSmillert lp->d_nsectors, 0, 0); 14061e0ad43cSotto if (ui == ULLONG_MAX - 1) { 140796a888c6Smillert fputs("Command aborted\n", stderr); 140896a888c6Smillert *lp = oldlabel; /* undo damage */ 140996a888c6Smillert return; 14101e0ad43cSotto } if (ui == ULLONG_MAX) 14116fe57b42Smillert fputs("Invalid entry\n", stderr); 14126fe57b42Smillert else 14136fe57b42Smillert break; 14146fe57b42Smillert } 14156fe57b42Smillert lp->d_nsectors = ui; 14166fe57b42Smillert 14176fe57b42Smillert /* tracks/cylinder */ 14186fe57b42Smillert for (;;) { 1419117239d3Skrw ui = getuint64(lp, "tracks/cylinder", 14206fe57b42Smillert "The number of tracks per cylinder.", lp->d_ntracks, 14214b9a3bdaSmillert lp->d_ntracks, 0, 0); 14221e0ad43cSotto if (ui == ULLONG_MAX - 1) { 142396a888c6Smillert fputs("Command aborted\n", stderr); 142496a888c6Smillert *lp = oldlabel; /* undo damage */ 142596a888c6Smillert return; 14261e0ad43cSotto } else if (ui == ULLONG_MAX) 14276fe57b42Smillert fputs("Invalid entry\n", stderr); 14286fe57b42Smillert else 14296fe57b42Smillert break; 14306fe57b42Smillert } 14316fe57b42Smillert lp->d_ntracks = ui; 14326fe57b42Smillert 14336fe57b42Smillert /* sectors/cylinder */ 1434148b6188Smillert for (;;) { 1435117239d3Skrw ui = getuint64(lp, "sectors/cylinder", 1436148b6188Smillert "The number of sectors per cylinder (Usually sectors/track " 14374b9a3bdaSmillert "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl, 14384b9a3bdaSmillert 0, 0); 14391e0ad43cSotto if (ui == ULLONG_MAX - 1) { 144096a888c6Smillert fputs("Command aborted\n", stderr); 144196a888c6Smillert *lp = oldlabel; /* undo damage */ 144296a888c6Smillert return; 14431e0ad43cSotto } else if (ui == ULLONG_MAX) 1444148b6188Smillert fputs("Invalid entry\n", stderr); 1445148b6188Smillert else 1446148b6188Smillert break; 1447148b6188Smillert } 1448148b6188Smillert lp->d_secpercyl = ui; 14496fe57b42Smillert 14506fe57b42Smillert /* number of cylinders */ 14516fe57b42Smillert for (;;) { 1452117239d3Skrw ui = getuint64(lp, "number of cylinders", 14536fe57b42Smillert "The total number of cylinders on the disk.", 14544b9a3bdaSmillert lp->d_ncylinders, lp->d_ncylinders, 0, 0); 14551e0ad43cSotto if (ui == ULLONG_MAX - 1) { 145696a888c6Smillert fputs("Command aborted\n", stderr); 145796a888c6Smillert *lp = oldlabel; /* undo damage */ 145896a888c6Smillert return; 14591e0ad43cSotto } else if (ui == ULLONG_MAX) 14606fe57b42Smillert fputs("Invalid entry\n", stderr); 14616fe57b42Smillert else 14626fe57b42Smillert break; 14636fe57b42Smillert } 14646fe57b42Smillert lp->d_ncylinders = ui; 14656fe57b42Smillert 14666fe57b42Smillert /* total sectors */ 14676fe57b42Smillert for (;;) { 146834af67a3Sotto u_int64_t nsec = MAX(DL_GETDSIZE(lp), 146934af67a3Sotto (u_int64_t)lp->d_ncylinders * lp->d_secpercyl); 1470117239d3Skrw ui = getuint64(lp, "total sectors", 14716fe57b42Smillert "The total number of sectors on the disk.", 1472baaa8969Smillert nsec, nsec, 0, 0); 14731e0ad43cSotto if (ui == ULLONG_MAX - 1) { 147496a888c6Smillert fputs("Command aborted\n", stderr); 147596a888c6Smillert *lp = oldlabel; /* undo damage */ 147696a888c6Smillert return; 14771e0ad43cSotto } else if (ui == ULLONG_MAX) 14786fe57b42Smillert fputs("Invalid entry\n", stderr); 14791e0ad43cSotto else if (ui > DL_GETDSIZE(lp) && 14801e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 1481f98aebd4Smillert puts("You may want to increase the size of the 'c' " 1482f98aebd4Smillert "partition."); 14836fe57b42Smillert break; 14841e0ad43cSotto } else if (ui < DL_GETDSIZE(lp) && 14851e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 14866fe57b42Smillert /* shrink free count */ 14879fdcb4d6Skrw freesectors = editor_countfree(lp); 14889fdcb4d6Skrw if (DL_GETDSIZE(lp) - ui > freesectors) 14896fe57b42Smillert fprintf(stderr, 14901e0ad43cSotto "Not enough free space to shrink by %llu " 14911e0ad43cSotto "sectors (only %llu sectors left)\n", 14929fdcb4d6Skrw DL_GETDSIZE(lp) - ui, freesectors); 1493c4f83f03Skrw else 14946fe57b42Smillert break; 14956fe57b42Smillert } else 14966fe57b42Smillert break; 14976fe57b42Smillert } 149841ed49b7Smillert /* Adjust ending_sector if necessary. */ 149978f0fb17Skrw if (ending_sector > ui) { 150096a888c6Smillert ending_sector = ui; 150178f0fb17Skrw DL_SETBEND(lp, ending_sector); 150278f0fb17Skrw } 15031e0ad43cSotto DL_SETDSIZE(lp, ui); 15046fe57b42Smillert } 1505a7e61405Smillert 1506a7e61405Smillert struct partition ** 15070fbd3c97Skrw sort_partitions(struct disklabel *lp) 1508a7e61405Smillert { 1509d18c2a43Skrw static struct partition *spp[MAXPARTITIONS+2]; 15100fbd3c97Skrw int i, npartitions; 1511a7e61405Smillert 1512d18c2a43Skrw memset(spp, 0, sizeof(spp)); 1513d18c2a43Skrw 1514a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1515a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1516a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 15171e0ad43cSotto DL_GETPSIZE(&lp->d_partitions[i]) != 0) 1518a7e61405Smillert spp[npartitions++] = &lp->d_partitions[i]; 1519a7e61405Smillert } 1520a7e61405Smillert 1521a7e61405Smillert /* 1522a7e61405Smillert * Sort the partitions based on starting offset. 1523a7e61405Smillert * This is safe because we guarantee no overlap. 1524a7e61405Smillert */ 1525a7e61405Smillert if (npartitions > 1) 1526a7e61405Smillert if (heapsort((void *)spp, npartitions, sizeof(spp[0]), 1527a7e61405Smillert partition_cmp)) 1528a7e61405Smillert err(4, "failed to sort partition table"); 1529a7e61405Smillert 1530a7e61405Smillert return(spp); 1531a7e61405Smillert } 15320f820bbbSmillert 15330f820bbbSmillert /* 15340f820bbbSmillert * Get a valid disk type if necessary. 15350f820bbbSmillert */ 15360f820bbbSmillert void 15378809fabbSderaadt getdisktype(struct disklabel *lp, char *banner, char *dev) 15380f820bbbSmillert { 15390f820bbbSmillert int i; 1540803ff7d5Smillert char *s, *def = "SCSI"; 1541803ff7d5Smillert struct dtypes { 1542803ff7d5Smillert char *dev; 1543803ff7d5Smillert char *type; 1544803ff7d5Smillert } dtypes[] = { 1545c33fcabaSmillert { "sd", "SCSI" }, 1546c33fcabaSmillert { "rz", "SCSI" }, 1547c33fcabaSmillert { "wd", "IDE" }, 1548c33fcabaSmillert { "fd", "FLOPPY" }, 1549c33fcabaSmillert { "xd", "SMD" }, 1550c33fcabaSmillert { "xy", "SMD" }, 1551c33fcabaSmillert { "hd", "HP-IB" }, 1552d7878011Sderaadt { "ccd", "CCD" }, /* deprecated */ 1553c33fcabaSmillert { "vnd", "VND" }, 1554c33fcabaSmillert { "svnd", "VND" }, 1555c33fcabaSmillert { NULL, NULL } 1556803ff7d5Smillert }; 1557803ff7d5Smillert 1558803ff7d5Smillert if ((s = basename(dev)) != NULL) { 1559803ff7d5Smillert if (*s == 'r') 1560803ff7d5Smillert s++; 1561803ff7d5Smillert i = strcspn(s, "0123456789"); 1562803ff7d5Smillert s[i] = '\0'; 1563803ff7d5Smillert dev = s; 1564803ff7d5Smillert for (i = 0; dtypes[i].dev != NULL; i++) { 1565803ff7d5Smillert if (strcmp(dev, dtypes[i].dev) == 0) { 1566803ff7d5Smillert def = dtypes[i].type; 1567803ff7d5Smillert break; 1568803ff7d5Smillert } 1569803ff7d5Smillert } 1570803ff7d5Smillert } 15710f820bbbSmillert 15720f820bbbSmillert if (lp->d_type > DKMAXTYPES || lp->d_type == 0) { 15730f820bbbSmillert puts(banner); 15740f820bbbSmillert puts("Possible values are:"); 1575eb5dd924Sderaadt printf("\"IDE\", "); 15760f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15770f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15780f820bbbSmillert if (i < DKMAXTYPES - 1) 15790f820bbbSmillert fputs(", ", stdout); 15800f820bbbSmillert } 15810f820bbbSmillert putchar('\n'); 15820f820bbbSmillert 15830f820bbbSmillert for (;;) { 1584c33fcabaSmillert s = getstring("Disk type", 1585803ff7d5Smillert "What kind of disk is this? Usually SCSI, IDE, " 1586d7878011Sderaadt "ESDI, ST506, or floppy.", def); 158796a888c6Smillert if (s == NULL) 158896a888c6Smillert continue; 15895b412421Smillert if (strcasecmp(s, "IDE") == 0) { 15905b412421Smillert lp->d_type = DTYPE_ESDI; 15915b412421Smillert return; 15925b412421Smillert } 15930f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) 15940f820bbbSmillert if (strcasecmp(s, dktypenames[i]) == 0) { 15950f820bbbSmillert lp->d_type = i; 15960f820bbbSmillert return; 15970f820bbbSmillert } 15980f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", s); 15990f820bbbSmillert fputs("Valid types are: ", stdout); 16000f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 16010f820bbbSmillert printf("\"%s\"", dktypenames[i]); 16020f820bbbSmillert if (i < DKMAXTYPES - 1) 16030f820bbbSmillert fputs(", ", stdout); 16040f820bbbSmillert } 16050f820bbbSmillert putchar('\n'); 16060f820bbbSmillert } 16070f820bbbSmillert } 16080f820bbbSmillert } 160996a888c6Smillert 161096a888c6Smillert /* 161196a888c6Smillert * Get beginning and ending sectors of the OpenBSD portion of the disk 161296a888c6Smillert * from the user. 161396a888c6Smillert */ 161496a888c6Smillert void 16159fdcb4d6Skrw set_bounds(struct disklabel *lp) 161696a888c6Smillert { 16171e0ad43cSotto u_int64_t ui, start_temp; 161896a888c6Smillert 161996a888c6Smillert /* Starting sector */ 162096a888c6Smillert do { 1621117239d3Skrw ui = getuint64(lp, "Starting sector", 162296a888c6Smillert "The start of the OpenBSD portion of the disk.", 16231e0ad43cSotto starting_sector, DL_GETDSIZE(lp), 0, 0); 16241e0ad43cSotto if (ui == ULLONG_MAX - 1) { 162596a888c6Smillert fputs("Command aborted\n", stderr); 162696a888c6Smillert return; 162796a888c6Smillert } 16281e0ad43cSotto } while (ui >= DL_GETDSIZE(lp)); 162996a888c6Smillert start_temp = ui; 163096a888c6Smillert 16314793b14cSmillert /* Size */ 163296a888c6Smillert do { 1633117239d3Skrw ui = getuint64(lp, "Size ('*' for entire disk)", 1634f98aebd4Smillert "The size of the OpenBSD portion of the disk ('*' for the " 1635f98aebd4Smillert "entire disk).", ending_sector - starting_sector, 16361e0ad43cSotto DL_GETDSIZE(lp) - start_temp, 0, 0); 16371e0ad43cSotto if (ui == ULLONG_MAX - 1) { 163896a888c6Smillert fputs("Command aborted\n", stderr); 163996a888c6Smillert return; 164096a888c6Smillert } 16411e0ad43cSotto } while (ui > DL_GETDSIZE(lp) - start_temp); 16424793b14cSmillert ending_sector = start_temp + ui; 164378f0fb17Skrw DL_SETBEND(lp, ending_sector); 164496a888c6Smillert starting_sector = start_temp; 164578f0fb17Skrw DL_SETBSTART(lp, starting_sector); 164696a888c6Smillert } 164796a888c6Smillert 164896a888c6Smillert /* 16490d63cfbaSjsing * Allow user to interactively change disklabel UID. 16500d63cfbaSjsing */ 16510d63cfbaSjsing void 165269a6ffbcSjsing set_duid(struct disklabel *lp) 16530d63cfbaSjsing { 16540d63cfbaSjsing char *s; 16550d63cfbaSjsing int i; 16560d63cfbaSjsing 1657f6ad9e2dSjsing printf("The disklabel UID is currently: " 1658f6ad9e2dSjsing "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n", 1659f6ad9e2dSjsing lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3], 1660f6ad9e2dSjsing lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]); 16610d63cfbaSjsing 16620d63cfbaSjsing do { 166369a6ffbcSjsing s = getstring("duid", "The disklabel UID, given as a 16 " 16640d63cfbaSjsing "character hexadecimal string.", NULL); 1665ce98d1aeShalex if (s == NULL || strlen(s) == 0) { 16660d63cfbaSjsing fputs("Command aborted\n", stderr); 16670d63cfbaSjsing return; 16680d63cfbaSjsing } 166969a6ffbcSjsing i = duid_parse(lp, s); 16700d63cfbaSjsing if (i != 0) 16710d63cfbaSjsing fputs("Invalid UID entered.\n", stderr); 16720d63cfbaSjsing } while (i != 0); 16730d63cfbaSjsing } 16740d63cfbaSjsing 16750d63cfbaSjsing /* 167696a888c6Smillert * Return a list of the "chunks" of free space available 167796a888c6Smillert */ 167896a888c6Smillert struct diskchunk * 16798809fabbSderaadt free_chunks(struct disklabel *lp) 168096a888c6Smillert { 168196a888c6Smillert struct partition **spp; 168296a888c6Smillert static struct diskchunk chunks[MAXPARTITIONS + 2]; 168399bd27d2Skrw u_int64_t start, stop; 168496a888c6Smillert int i, numchunks; 168596a888c6Smillert 16860fbd3c97Skrw /* Sort the in-use partitions based on offset */ 16870fbd3c97Skrw spp = sort_partitions(lp); 168896a888c6Smillert 168996a888c6Smillert /* If there are no partitions, it's all free. */ 16900fbd3c97Skrw if (spp[0] == NULL) { 16912d8451b0Smillert chunks[0].start = starting_sector; 169296a888c6Smillert chunks[0].stop = ending_sector; 169396a888c6Smillert chunks[1].start = chunks[1].stop = 0; 169496a888c6Smillert return(chunks); 169596a888c6Smillert } 169696a888c6Smillert 169796a888c6Smillert /* Find chunks of free space */ 169896a888c6Smillert numchunks = 0; 16990fbd3c97Skrw if (DL_GETPOFFSET(spp[0]) > starting_sector) { 17002d8451b0Smillert chunks[0].start = starting_sector; 17011e0ad43cSotto chunks[0].stop = DL_GETPOFFSET(spp[0]); 170296a888c6Smillert numchunks++; 170396a888c6Smillert } 17040fbd3c97Skrw for (i = 0; spp[i] != NULL; i++) { 170599bd27d2Skrw start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]); 1706aff3f969Sotto if (start < starting_sector) 1707aff3f969Sotto start = starting_sector; 1708aff3f969Sotto else if (start > ending_sector) 1709aff3f969Sotto start = ending_sector; 171099bd27d2Skrw if (spp[i + 1] != NULL) 171199bd27d2Skrw stop = DL_GETPOFFSET(spp[i+1]); 171299bd27d2Skrw else 171399bd27d2Skrw stop = ending_sector; 1714aff3f969Sotto if (stop < starting_sector) 1715aff3f969Sotto stop = starting_sector; 1716aff3f969Sotto else if (stop > ending_sector) 1717aff3f969Sotto stop = ending_sector; 171899bd27d2Skrw if (start < stop) { 171999bd27d2Skrw chunks[numchunks].start = start; 172099bd27d2Skrw chunks[numchunks].stop = stop; 172196a888c6Smillert numchunks++; 172296a888c6Smillert } 172396a888c6Smillert } 172496a888c6Smillert 172596a888c6Smillert /* Terminate and return */ 172696a888c6Smillert chunks[numchunks].start = chunks[numchunks].stop = 0; 172796a888c6Smillert return(chunks); 172896a888c6Smillert } 17294793b14cSmillert 17304793b14cSmillert void 173187023ed9Skrw find_bounds(struct disklabel *lp) 17324793b14cSmillert { 17336534e983Sderaadt starting_sector = DL_GETBSTART(lp); 17346534e983Sderaadt ending_sector = DL_GETBEND(lp); 1735b2d4a455Smiod 17366534e983Sderaadt if (ending_sector) { 173734ae4198Skrw if (verbose) 173834ae4198Skrw printf("Treating sectors %llu-%llu as the OpenBSD" 173934ae4198Skrw " portion of the disk.\nYou can use the 'b'" 174034ae4198Skrw " command to change this.\n\n", starting_sector, 174134ae4198Skrw ending_sector); 1742b2d4a455Smiod } else { 174381b6e3e6Skrw #if NUMBOOT > 0 1744d3f02056Smillert /* Boot blocks take up the first cylinder */ 1745d3f02056Smillert starting_sector = lp->d_secpercyl; 174634ae4198Skrw if (verbose) 174734ae4198Skrw printf("Reserving the first data cylinder for boot" 174834ae4198Skrw " blocks.\nYou can use the 'b' command to change" 174934ae4198Skrw " this.\n\n"); 17504793b14cSmillert #endif 17514793b14cSmillert } 1752b2d4a455Smiod } 1753c0bdc608Smillert 1754c0bdc608Smillert /* 1755c0bdc608Smillert * Calculate free space. 1756c0bdc608Smillert */ 17579fdcb4d6Skrw u_int64_t 17589fdcb4d6Skrw editor_countfree(struct disklabel *lp) 1759c0bdc608Smillert { 1760d93cb2bbSkrw struct diskchunk *chunks; 17619fdcb4d6Skrw u_int64_t freesectors = 0; 1762c0bdc608Smillert int i; 1763c0bdc608Smillert 1764d93cb2bbSkrw chunks = free_chunks(lp); 1765509930fbSotto 1766d93cb2bbSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) 17679fdcb4d6Skrw freesectors += chunks[i].stop - chunks[i].start; 17689fdcb4d6Skrw 17699fdcb4d6Skrw return (freesectors); 1770c0bdc608Smillert } 1771617e6e4aSmillert 1772617e6e4aSmillert void 17734d812bb6Slum editor_help(void) 1774617e6e4aSmillert { 1775617e6e4aSmillert puts("Available commands:"); 1776617e6e4aSmillert puts( 17774d812bb6Slum " ? | h - show help n [part] - set mount point\n" 177849159a67Skrw " A - auto partition all space p [unit] - print partitions\n" 177949159a67Skrw " a [part] - add partition q - quit & save changes\n" 17804659aa0dSotto " b - set OpenBSD boundaries R [part] - resize auto allocated partition\n" 178149159a67Skrw " c [part] - change partition size r - display free space\n" 17826aaa4aabSotto " D - reset label to default s [path] - save label to file\n" 17836aaa4aabSotto " d [part] - delete partition U - undo all changes\n" 17846aaa4aabSotto " e - edit drive parameters u - undo last change\n" 17856aaa4aabSotto " g [d|u] - [d]isk or [u]ser geometry w - write label to disk\n" 17860d63cfbaSjsing " i - modify disklabel UID X - toggle expert mode\n" 17870d63cfbaSjsing " l [unit] - print disk label header x - exit & lose changes\n" 17880d63cfbaSjsing " M - disklabel(8) man page z - delete all partitions\n" 17890d63cfbaSjsing " m [part] - modify partition\n" 1790c4884206Skrw "\n" 1791c4884206Skrw "Suffixes can be used to indicate units other than sectors:\n" 1792e5f81948Sotto " 'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes) 't' (terabytes)\n" 1793e5f81948Sotto " 'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n" 1794c4884206Skrw "Values in non-sector units are truncated to the nearest cylinder boundary."); 17954d812bb6Slum 1796617e6e4aSmillert } 1797bd6726faSmillert 17984f3bbbf0Skrw void 17998809fabbSderaadt mpcopy(char **to, char **from) 1800bd6726faSmillert { 1801bd6726faSmillert int i; 1802bd6726faSmillert 1803bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1804bd6726faSmillert free(to[i]); 1805bd6726faSmillert to[i] = NULL; 1806408ab9bcSkrw if (from[i] != NULL) { 1807408ab9bcSkrw to[i] = strdup(from[i]); 1808408ab9bcSkrw if (to[i] == NULL) 1809408ab9bcSkrw errx(4, "out of memory"); 1810bd6726faSmillert } 1811bd6726faSmillert } 1812bd6726faSmillert } 1813bd6726faSmillert 1814bd6726faSmillert int 18158809fabbSderaadt mpequal(char **mp1, char **mp2) 1816bd6726faSmillert { 1817bd6726faSmillert int i; 1818bd6726faSmillert 1819bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1820bd6726faSmillert if (mp1[i] == NULL && mp2[i] == NULL) 1821bd6726faSmillert continue; 1822bd6726faSmillert 1823bd6726faSmillert if ((mp1[i] != NULL && mp2[i] == NULL) || 1824bd6726faSmillert (mp1[i] == NULL && mp2[i] != NULL) || 1825bd6726faSmillert (strcmp(mp1[i], mp2[i]) != 0)) 1826bd6726faSmillert return(0); 1827bd6726faSmillert } 1828bd6726faSmillert return(1); 1829bd6726faSmillert } 1830bd6726faSmillert 183193160b9bSkrw void 183234ae4198Skrw mpsave(struct disklabel *lp) 1833bd6726faSmillert { 1834d8b446ceSderaadt int i, j; 1835bd6726faSmillert char bdev[MAXPATHLEN], *p; 18363f843443Smillert struct mountinfo mi[MAXPARTITIONS]; 1837bd6726faSmillert FILE *fp; 1838fe01da94Skrw u_int8_t fstype; 1839bd6726faSmillert 184093160b9bSkrw if (!fstabfile) 184193160b9bSkrw return; 184293160b9bSkrw 18433f843443Smillert memset(&mi, 0, sizeof(mi)); 18443f843443Smillert 1845d8b446ceSderaadt for (i = 0; i < MAXPARTITIONS; i++) { 1846fe01da94Skrw fstype = lp->d_partitions[i].p_fstype; 1847fe01da94Skrw if (mountpoints[i] != NULL || fstype == FS_SWAP) { 184834ae4198Skrw mi[i].mountpoint = mountpoints[i]; 18493f843443Smillert mi[i].partno = i; 1850bd6726faSmillert } 1851bd6726faSmillert } 1852bd6726faSmillert 185334ae4198Skrw /* Convert specname to bdev */ 1854d6d80bb0Skrw if (uidflag) { 1855d6d80bb0Skrw snprintf(bdev, sizeof(bdev), 1856d6d80bb0Skrw "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 1857d6d80bb0Skrw lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3], 1858d6d80bb0Skrw lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7], 1859d6d80bb0Skrw specname[strlen(specname)-1]); 1860d6d80bb0Skrw } else if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 && 186134ae4198Skrw specname[sizeof(_PATH_DEV) - 1] == 'r') { 1862bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV, 186334ae4198Skrw &specname[sizeof(_PATH_DEV)]); 1864bd6726faSmillert } else { 186534ae4198Skrw if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r') 186693160b9bSkrw return; 1867bd6726faSmillert *p = '\0'; 186834ae4198Skrw snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1); 1869bd6726faSmillert *p = 'r'; 1870bd6726faSmillert } 1871bd6726faSmillert bdev[strlen(bdev) - 1] = '\0'; 1872bd6726faSmillert 18733f843443Smillert /* Sort mountpoints so we don't try to mount /usr/local before /usr */ 18743f843443Smillert qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp); 18753f843443Smillert 1876d71533c9Stedu if ((fp = fopen(fstabfile, "w"))) { 1877fe01da94Skrw for (i = 0; i < MAXPARTITIONS; i++) { 18785fea0b85Smillert j = mi[i].partno; 1879fe01da94Skrw fstype = lp->d_partitions[j].p_fstype; 1880fe01da94Skrw if (fstype == FS_SWAP) { 1881fe01da94Skrw fprintf(fp, "%s%c none swap sw\n", bdev, 'a'+j); 1882fe01da94Skrw } else if (mi[i].mountpoint) { 1883fe01da94Skrw fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 1884fe01da94Skrw 'a' + j, mi[i].mountpoint, 1885fe01da94Skrw fstypesnames[fstype], j == 0 ? 1 : 2); 1886fe01da94Skrw } 1887bd6726faSmillert } 1888bd6726faSmillert fclose(fp); 188993160b9bSkrw } 1890bd6726faSmillert } 189124a2c1a4Smillert 1892408ab9bcSkrw void 1893408ab9bcSkrw mpfree(char **mp) 1894408ab9bcSkrw { 1895408ab9bcSkrw int part; 1896408ab9bcSkrw 1897408ab9bcSkrw if (mp == NULL) 1898408ab9bcSkrw return; 1899408ab9bcSkrw 190075691760Skrw for (part = 0; part < MAXPARTITIONS; part++) 1901408ab9bcSkrw free(mp[part]); 1902408ab9bcSkrw 1903408ab9bcSkrw free(mp); 1904408ab9bcSkrw } 1905408ab9bcSkrw 190624a2c1a4Smillert int 1907604d3bdeSkrw get_offset(struct disklabel *lp, int partno) 190824a2c1a4Smillert { 1909604d3bdeSkrw struct diskchunk *chunks; 191024a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 191115c15d8aSkrw u_int64_t ui, maxsize; 1912604d3bdeSkrw int i, fstype; 191324a2c1a4Smillert 1914117239d3Skrw ui = getuint64(lp, "offset", 19151e0ad43cSotto "Starting sector for this partition.", 19161e0ad43cSotto DL_GETPOFFSET(pp), 19171e0ad43cSotto DL_GETPOFFSET(pp), 0, DO_CONVERSIONS | 191824a2c1a4Smillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 1919e9ff19beSkrw 1920e9ff19beSkrw if (ui == ULLONG_MAX - 1) 192124a2c1a4Smillert fputs("Command aborted\n", stderr); 1922e9ff19beSkrw else if (ui == ULLONG_MAX) 192324a2c1a4Smillert fputs("Invalid entry\n", stderr); 192440e98e9fSkrw else if (ui < starting_sector || ui >= ending_sector) 1925e9ff19beSkrw fprintf(stderr, "The offset must be >= %llu and < %llu, " 1926e9ff19beSkrw "the limits of the OpenBSD portion\n" 1927e9ff19beSkrw "of the disk. The 'b' command can change these limits.\n", 192840e98e9fSkrw starting_sector, ending_sector); 1929fc1a4cc6Sderaadt #ifdef SUN_AAT0 193049bf537cSderaadt else if (partno == 0 && ui != 0) 193149bf537cSderaadt fprintf(stderr, "This architecture requires that " 193240f544cdSderaadt "partition 'a' start at sector 0.\n"); 193349bf537cSderaadt #endif 193415c15d8aSkrw else { 1935604d3bdeSkrw fstype = pp->p_fstype; 1936604d3bdeSkrw pp->p_fstype = FS_UNUSED; 1937604d3bdeSkrw chunks = free_chunks(lp); 1938604d3bdeSkrw pp->p_fstype = fstype; 1939e9ff19beSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 1940e9ff19beSkrw if (ui < chunks[i].start || ui >= chunks[i].stop) 194115c15d8aSkrw continue; 19421e0ad43cSotto DL_SETPOFFSET(pp, ui); 194315c15d8aSkrw maxsize = chunks[i].stop - DL_GETPOFFSET(pp); 194415c15d8aSkrw if (DL_GETPSIZE(pp) > maxsize) 194515c15d8aSkrw DL_SETPSIZE(pp, maxsize); 194624a2c1a4Smillert return (0); 194724a2c1a4Smillert } 194815c15d8aSkrw fputs("The offset must be in a free area.\n", stderr); 194915c15d8aSkrw } 1950e9ff19beSkrw 1951e9ff19beSkrw /* Partition offset was not set. */ 1952e9ff19beSkrw return (1); 195315c15d8aSkrw } 195424a2c1a4Smillert 195524a2c1a4Smillert int 19569fdcb4d6Skrw get_size(struct disklabel *lp, int partno) 195724a2c1a4Smillert { 195824a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 195914192793Skrw u_int64_t maxsize, ui; 196014192793Skrw 196114192793Skrw maxsize = max_partition_size(lp, partno); 196224a2c1a4Smillert 1963117239d3Skrw ui = getuint64(lp, "size", "Size of the partition. " 19647da73705Skrw "You may also say +/- amount for a relative change.", 196514192793Skrw DL_GETPSIZE(pp), maxsize, DL_GETPOFFSET(pp), 1966525051f1Sotto DO_CONVERSIONS | ((pp->p_fstype == FS_BSDFFS || 1967525051f1Sotto pp->p_fstype == FS_SWAP) ? DO_ROUNDING : 0)); 1968e9ff19beSkrw 1969e9ff19beSkrw if (ui == ULLONG_MAX - 1) 197024a2c1a4Smillert fputs("Command aborted\n", stderr); 1971e9ff19beSkrw else if (ui == ULLONG_MAX) 197224a2c1a4Smillert fputs("Invalid entry\n", stderr); 197328e3704eSkrw else if (ui == 0) 19743f74e3efSkrw fputs("The size must be > 0 sectors\n", stderr); 197540e98e9fSkrw else if (ui + DL_GETPOFFSET(pp) > ending_sector) 197640e98e9fSkrw fprintf(stderr, "The size can't be more than " 197740e98e9fSkrw "%llu sectors, or the partition would\n" 197840e98e9fSkrw "extend beyond the last sector (%llu) of the " 197940e98e9fSkrw "OpenBSD portion of\nthe disk. " 198040e98e9fSkrw "The 'b' command can change this limit.\n", 198140e98e9fSkrw ending_sector - DL_GETPOFFSET(pp), ending_sector); 198214192793Skrw else if (ui > maxsize) 198314192793Skrw fprintf(stderr,"Sorry, there are only %llu sectors left\n", 198414192793Skrw maxsize); 198559ccf790Skrw else { 198659ccf790Skrw DL_SETPSIZE(pp, ui); 198724a2c1a4Smillert return (0); 198824a2c1a4Smillert } 1989e9ff19beSkrw 1990e9ff19beSkrw /* Partition size was not set. */ 1991e9ff19beSkrw return (1); 1992e9ff19beSkrw } 199324a2c1a4Smillert 199424a2c1a4Smillert int 19958809fabbSderaadt get_fsize(struct disklabel *lp, int partno) 199624a2c1a4Smillert { 19971e0ad43cSotto u_int64_t ui, fsize, frag; 199824a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 199924a2c1a4Smillert 2000a4c87e64Skrw if (!expert || pp->p_fstype != FS_BSDFFS) 2001a4c87e64Skrw return (0); 2002a4c87e64Skrw 2003ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 2004ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 2005ddfcbf38Sotto if (fsize == 0) 2006ddfcbf38Sotto frag = 8; 2007ddfcbf38Sotto 200824a2c1a4Smillert for (;;) { 2009117239d3Skrw ui = getuint64(lp, "fragment size", 2010c782b064Skrw "Size of ffs block fragments. A multiple of the disk " 2011c782b064Skrw "sector-size.", fsize, ULLONG_MAX-2, 0, 0); 20121e0ad43cSotto if (ui == ULLONG_MAX - 1) { 201324a2c1a4Smillert fputs("Command aborted\n", stderr); 201424a2c1a4Smillert return (1); 2015c782b064Skrw } else if (ui == ULLONG_MAX) { 201624a2c1a4Smillert fputs("Invalid entry\n", stderr); 2017c782b064Skrw } else if (ui < lp->d_secsize || (ui % lp->d_secsize) != 0) { 2018c782b064Skrw fprintf(stderr, "Error: fragment size must be a " 2019c782b064Skrw "multiple of the disk sector size (%d)\n", 2020c782b064Skrw lp->d_secsize); 2021c782b064Skrw } else 202224a2c1a4Smillert break; 202324a2c1a4Smillert } 202424a2c1a4Smillert if (ui == 0) 202524a2c1a4Smillert puts("Zero fragment size implies zero block size"); 2026ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag); 202724a2c1a4Smillert return(0); 202824a2c1a4Smillert } 202924a2c1a4Smillert 203024a2c1a4Smillert int 20318809fabbSderaadt get_bsize(struct disklabel *lp, int partno) 203224a2c1a4Smillert { 20336be94867Skrw u_int64_t adj, ui, bsize, frag, fsize, orig_offset, orig_size; 203424a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 20356be94867Skrw char *p; 203624a2c1a4Smillert 2037a49bdda8Skrw if (pp->p_fstype != FS_BSDFFS) 2038a4c87e64Skrw return (0); 2039a4c87e64Skrw 204024a2c1a4Smillert /* Avoid dividing by zero... */ 2041ddfcbf38Sotto if (pp->p_fragblock == 0) 204224a2c1a4Smillert return(1); 2043ddfcbf38Sotto 2044a49bdda8Skrw if (!expert) 2045a49bdda8Skrw goto align; 2046a49bdda8Skrw 2047ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 2048ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 204924a2c1a4Smillert 205024a2c1a4Smillert for (;;) { 2051117239d3Skrw ui = getuint64(lp, "block size", 20520cf7e76dSotto "Size of ffs blocks. 1, 2, 4 or 8 times ffs fragment size.", 2053c782b064Skrw fsize * frag, ULLONG_MAX - 2, 0, 0); 205424a2c1a4Smillert 205524a2c1a4Smillert /* sanity checks */ 20561e0ad43cSotto if (ui == ULLONG_MAX - 1) { 205724a2c1a4Smillert fputs("Command aborted\n", stderr); 205824a2c1a4Smillert return(1); 20591e0ad43cSotto } else if (ui == ULLONG_MAX) 206024a2c1a4Smillert fputs("Invalid entry\n", stderr); 206124a2c1a4Smillert else if (ui < getpagesize()) 206224a2c1a4Smillert fprintf(stderr, 206324a2c1a4Smillert "Error: block size must be at least as big " 206424a2c1a4Smillert "as page size (%d).\n", getpagesize()); 20650cf7e76dSotto else if (ui < fsize || (fsize != ui && fsize * 2 != ui && 20660cf7e76dSotto fsize * 4 != ui && fsize * 8 != ui)) 20670cf7e76dSotto fprintf(stderr, "Error: block size must be 1, 2, 4 or " 20680cf7e76dSotto "8 times fragment size (%llu).\n", 20692777acfaSchl (unsigned long long) fsize); 207024a2c1a4Smillert else 207124a2c1a4Smillert break; 207224a2c1a4Smillert } 20730cf7e76dSotto frag = ui / fsize; 20740cf7e76dSotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, frag); 2075a49bdda8Skrw 2076a49bdda8Skrw #ifndef SUN_CYLCHECK 20776be94867Skrw p = getstring("Align partition to block size", 20786be94867Skrw "Round the partition offset and size to multiples of bsize?", "y"); 20796be94867Skrw 20806be94867Skrw if (*p == 'n' || *p == 'N') 20816be94867Skrw return (0); 20826be94867Skrw #endif 20836be94867Skrw 20846be94867Skrw align: 20856be94867Skrw 20866be94867Skrw #ifndef SUN_CYLCHECK 20876be94867Skrw orig_size = DL_GETPSIZE(pp); 20886be94867Skrw orig_offset = DL_GETPOFFSET(pp); 20896be94867Skrw 2090a49bdda8Skrw bsize = (DISKLABELV1_FFS_FRAG(pp->p_fragblock) * 2091a49bdda8Skrw DISKLABELV1_FFS_FSIZE(pp->p_fragblock)) / lp->d_secsize; 2092a49bdda8Skrw if (DL_GETPOFFSET(pp) != starting_sector) { 2093a49bdda8Skrw /* Can't change offset of first partition. */ 2094a49bdda8Skrw adj = bsize - (DL_GETPOFFSET(pp) % bsize); 2095a49bdda8Skrw if (adj != 0 && adj != bsize) { 2096a49bdda8Skrw DL_SETPOFFSET(pp, DL_GETPOFFSET(pp) + adj); 2097a49bdda8Skrw DL_SETPSIZE(pp, DL_GETPSIZE(pp) - adj); 2098a49bdda8Skrw } 2099a49bdda8Skrw } 2100a49bdda8Skrw /* Always align end. */ 2101a49bdda8Skrw adj = (DL_GETPOFFSET(pp) + DL_GETPSIZE(pp)) % bsize; 2102a49bdda8Skrw if (adj > 0) 2103a49bdda8Skrw DL_SETPSIZE(pp, DL_GETPSIZE(pp) - adj); 21046be94867Skrw 2105ef5288d7Skrw if (orig_offset != DL_GETPOFFSET(pp) && !aflag) 21066be94867Skrw printf("Rounding offset to bsize (%llu sectors): %llu\n", 21076be94867Skrw bsize, DL_GETPOFFSET(pp)); 2108ef5288d7Skrw if (orig_size != DL_GETPSIZE(pp) && !aflag) 21096be94867Skrw printf("Rounding size to bsize (%llu sectors): %llu\n", 21106be94867Skrw bsize, DL_GETPSIZE(pp)); 2111a49bdda8Skrw #endif 211224a2c1a4Smillert return(0); 211324a2c1a4Smillert } 211424a2c1a4Smillert 211524a2c1a4Smillert int 21168809fabbSderaadt get_fstype(struct disklabel *lp, int partno) 211724a2c1a4Smillert { 211824a2c1a4Smillert char *p; 21191e0ad43cSotto u_int64_t ui; 212024a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 212124a2c1a4Smillert 212224a2c1a4Smillert if (pp->p_fstype < FSMAXTYPES) { 2123c33fcabaSmillert p = getstring("FS type", 212424a2c1a4Smillert "Filesystem type (usually 4.2BSD or swap)", 212524a2c1a4Smillert fstypenames[pp->p_fstype]); 212624a2c1a4Smillert if (p == NULL) { 212724a2c1a4Smillert fputs("Command aborted\n", stderr); 212824a2c1a4Smillert return(1); 212924a2c1a4Smillert } 213024a2c1a4Smillert for (ui = 0; ui < FSMAXTYPES; ui++) { 213124a2c1a4Smillert if (!strcasecmp(p, fstypenames[ui])) { 213224a2c1a4Smillert pp->p_fstype = ui; 213324a2c1a4Smillert break; 213424a2c1a4Smillert } 213524a2c1a4Smillert } 213624a2c1a4Smillert if (ui >= FSMAXTYPES) { 2137430e1380Skrw printf("Unrecognized filesystem type '%s', treating " 2138430e1380Skrw "as 'unknown'\n", p); 213924a2c1a4Smillert pp->p_fstype = FS_OTHER; 214024a2c1a4Smillert } 214124a2c1a4Smillert } else { 214224a2c1a4Smillert for (;;) { 2143117239d3Skrw ui = getuint64(lp, "FS type (decimal)", 2144430e1380Skrw "Filesystem type as a decimal number; usually 7 " 2145430e1380Skrw "(4.2BSD) or 1 (swap).", 214624a2c1a4Smillert pp->p_fstype, pp->p_fstype, 0, 0); 21471e0ad43cSotto if (ui == ULLONG_MAX - 1) { 214824a2c1a4Smillert fputs("Command aborted\n", stderr); 214924a2c1a4Smillert return(1); 21501e0ad43cSotto } if (ui == ULLONG_MAX) 215124a2c1a4Smillert fputs("Invalid entry\n", stderr); 215224a2c1a4Smillert else 215324a2c1a4Smillert break; 215424a2c1a4Smillert } 215524a2c1a4Smillert pp->p_fstype = ui; 215624a2c1a4Smillert } 215724a2c1a4Smillert return(0); 215824a2c1a4Smillert } 215924a2c1a4Smillert 216024a2c1a4Smillert int 216134ae4198Skrw get_mp(struct disklabel *lp, int partno) 216224a2c1a4Smillert { 216324a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 2164ec9fde5fSkrw char *p; 2165ec9fde5fSkrw int i; 216624a2c1a4Smillert 216734ae4198Skrw if (fstabfile && pp->p_fstype != FS_UNUSED && 216824a2c1a4Smillert pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT && 216924a2c1a4Smillert pp->p_fstype != FS_OTHER) { 2170ddaff619Smillert for (;;) { 2171c33fcabaSmillert p = getstring("mount point", 217224a2c1a4Smillert "Where to mount this filesystem (ie: / /var /usr)", 217334ae4198Skrw mountpoints[partno] ? mountpoints[partno] : "none"); 217424a2c1a4Smillert if (p == NULL) { 217524a2c1a4Smillert fputs("Command aborted\n", stderr); 217624a2c1a4Smillert return(1); 217724a2c1a4Smillert } 2178ddaff619Smillert if (strcasecmp(p, "none") == 0) { 217934ae4198Skrw free(mountpoints[partno]); 218034ae4198Skrw mountpoints[partno] = NULL; 2181ddaff619Smillert break; 2182ddaff619Smillert } 2183ec9fde5fSkrw for (i = 0; i < MAXPARTITIONS; i++) 218493160b9bSkrw if (mountpoints[i] != NULL && i != partno && 2185ec9fde5fSkrw strcmp(p, mountpoints[i]) == 0) 2186ec9fde5fSkrw break; 2187ec9fde5fSkrw if (i < MAXPARTITIONS) { 218893160b9bSkrw fprintf(stderr, "'%c' already being mounted at " 218993160b9bSkrw "'%s'\n", 'a'+i, p); 2190ec9fde5fSkrw break; 2191ec9fde5fSkrw } 2192ddaff619Smillert if (*p == '/') { 2193ddaff619Smillert /* XXX - might as well realloc */ 219434ae4198Skrw free(mountpoints[partno]); 219534ae4198Skrw if ((mountpoints[partno] = strdup(p)) == NULL) 219624a2c1a4Smillert errx(4, "out of memory"); 2197ddaff619Smillert break; 2198ddaff619Smillert } 2199ddaff619Smillert fputs("Mount points must start with '/'\n", stderr); 220024a2c1a4Smillert } 220124a2c1a4Smillert } 220224a2c1a4Smillert return(0); 220324a2c1a4Smillert } 22043f843443Smillert 22053f843443Smillert int 22068809fabbSderaadt micmp(const void *a1, const void *a2) 22073f843443Smillert { 22083f843443Smillert struct mountinfo *mi1 = (struct mountinfo *)a1; 22093f843443Smillert struct mountinfo *mi2 = (struct mountinfo *)a2; 22103f843443Smillert 22113f843443Smillert /* We want all the NULLs at the end... */ 22123f843443Smillert if (mi1->mountpoint == NULL && mi2->mountpoint == NULL) 22133f843443Smillert return(0); 22143f843443Smillert else if (mi1->mountpoint == NULL) 22153f843443Smillert return(1); 22163f843443Smillert else if (mi2->mountpoint == NULL) 22173f843443Smillert return(-1); 22183f843443Smillert else 22193f843443Smillert return(strcmp(mi1->mountpoint, mi2->mountpoint)); 22203f843443Smillert } 2221c33fcabaSmillert 2222c33fcabaSmillert void 222387023ed9Skrw get_geometry(int f, struct disklabel **dgpp) 2224c33fcabaSmillert { 2225c33fcabaSmillert struct stat st; 2226c33fcabaSmillert struct disklabel *disk_geop; 222787023ed9Skrw 2228c33fcabaSmillert if (fstat(f, &st) == -1) 2229c33fcabaSmillert err(4, "Can't stat device"); 2230c33fcabaSmillert 2231c33fcabaSmillert /* Get disk geometry */ 2232c33fcabaSmillert if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL) 2233c33fcabaSmillert errx(4, "out of memory"); 22349a379a6cSkrw if (ioctl(f, DIOCGPDINFO, disk_geop) < 0) 22359a379a6cSkrw err(4, "ioctl DIOCGPDINFO"); 2236c33fcabaSmillert *dgpp = disk_geop; 2237c33fcabaSmillert } 2238c33fcabaSmillert 2239c33fcabaSmillert void 22408809fabbSderaadt set_geometry(struct disklabel *lp, struct disklabel *dgp, 224187023ed9Skrw struct disklabel *ugp, char *p) 2242c33fcabaSmillert { 2243c33fcabaSmillert if (p == NULL) { 22449a36aa41Ssthen p = getstring("[d]isk or [u]ser geometry", 2245c33fcabaSmillert "Enter 'd' to use the geometry based on what the disk " 22469a36aa41Ssthen "itself thinks it is, or 'u' to use the geometry that " 22479a36aa41Ssthen "was found in the label.", 2248c33fcabaSmillert "d"); 2249c33fcabaSmillert } 2250c33fcabaSmillert if (p == NULL) { 2251c33fcabaSmillert fputs("Command aborted\n", stderr); 2252c33fcabaSmillert return; 2253c33fcabaSmillert } 2254c33fcabaSmillert switch (*p) { 2255c33fcabaSmillert case 'd': 2256c33fcabaSmillert case 'D': 2257c33fcabaSmillert if (dgp == NULL) 2258c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2259c33fcabaSmillert else { 2260c33fcabaSmillert lp->d_secsize = dgp->d_secsize; 2261c33fcabaSmillert lp->d_nsectors = dgp->d_nsectors; 2262c33fcabaSmillert lp->d_ntracks = dgp->d_ntracks; 2263c33fcabaSmillert lp->d_ncylinders = dgp->d_ncylinders; 2264c33fcabaSmillert lp->d_secpercyl = dgp->d_secpercyl; 226534af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(dgp)); 2266c33fcabaSmillert } 2267c33fcabaSmillert break; 2268c33fcabaSmillert case 'u': 2269c33fcabaSmillert case 'U': 2270c33fcabaSmillert if (ugp == NULL) 2271c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2272c33fcabaSmillert else { 2273c33fcabaSmillert lp->d_secsize = ugp->d_secsize; 2274c33fcabaSmillert lp->d_nsectors = ugp->d_nsectors; 2275c33fcabaSmillert lp->d_ntracks = ugp->d_ntracks; 2276c33fcabaSmillert lp->d_ncylinders = ugp->d_ncylinders; 2277c33fcabaSmillert lp->d_secpercyl = ugp->d_secpercyl; 227834af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(ugp)); 2279c33fcabaSmillert if (dgp != NULL && ugp->d_secsize == dgp->d_secsize && 2280c33fcabaSmillert ugp->d_nsectors == dgp->d_nsectors && 2281c33fcabaSmillert ugp->d_ntracks == dgp->d_ntracks && 2282c33fcabaSmillert ugp->d_ncylinders == dgp->d_ncylinders && 2283c33fcabaSmillert ugp->d_secpercyl == dgp->d_secpercyl && 228434af67a3Sotto DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp)) 2285c33fcabaSmillert fputs("Note: user geometry is the same as disk " 2286c33fcabaSmillert "geometry.\n", stderr); 2287c33fcabaSmillert } 2288c33fcabaSmillert break; 2289c33fcabaSmillert default: 22909a36aa41Ssthen fputs("You must enter either 'd' or 'u'.\n", stderr); 2291c33fcabaSmillert break; 2292c33fcabaSmillert } 2293c33fcabaSmillert } 22949afbe9eeSmillert 22959afbe9eeSmillert void 22969fdcb4d6Skrw zero_partitions(struct disklabel *lp) 22979afbe9eeSmillert { 22989afbe9eeSmillert int i; 22999afbe9eeSmillert 2300b4ed6301Skrw for (i = 0; i < MAXPARTITIONS; i++) { 23019afbe9eeSmillert memset(&lp->d_partitions[i], 0, sizeof(struct partition)); 2302b4ed6301Skrw free(mountpoints[i]); 2303b4ed6301Skrw mountpoints[i] = NULL; 2304b4ed6301Skrw } 2305b4ed6301Skrw 230634af67a3Sotto DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); 23079afbe9eeSmillert } 230814192793Skrw 230914192793Skrw u_int64_t 231014192793Skrw max_partition_size(struct disklabel *lp, int partno) 231114192793Skrw { 231214192793Skrw struct partition *pp = &lp->d_partitions[partno]; 231314192793Skrw struct diskchunk *chunks; 231444ffe03bSotto u_int64_t maxsize = 0, offset; 231514192793Skrw int fstype, i; 231614192793Skrw 231714192793Skrw fstype = pp->p_fstype; 231814192793Skrw pp->p_fstype = FS_UNUSED; 231914192793Skrw chunks = free_chunks(lp); 232014192793Skrw pp->p_fstype = fstype; 232114192793Skrw 232214192793Skrw offset = DL_GETPOFFSET(pp); 232314192793Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 232414192793Skrw if (offset < chunks[i].start || offset >= chunks[i].stop) 232514192793Skrw continue; 232614192793Skrw maxsize = chunks[i].stop - offset; 232714192793Skrw break; 232814192793Skrw } 232914192793Skrw return (maxsize); 233014192793Skrw } 2331aff3f969Sotto 2332aff3f969Sotto void 2333eafadddfSkrw psize(u_int64_t sz, char unit, struct disklabel *lp) 2334aff3f969Sotto { 2335aff3f969Sotto double d = scale(sz, unit, lp); 2336aff3f969Sotto if (d < 0) 2337aff3f969Sotto printf("%llu", sz); 2338aff3f969Sotto else 2339aff3f969Sotto printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit); 2340aff3f969Sotto } 2341aff3f969Sotto 2342aff3f969Sotto void 234334ae4198Skrw display_edit(struct disklabel *lp, char unit, u_int64_t fr) 2344aff3f969Sotto { 2345aff3f969Sotto int i; 2346aff3f969Sotto 2347352d199bSkrw unit = canonical_unit(lp, unit); 2348aff3f969Sotto 2349aff3f969Sotto printf("OpenBSD area: "); 235059882f1dSkrw psize(starting_sector, 0, lp); 2351aff3f969Sotto printf("-"); 235259882f1dSkrw psize(ending_sector, 0, lp); 2353aff3f969Sotto printf("; size: "); 2354aff3f969Sotto psize(ending_sector - starting_sector, unit, lp); 2355aff3f969Sotto printf("; free: "); 2356aff3f969Sotto psize(fr, unit, lp); 2357aff3f969Sotto 2358aff3f969Sotto printf("\n# %16.16s %16.16s fstype [fsize bsize cpg]\n", 2359aff3f969Sotto "size", "offset"); 2360aff3f969Sotto for (i = 0; i < lp->d_npartitions; i++) 236134ae4198Skrw display_partition(stdout, lp, i, unit); 2362aff3f969Sotto } 2363