1*a49bdda8Skrw /* $OpenBSD: editor.c,v 1.241 2010/07/27 00:49:42 krw 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 426fe57b42Smillert /* flags for getuint() */ 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 { 655f3e1104Skrw daddr64_t minsz; /* starts as blocks, xlated to sectors. */ 665f3e1104Skrw daddr64_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, "/" }, 748dde8bb6Sotto { MEG(80), MEG(256), 5, "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" }, 8092adb55fSderaadt { GIG(1), GIG(2), 3, "/usr/src" }, 8192adb55fSderaadt { GIG(1), GIG(2), 3, "/usr/obj" }, 826e1f4775Sotto { GIG(1), GIG(300), 45, "/home" } 834ab111d2Sderaadt /* Anything beyond this leave for the user to decide */ 848dde8bb6Sotto }; 858dde8bb6Sotto 868dde8bb6Sotto const struct space_allocation alloc_medium[] = { 87905e8239Sderaadt { MEG(800), GIG(2), 5, "/" }, 888dde8bb6Sotto { MEG(80), MEG(256), 10, "swap" }, 89905e8239Sderaadt { MEG(900), GIG(3), 78, "/usr" }, 90905e8239Sderaadt { MEG(256), GIG(2), 7, "/home" } 918dde8bb6Sotto }; 928dde8bb6Sotto 938dde8bb6Sotto const struct space_allocation alloc_small[] = { 9492adb55fSderaadt { MEG(700), GIG(4), 95, "/" }, 958dde8bb6Sotto { MEG(1), MEG(256), 5, "swap" } 968dde8bb6Sotto }; 978dde8bb6Sotto 988dde8bb6Sotto const struct space_allocation alloc_stupid[] = { 998dde8bb6Sotto { MEG(1), MEG(2048), 100, "/" } 1008dde8bb6Sotto }; 1018dde8bb6Sotto 102b2813ff1Sderaadt #ifndef nitems 103b2813ff1Sderaadt #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 104b2813ff1Sderaadt #endif 105b2813ff1Sderaadt 1068a862940Sderaadt const struct { 1078a862940Sderaadt const struct space_allocation *table; 1088a862940Sderaadt int sz; 1098a862940Sderaadt } alloc_table[] = { 1108dde8bb6Sotto { alloc_big, nitems(alloc_big) }, 1118dde8bb6Sotto { alloc_medium, nitems(alloc_medium) }, 1128dde8bb6Sotto { alloc_small, nitems(alloc_small) }, 1138dde8bb6Sotto { alloc_stupid, nitems(alloc_stupid) } 114557f712bSkrw }; 115557f712bSkrw 1169fdcb4d6Skrw void edit_parms(struct disklabel *); 1176aaa4aabSotto void editor_resize(struct disklabel *, char *); 11834ae4198Skrw void editor_add(struct disklabel *, char *); 1199fdcb4d6Skrw void editor_change(struct disklabel *, char *); 1209fdcb4d6Skrw u_int64_t editor_countfree(struct disklabel *); 12134ae4198Skrw void editor_delete(struct disklabel *, char *); 1224d812bb6Slum void editor_help(void); 12334ae4198Skrw void editor_modify(struct disklabel *, char *); 12434ae4198Skrw void editor_name(struct disklabel *, char *); 125c72b5b24Smillert char *getstring(char *, char *, char *); 126dea75673Skrw u_int64_t getuint(struct disklabel *, char *, char *, u_int64_t, u_int64_t, u_int64_t, int); 1271f0f871dSkrw int has_overlap(struct disklabel *); 128c72b5b24Smillert int partition_cmp(const void *, const void *); 1290fbd3c97Skrw struct partition **sort_partitions(struct disklabel *); 130c72b5b24Smillert void getdisktype(struct disklabel *, char *, char *); 13187023ed9Skrw void find_bounds(struct disklabel *); 1329fdcb4d6Skrw void set_bounds(struct disklabel *); 1330d63cfbaSjsing void set_uid(struct disklabel *); 134c72b5b24Smillert struct diskchunk *free_chunks(struct disklabel *); 1354f3bbbf0Skrw void mpcopy(char **, char **); 136c72b5b24Smillert int micmp(const void *, const void *); 137c72b5b24Smillert int mpequal(char **, char **); 138c72b5b24Smillert int get_bsize(struct disklabel *, int); 139c72b5b24Smillert int get_fsize(struct disklabel *, int); 140c72b5b24Smillert int get_fstype(struct disklabel *, int); 14134ae4198Skrw int get_mp(struct disklabel *, int); 142604d3bdeSkrw int get_offset(struct disklabel *, int); 1439fdcb4d6Skrw int get_size(struct disklabel *, int); 14487023ed9Skrw void get_geometry(int, struct disklabel **); 14587023ed9Skrw void set_geometry(struct disklabel *, struct disklabel *, struct disklabel *, 14687023ed9Skrw char *); 1479fdcb4d6Skrw void zero_partitions(struct disklabel *); 14814192793Skrw u_int64_t max_partition_size(struct disklabel *, int); 14934ae4198Skrw void display_edit(struct disklabel *, char, u_int64_t); 15096a888c6Smillert 1511e0ad43cSotto static u_int64_t starting_sector; 1521e0ad43cSotto static u_int64_t ending_sector; 1532d8451b0Smillert static int expert; 154fc6e9c48Sotto static int overlap; 1556fe57b42Smillert 1566fe57b42Smillert /* 1574d4a335eSkrw * Simple partition editor. 1586fe57b42Smillert */ 1596fe57b42Smillert int 16034ae4198Skrw editor(struct disklabel *lp, int f) 1616fe57b42Smillert { 1624f3bbbf0Skrw struct disklabel origlabel, lastlabel, tmplabel, label = *lp; 1637e28fb0fSderaadt struct disklabel *disk_geop = NULL; 16496a888c6Smillert struct partition *pp; 1656fe57b42Smillert FILE *fp; 1666fe57b42Smillert char buf[BUFSIZ], *cmd, *arg; 16734ae4198Skrw char **omountpoints = NULL; 1684f3bbbf0Skrw char **origmountpoints = NULL, **tmpmountpoints = NULL; 1697e28fb0fSderaadt int i, error = 0; 170bd6726faSmillert 171bd6726faSmillert /* Alloc and init mount point info */ 17234ae4198Skrw if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 1734f3bbbf0Skrw !(origmountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 174bd6726faSmillert !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *)))) 175bd6726faSmillert errx(4, "out of memory"); 1766fe57b42Smillert 17796a888c6Smillert /* Don't allow disk type of "unknown" */ 17834ae4198Skrw getdisktype(&label, "You need to specify a type for this disk.", specname); 1796fe57b42Smillert 18087023ed9Skrw /* Get the on-disk geometries if possible */ 18187023ed9Skrw get_geometry(f, &disk_geop); 182c33fcabaSmillert 183d09f3941Smillert /* How big is the OpenBSD portion of the disk? */ 18487023ed9Skrw find_bounds(&label); 185d09f3941Smillert 18696a888c6Smillert /* Make sure there is no partition overlap. */ 1871f0f871dSkrw if (has_overlap(&label)) 1886fe57b42Smillert errx(1, "can't run when there is partition overlap."); 1896fe57b42Smillert 19096a888c6Smillert /* If we don't have a 'c' partition, create one. */ 191d09f3941Smillert pp = &label.d_partitions[RAW_PART]; 1921e0ad43cSotto if (label.d_npartitions < 3 || DL_GETPSIZE(pp) == 0) { 19396a888c6Smillert puts("No 'c' partition found, adding one that spans the disk."); 19496a888c6Smillert if (label.d_npartitions < 3) 19596a888c6Smillert label.d_npartitions = 3; 19634af67a3Sotto DL_SETPOFFSET(pp, 0); 19734af67a3Sotto DL_SETPSIZE(pp, DL_GETDSIZE(&label)); 19896a888c6Smillert pp->p_fstype = FS_UNUSED; 199ddfcbf38Sotto pp->p_fragblock = pp->p_cpg = 0; 20096a888c6Smillert } 2010f820bbbSmillert 202fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 203fc1a4cc6Sderaadt if (label.d_flags & D_VENDOR) { 204fc1a4cc6Sderaadt puts("This platform requires that partition offsets/sizes " 205fc1a4cc6Sderaadt "be on cylinder boundaries.\n" 206fc1a4cc6Sderaadt "Partition offsets/sizes will be rounded to the " 207fc1a4cc6Sderaadt "nearest cylinder automatically."); 208fc1a4cc6Sderaadt } 2096fe57b42Smillert #endif 2106fe57b42Smillert 211bd6726faSmillert /* Set d_bbsize and d_sbsize as necessary */ 21255403f76Smillert if (label.d_bbsize == 0) 21355403f76Smillert label.d_bbsize = BBSIZE; 21455403f76Smillert if (label.d_sbsize == 0) 21555403f76Smillert label.d_sbsize = SBSIZE; 216f98aebd4Smillert 21793160b9bSkrw /* Save the (U|u)ndo labels and mountpoints. */ 21893160b9bSkrw mpcopy(origmountpoints, mountpoints); 2194f3bbbf0Skrw origlabel = label; 2206fe57b42Smillert lastlabel = label; 22134ae4198Skrw 22234ae4198Skrw puts("Label editor (enter '?' for help at any prompt)"); 2236fe57b42Smillert for (;;) { 2246fe57b42Smillert fputs("> ", stdout); 2256e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 2266e0becc5Smillert putchar('\n'); 2276e0becc5Smillert buf[0] = 'q'; 2286e0becc5Smillert buf[1] = '\0'; 2296e0becc5Smillert } 230260513deSmillert if ((cmd = strtok(buf, " \t\r\n")) == NULL) 231260513deSmillert continue; 232260513deSmillert arg = strtok(NULL, " \t\r\n"); 2336fe57b42Smillert 2344f3bbbf0Skrw if ((*cmd != 'u') && (*cmd != 'U')) { 2354f3bbbf0Skrw /* 2364f3bbbf0Skrw * Save undo info in case the command tries to make 2374f3bbbf0Skrw * changes but decides not to. 2384f3bbbf0Skrw */ 2394f3bbbf0Skrw tmplabel = lastlabel; 2404f3bbbf0Skrw lastlabel = label; 2414f3bbbf0Skrw mpcopy(tmpmountpoints, omountpoints); 2424f3bbbf0Skrw mpcopy(omountpoints, mountpoints); 2434f3bbbf0Skrw } 2446fe57b42Smillert 2454f3bbbf0Skrw switch (*cmd) { 2466fe57b42Smillert case '?': 247ea37abd3Sderaadt case 'h': 2484d812bb6Slum editor_help(); 2496fe57b42Smillert break; 2506fe57b42Smillert 251557f712bSkrw case 'A': 252ab20a3eaSkrw if (ioctl(f, DIOCGPDINFO, &label) == 0) { 253ab20a3eaSkrw aflag = 1; 25434ae4198Skrw editor_allocspace(&label); 255ab20a3eaSkrw } else 25634ae4198Skrw label = lastlabel; 257557f712bSkrw break; 2586fe57b42Smillert case 'a': 25934ae4198Skrw editor_add(&label, arg); 26096a888c6Smillert break; 26196a888c6Smillert 26296a888c6Smillert case 'b': 2639fdcb4d6Skrw set_bounds(&label); 2646fe57b42Smillert break; 2656fe57b42Smillert 2666fe57b42Smillert case 'c': 2679fdcb4d6Skrw editor_change(&label, arg); 2686fe57b42Smillert break; 2696fe57b42Smillert 2709afbe9eeSmillert case 'D': 27193160b9bSkrw if (ioctl(f, DIOCGPDINFO, &label) == 0) { 27271bba4ecSkrw dflag = 1; 27393160b9bSkrw for (i=0; i<MAXPARTITIONS; i++) { 27493160b9bSkrw free(mountpoints[i]); 27593160b9bSkrw mountpoints[i] = NULL; 27693160b9bSkrw } 27793160b9bSkrw } else 278cdd7eb76Smillert warn("unable to get default partition table"); 2799afbe9eeSmillert break; 2809afbe9eeSmillert 2816fe57b42Smillert case 'd': 28234ae4198Skrw editor_delete(&label, arg); 2836fe57b42Smillert break; 2846fe57b42Smillert 2859afbe9eeSmillert case 'e': 2869fdcb4d6Skrw edit_parms(&label); 2879afbe9eeSmillert break; 2889afbe9eeSmillert 289c33fcabaSmillert case 'g': 29087023ed9Skrw set_geometry(&label, disk_geop, lp, arg); 291c33fcabaSmillert break; 292c33fcabaSmillert 2930d63cfbaSjsing case 'i': 2940d63cfbaSjsing set_uid(&label); 2950d63cfbaSjsing break; 2960d63cfbaSjsing 2976fe57b42Smillert case 'm': 29834ae4198Skrw editor_modify(&label, arg); 299bd6726faSmillert break; 300bd6726faSmillert 301bd6726faSmillert case 'n': 3025c79e1cfSkrw if (!fstabfile) { 303bd6726faSmillert fputs("This option is not valid when run " 30484d0bb16Sderaadt "without the -f flag.\n", stderr); 305bd6726faSmillert break; 306bd6726faSmillert } 30734ae4198Skrw editor_name(&label, arg); 3086fe57b42Smillert break; 3096fe57b42Smillert 3106fe57b42Smillert case 'p': 31134ae4198Skrw display_edit(&label, arg ? *arg : 0, editor_countfree(&label)); 3126fe57b42Smillert break; 3136fe57b42Smillert 314aff3f969Sotto case 'l': 31534ae4198Skrw display(stdout, &label, arg ? *arg : 0, 0); 316aff3f969Sotto break; 317aff3f969Sotto 318508086e9Smillert case 'M': { 319508086e9Smillert sig_t opipe = signal(SIGPIPE, SIG_IGN); 32045decb36Sderaadt char *pager, *comm = NULL; 321e7936562Sderaadt extern const u_char manpage[]; 32208f8e31fSotto extern const int manpage_sz; 3235d12b01bSderaadt 324489bd112Spjanzen if ((pager = getenv("PAGER")) == NULL || *pager == '\0') 325508086e9Smillert pager = _PATH_LESS; 32608f8e31fSotto 32745decb36Sderaadt if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 && 32845decb36Sderaadt (fp = popen(comm, "w")) != NULL) { 32908f8e31fSotto (void) fwrite(manpage, manpage_sz, 1, fp); 3305d12b01bSderaadt pclose(fp); 331508086e9Smillert } else 332508086e9Smillert warn("unable to execute %s", pager); 333508086e9Smillert 33445decb36Sderaadt free(comm); 335508086e9Smillert (void)signal(SIGPIPE, opipe); 3365d12b01bSderaadt break; 337508086e9Smillert } 3385d12b01bSderaadt 3396fe57b42Smillert case 'q': 34069220492Smillert if (donothing) { 34169220492Smillert puts("In no change mode, not writing label."); 3427e28fb0fSderaadt goto done; 34369220492Smillert } 344bd6726faSmillert /* Save mountpoint info if there is any. */ 34534ae4198Skrw mpsave(&label); 34693160b9bSkrw 34771bba4ecSkrw /* 34893160b9bSkrw * If we haven't changed the original label, and it 34993160b9bSkrw * wasn't a default label or an auto-allocated label, 35093160b9bSkrw * there is no need to do anything before exiting. Note 35193160b9bSkrw * that 'w' will reset dflag and aflag to allow 'q' to 35293160b9bSkrw * exit without further questions. 35371bba4ecSkrw */ 354ab20a3eaSkrw if (!dflag && !aflag && 355ab20a3eaSkrw memcmp(lp, &label, sizeof(label)) == 0) { 356bd6726faSmillert puts("No label changes."); 3577e28fb0fSderaadt goto done; 3586fe57b42Smillert } 3596fe57b42Smillert do { 360d0e67762Smillert arg = getstring("Write new label?", 361d0e67762Smillert "Write the modified label to disk?", 362d0e67762Smillert "y"); 36396a888c6Smillert } while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n'); 36496a888c6Smillert if (arg && tolower(*arg) == 'y') { 365d0e67762Smillert if (writelabel(f, bootarea, &label) == 0) { 3666fe57b42Smillert *lp = label; 3677e28fb0fSderaadt goto done; 3686fe57b42Smillert } 369d0e67762Smillert warnx("unable to write label"); 370d0e67762Smillert } 3717e28fb0fSderaadt error = 1; 3727e28fb0fSderaadt goto done; 3736fe57b42Smillert /* NOTREACHED */ 3746fe57b42Smillert break; 3756fe57b42Smillert 3766aaa4aabSotto case 'R': 377fc6e9c48Sotto if (aflag && !overlap) 3786aaa4aabSotto editor_resize(&label, arg); 3796aaa4aabSotto else 3806aaa4aabSotto fputs("Resize only implemented for auto " 381fc6e9c48Sotto "allocated labels\n", stderr); 3826aaa4aabSotto break; 3836aaa4aabSotto 38425f9c360Skrw case 'r': { 38525f9c360Skrw struct diskchunk *chunks; 38625f9c360Skrw int i; 3879fdcb4d6Skrw /* Display free space. */ 38825f9c360Skrw chunks = free_chunks(&label); 38925f9c360Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; 39025f9c360Skrw i++) 39125f9c360Skrw fprintf(stderr, "Free sectors: %16llu - %16llu " 39225f9c360Skrw "(%16llu)\n", 39325f9c360Skrw chunks[i].start, chunks[i].stop - 1, 39425f9c360Skrw chunks[i].stop - chunks[i].start); 39525f9c360Skrw fprintf(stderr, "Total free sectors: %llu.\n", 3969fdcb4d6Skrw editor_countfree(&label)); 397c0bdc608Smillert break; 39825f9c360Skrw } 399c0bdc608Smillert 4006fe57b42Smillert case 's': 4016fe57b42Smillert if (arg == NULL) { 402c33fcabaSmillert arg = getstring("Filename", 4036fe57b42Smillert "Name of the file to save label into.", 4046fe57b42Smillert NULL); 405e97229a3Scnst if (arg == NULL || *arg == '\0') 4066fe57b42Smillert break; 4076fe57b42Smillert } 4086fe57b42Smillert if ((fp = fopen(arg, "w")) == NULL) { 4096fe57b42Smillert warn("cannot open %s", arg); 4106fe57b42Smillert } else { 41134ae4198Skrw display(fp, &label, 0, 1); 4126fe57b42Smillert (void)fclose(fp); 4136fe57b42Smillert } 4146fe57b42Smillert break; 4156fe57b42Smillert 4164f3bbbf0Skrw case 'U': 41793160b9bSkrw /* 41893160b9bSkrw * If we allow 'U' repeatedly, information would be lost. This way 41993160b9bSkrw * multiple 'U's followed by 'u' would undo the 'U's. 42093160b9bSkrw */ 42193160b9bSkrw if (memcmp(&label, &origlabel, sizeof(label)) || 42293160b9bSkrw !mpequal(mountpoints, origmountpoints)) { 4234f3bbbf0Skrw tmplabel = label; 4244f3bbbf0Skrw label = origlabel; 4254f3bbbf0Skrw lastlabel = tmplabel; 4264f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 4274f3bbbf0Skrw mpcopy(mountpoints, origmountpoints); 4284f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4294f3bbbf0Skrw } 43093160b9bSkrw puts("Original label and mount points restored."); 4314f3bbbf0Skrw break; 4324f3bbbf0Skrw 4336fe57b42Smillert case 'u': 4346fe57b42Smillert tmplabel = label; 4356fe57b42Smillert label = lastlabel; 4366fe57b42Smillert lastlabel = tmplabel; 4374f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 438bd6726faSmillert mpcopy(mountpoints, omountpoints); 4394f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4406fe57b42Smillert puts("Last change undone."); 4416fe57b42Smillert break; 4426fe57b42Smillert 443040947cfSmillert case 'w': 444bd6726faSmillert if (donothing) { 445040947cfSmillert puts("In no change mode, not writing label."); 446bd6726faSmillert break; 447bd6726faSmillert } 44893160b9bSkrw 44941f684b9Skrw /* Write label to disk. */ 45041f684b9Skrw if (writelabel(f, bootarea, &label) != 0) 451040947cfSmillert warnx("unable to write label"); 45271bba4ecSkrw else { 453ab20a3eaSkrw dflag = aflag = 0; 4545af08e9cSmillert *lp = label; 45571bba4ecSkrw } 456040947cfSmillert break; 457040947cfSmillert 4582d8451b0Smillert case 'X': 4592d8451b0Smillert expert = !expert; 4602d8451b0Smillert printf("%s expert mode\n", expert ? "Entering" : 4612d8451b0Smillert "Exiting"); 4622d8451b0Smillert break; 4632d8451b0Smillert 4646fe57b42Smillert case 'x': 4657e28fb0fSderaadt goto done; 4666fe57b42Smillert break; 4676fe57b42Smillert 4689afbe9eeSmillert case 'z': 4699fdcb4d6Skrw zero_partitions(&label); 4706fe57b42Smillert break; 4716fe57b42Smillert 4729afbe9eeSmillert case '\n': 4736fe57b42Smillert break; 4746fe57b42Smillert 4756fe57b42Smillert default: 4766fe57b42Smillert printf("Unknown option: %c ('?' for help)\n", *cmd); 4776fe57b42Smillert break; 4786fe57b42Smillert } 4794f3bbbf0Skrw 4804f3bbbf0Skrw /* 4814f3bbbf0Skrw * If no changes were made to label or mountpoints, then 4824f3bbbf0Skrw * restore undo info. 4834f3bbbf0Skrw */ 4844f3bbbf0Skrw if (memcmp(&label, &lastlabel, sizeof(label)) == 0 && 48593160b9bSkrw (mpequal(mountpoints, omountpoints))) { 4864f3bbbf0Skrw lastlabel = tmplabel; 4874f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4884f3bbbf0Skrw } 4896fe57b42Smillert } 4907e28fb0fSderaadt done: 4917e28fb0fSderaadt free(omountpoints); 4927e28fb0fSderaadt free(origmountpoints); 4937e28fb0fSderaadt free(tmpmountpoints); 4947e28fb0fSderaadt if (disk_geop) 4957e28fb0fSderaadt free(disk_geop); 4967e28fb0fSderaadt return(error); 4976fe57b42Smillert } 4986fe57b42Smillert 4998dde8bb6Sotto int64_t 5008dde8bb6Sotto getphysmem(void) 5018dde8bb6Sotto { 5028dde8bb6Sotto int64_t physmem; 5038dde8bb6Sotto size_t sz = sizeof(physmem); 5048dde8bb6Sotto int mib[] = { CTL_HW, HW_PHYSMEM64 }; 5058dde8bb6Sotto if (sysctl(mib, 2, &physmem, &sz, NULL, (size_t)0) == -1) 5068dde8bb6Sotto errx(4, "can't get mem size"); 5078dde8bb6Sotto return physmem; 5088dde8bb6Sotto } 5098dde8bb6Sotto 5106fe57b42Smillert /* 511557f712bSkrw * Allocate all disk space according to standard recommendations for a 512557f712bSkrw * root disk. 513557f712bSkrw */ 514557f712bSkrw void 5158dde8bb6Sotto editor_allocspace(struct disklabel *lp_org) 516557f712bSkrw { 5178dde8bb6Sotto struct disklabel *lp, label; 5188dde8bb6Sotto struct space_allocation *alloc; 51934ae4198Skrw struct space_allocation *ap; 520557f712bSkrw struct partition *pp; 52134ae4198Skrw struct diskchunk *chunks; 52234ae4198Skrw daddr64_t secs, chunkstart, chunksize, cylsecs, totsecs, xtrasecs; 52334ae4198Skrw char **partmp; 524*a49bdda8Skrw int i, j, lastalloc, index = 0, fragsize, partno; 5258dde8bb6Sotto int64_t physmem; 5268dde8bb6Sotto 52734ae4198Skrw /* How big is the OpenBSD portion of the disk? */ 5288dde8bb6Sotto find_bounds(lp_org); 529557f712bSkrw 530fc6e9c48Sotto overlap = 0; 531fc6e9c48Sotto for (i = 0; i < MAXPARTITIONS; i++) { 532fc6e9c48Sotto daddr64_t psz, pstart, pend; 533fc6e9c48Sotto 534fc6e9c48Sotto pp = &lp_org->d_partitions[i]; 535fc6e9c48Sotto psz = DL_GETPSIZE(pp); 536fc6e9c48Sotto pstart = DL_GETPOFFSET(pp); 537fc6e9c48Sotto pend = pstart + psz; 538fc6e9c48Sotto if (i != RAW_PART && psz != 0 && 539fc6e9c48Sotto ((pstart >= starting_sector && pstart <= ending_sector) || 540fc6e9c48Sotto (pend > starting_sector && pend < ending_sector))) { 541fc6e9c48Sotto overlap = 1; 542fc6e9c48Sotto break; 543fc6e9c48Sotto } 544fc6e9c48Sotto } 545fc6e9c48Sotto 546fc6e9c48Sotto physmem = getphysmem() / lp_org->d_secsize; 547fc6e9c48Sotto 5488dde8bb6Sotto cylsecs = lp_org->d_secpercyl; 5498dde8bb6Sotto again: 5508dde8bb6Sotto lp = &label; 5513d98fc8cSkrw for (i=0; i<MAXPARTITIONS; i++) { 5523d98fc8cSkrw free(mountpoints[i]); 5533d98fc8cSkrw mountpoints[i] = NULL; 5543d98fc8cSkrw } 5558dde8bb6Sotto memcpy(lp, lp_org, sizeof(struct disklabel)); 5560a7398ceSderaadt lp->d_npartitions = MAXPARTITIONS; 5578dde8bb6Sotto lastalloc = alloc_table[index].sz; 5588dde8bb6Sotto alloc = malloc(lastalloc * sizeof(struct space_allocation)); 5598dde8bb6Sotto if (alloc == NULL) 5608dde8bb6Sotto errx(4, "out of memory"); 5618dde8bb6Sotto memcpy(alloc, alloc_table[index].table, 5628dde8bb6Sotto lastalloc * sizeof(struct space_allocation)); 5638dde8bb6Sotto 5648dde8bb6Sotto /* bump max swap based on phys mem, little physmem gets 2x swap */ 5658dde8bb6Sotto if (index == 0) { 5668dde8bb6Sotto if (physmem < 256LL * 1024 * 1024 / lp->d_secsize) 5678dde8bb6Sotto alloc[1].maxsz = 2 * physmem; 5688dde8bb6Sotto else 5698dde8bb6Sotto alloc[1].maxsz += physmem; 5708dde8bb6Sotto /* bump max /var to make room for 2 crash dumps */ 5718dde8bb6Sotto alloc[3].maxsz += 2 * physmem; 5728dde8bb6Sotto } 5738dde8bb6Sotto 57434ae4198Skrw xtrasecs = totsecs = editor_countfree(lp); 575557f712bSkrw 57634ae4198Skrw for (i = 0; i < lastalloc; i++) { 5775f3e1104Skrw alloc[i].minsz = DL_BLKTOSEC(lp, alloc[i].minsz); 5785f3e1104Skrw alloc[i].maxsz = DL_BLKTOSEC(lp, alloc[i].maxsz); 57934ae4198Skrw if (xtrasecs > alloc[i].minsz) 58034ae4198Skrw xtrasecs -= alloc[i].minsz; 58134ae4198Skrw else 58234ae4198Skrw xtrasecs = 0; 583557f712bSkrw } 584557f712bSkrw 58534ae4198Skrw for (i = 0; i < lastalloc; i++) { 58634ae4198Skrw /* Find next available partition. */ 58734ae4198Skrw for (j = 0; j < MAXPARTITIONS; j++) 58834ae4198Skrw if (DL_GETPSIZE(&lp->d_partitions[j]) == 0) 58934ae4198Skrw break; 59034ae4198Skrw if (j == MAXPARTITIONS) 59134ae4198Skrw return; 592*a49bdda8Skrw partno = j; 59334ae4198Skrw pp = &lp->d_partitions[j]; 59434ae4198Skrw partmp = &mountpoints[j]; 59534ae4198Skrw ap = &alloc[i]; 596557f712bSkrw 59734ae4198Skrw /* Figure out the size of the partition. */ 59834ae4198Skrw if (i == lastalloc - 1) { 59934ae4198Skrw if (totsecs > ap->maxsz) 60034ae4198Skrw secs = ap->maxsz; 601557f712bSkrw else 6025f3e1104Skrw secs = totsecs; 6031f5ea549Skrw #ifdef SUN_CYLCHECK 6041f5ea549Skrw goto cylinderalign; 6051f5ea549Skrw #endif 606557f712bSkrw } else { 60734ae4198Skrw secs = ap->minsz; 6085f3e1104Skrw if (xtrasecs > 0) 60934ae4198Skrw secs += (xtrasecs / 100) * ap->rate; 61034ae4198Skrw if (secs > ap->maxsz) 61134ae4198Skrw secs = ap->maxsz; 6121f5ea549Skrw #ifdef SUN_CYLCHECK 6131f5ea549Skrw cylinderalign: 6145f3e1104Skrw secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; 6151f5ea549Skrw #endif 6165f3e1104Skrw totsecs -= secs; 6171f5ea549Skrw #ifdef SUN_CYLCHECK 6185f3e1104Skrw while (totsecs < 0) { 6195f3e1104Skrw secs -= cylsecs; 6205f3e1104Skrw totsecs += cylsecs; 621557f712bSkrw } 6221f5ea549Skrw #endif 623557f712bSkrw } 62434ae4198Skrw 62534ae4198Skrw /* Find largest chunk of free space. */ 62634ae4198Skrw chunks = free_chunks(lp); 62734ae4198Skrw chunkstart = 0; 62834ae4198Skrw chunksize = 0; 62934ae4198Skrw for (j = 0; chunks[j].start != 0 || chunks[j].stop != 0; j++) 63034ae4198Skrw if ((chunks[j].stop - chunks[j].start) > chunksize) { 63134ae4198Skrw chunkstart = chunks[j].start; 63234ae4198Skrw chunksize = chunks[j].stop - chunks[j].start; 633557f712bSkrw } 63434ae4198Skrw #ifdef SUN_CYLCHECK 63534ae4198Skrw if (lp->d_flags & D_VENDOR) { 63634ae4198Skrw /* Align chunk to cylinder boundaries. */ 63734ae4198Skrw chunksize -= chunksize % cylsecs; 6386ab0bb66Skrw chunkstart = ((chunkstart + cylsecs - 1) / cylsecs) * 6396ab0bb66Skrw cylsecs; 64034ae4198Skrw } 64134ae4198Skrw #endif 64234ae4198Skrw /* See if partition can fit into chunk. */ 64334ae4198Skrw if (secs > chunksize) { 64434ae4198Skrw totsecs += secs - chunksize; 64534ae4198Skrw secs = chunksize; 64634ae4198Skrw } 64734ae4198Skrw if (secs < ap->minsz) { 6488dde8bb6Sotto /* It did not work out, try next strategy */ 6498dde8bb6Sotto free(alloc); 6508dde8bb6Sotto if (++index < nitems(alloc_table)) 6518dde8bb6Sotto goto again; 6528dde8bb6Sotto else 6538dde8bb6Sotto return; 654557f712bSkrw } 65534ae4198Skrw 65634ae4198Skrw /* Everything seems ok so configure the partition. */ 6575f3e1104Skrw DL_SETPSIZE(pp, secs); 65834ae4198Skrw DL_SETPOFFSET(pp, chunkstart); 6596e312d52Sotto fragsize = 2048; 660c88f83bdSotto if (secs * lp->d_secsize > 128ULL * 1024 * 1024 * 1024) 661c88f83bdSotto fragsize *= 2; 662c88f83bdSotto if (secs * lp->d_secsize > 512ULL * 1024 * 1024 * 1024) 663c88f83bdSotto fragsize *= 2; 664557f712bSkrw #if defined (__sparc__) && !defined(__sparc64__) 665557f712bSkrw /* can't boot from > 8k boot blocks */ 666557f712bSkrw pp->p_fragblock = 6676e312d52Sotto DISKLABELV1_FFS_FRAGBLOCK(i == 0 ? 1024 : fragsize, 8); 668557f712bSkrw #else 6696e312d52Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8); 670557f712bSkrw #endif 671557f712bSkrw pp->p_cpg = 1; 67234ae4198Skrw if (ap->mp[0] != '/') 67334ae4198Skrw pp->p_fstype = FS_SWAP; 67434ae4198Skrw else { 67534ae4198Skrw pp->p_fstype = FS_BSDFFS; 676*a49bdda8Skrw get_bsize(lp, partno); 67734ae4198Skrw free(*partmp); 67834ae4198Skrw if ((*partmp = strdup(ap->mp)) == NULL) 679557f712bSkrw errx(4, "out of memory"); 680557f712bSkrw } 681557f712bSkrw } 682557f712bSkrw 6838dde8bb6Sotto free(alloc); 6848dde8bb6Sotto memcpy(lp_org, lp, sizeof(struct disklabel)); 685557f712bSkrw } 686557f712bSkrw 687557f712bSkrw /* 6886aaa4aabSotto * Resize a partition, moving all subsequent partitions 6896aaa4aabSotto */ 6906aaa4aabSotto void 6916aaa4aabSotto editor_resize(struct disklabel *lp, char *p) 6926aaa4aabSotto { 6936aaa4aabSotto struct disklabel label; 6946aaa4aabSotto struct partition *pp, *prev; 6956aaa4aabSotto daddr64_t secs, sz, off; 6966aaa4aabSotto #ifdef SUN_CYLCHECK 6976aaa4aabSotto daddr64_t cylsecs; 6986aaa4aabSotto #endif 6996aaa4aabSotto int partno, i; 7006aaa4aabSotto 7016aaa4aabSotto label = *lp; 7026aaa4aabSotto 7036aaa4aabSotto /* Change which partition? */ 7046aaa4aabSotto if (p == NULL) { 7056aaa4aabSotto p = getstring("partition to resize", 7066aaa4aabSotto "The letter of the partition to name, a - p.", NULL); 7076aaa4aabSotto } 7086aaa4aabSotto if (p == NULL) { 7096aaa4aabSotto fputs("Command aborted\n", stderr); 7106aaa4aabSotto return; 7116aaa4aabSotto } 7126aaa4aabSotto partno = p[0] - 'a'; 7136aaa4aabSotto if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 7146aaa4aabSotto fprintf(stderr, "Partition must be between 'a' and '%c' " 7156aaa4aabSotto "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 7166aaa4aabSotto return; 7176aaa4aabSotto } 7186aaa4aabSotto 7196aaa4aabSotto pp = &label.d_partitions[partno]; 720fc6e9c48Sotto sz = DL_GETPSIZE(pp); 721fc6e9c48Sotto if (sz == 0) { 722fc6e9c48Sotto fputs("No such partition\n", stderr); 723fc6e9c48Sotto return; 724fc6e9c48Sotto } 725fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) { 726fc6e9c48Sotto fputs("Cannot resize spoofed partition\n", stderr); 727fc6e9c48Sotto return; 728fc6e9c48Sotto } 7296aaa4aabSotto secs = getuint(lp, "resize", "amount to grow (+) or shrink (-)", 730fc6e9c48Sotto 0, editor_countfree(lp), 0, DO_CONVERSIONS); 7316aaa4aabSotto 732fc6e9c48Sotto if (secs == 0 || secs == -1) { 7336aaa4aabSotto fputs("Command aborted\n", stderr); 7346aaa4aabSotto return; 7356aaa4aabSotto } 7366aaa4aabSotto 7376aaa4aabSotto #ifdef SUN_CYLCHECK 7386aaa4aabSotto cylsecs = lp->d_secpercyl; 7396aaa4aabSotto if (secs > 0) 7406aaa4aabSotto secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; 7416aaa4aabSotto else 7426aaa4aabSotto secs = ((secs - cylsecs + 1) / cylsecs) * cylsecs; 7436aaa4aabSotto #endif 7446aaa4aabSotto if (DL_GETPOFFSET(pp) + sz + secs > ending_sector) { 7456aaa4aabSotto fputs("Amount too big\n", stderr); 7466aaa4aabSotto return; 7476aaa4aabSotto } 7486aaa4aabSotto if (sz + secs < 0) { 7496aaa4aabSotto fputs("Amount too small\n", stderr); 7506aaa4aabSotto return; 7516aaa4aabSotto } 7526aaa4aabSotto 7536aaa4aabSotto DL_SETPSIZE(pp, sz + secs); 7546aaa4aabSotto 7556aaa4aabSotto /* 7566aaa4aabSotto * Pack partitions above the resized partition, leaving unused 7576aaa4aabSotto * partions alone. 7586aaa4aabSotto */ 7596aaa4aabSotto prev = pp; 7606aaa4aabSotto for (i = partno + 1; i < MAXPARTITIONS; i++) { 7616aaa4aabSotto if (i == RAW_PART) 7626aaa4aabSotto continue; 763fc6e9c48Sotto pp = &label.d_partitions[i]; 764fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) 765fc6e9c48Sotto continue; 766fc6e9c48Sotto sz = DL_GETPSIZE(pp); 7676aaa4aabSotto if (sz == 0) 7686aaa4aabSotto continue; 7696aaa4aabSotto 7706aaa4aabSotto off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev); 7716aaa4aabSotto 7726aaa4aabSotto if (off < ending_sector) { 7736aaa4aabSotto DL_SETPOFFSET(pp, off); 7746aaa4aabSotto if (off + DL_GETPSIZE(pp) > ending_sector) { 7756aaa4aabSotto DL_SETPSIZE(pp, ending_sector - off); 7766aaa4aabSotto fprintf(stderr, 7776aaa4aabSotto "Partition %c shrunk to make room\n", 7786aaa4aabSotto i + 'a'); 7796aaa4aabSotto } 7806aaa4aabSotto } else { 7816aaa4aabSotto fputs("No room left for all partitions\n", stderr); 7826aaa4aabSotto return; 7836aaa4aabSotto } 7846aaa4aabSotto prev = pp; 7856aaa4aabSotto } 7866aaa4aabSotto *lp = label; 7876aaa4aabSotto } 7886aaa4aabSotto 7896aaa4aabSotto /* 7906fe57b42Smillert * Add a new partition. 7916fe57b42Smillert */ 7926fe57b42Smillert void 79334ae4198Skrw editor_add(struct disklabel *lp, char *p) 7946fe57b42Smillert { 79596a888c6Smillert struct partition *pp; 79696a888c6Smillert struct diskchunk *chunks; 7975caa08b2Skrw char buf[2]; 7986e312d52Sotto int i, partno, fragsize; 799f8ab7229Schl u_int64_t freesectors, new_offset, new_size; 8009fdcb4d6Skrw 8019fdcb4d6Skrw freesectors = editor_countfree(lp); 8026fe57b42Smillert 8036fe57b42Smillert /* XXX - prompt user to steal space from another partition instead */ 804fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 8059fdcb4d6Skrw if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) { 806fc1a4cc6Sderaadt fputs("No space left, you need to shrink a partition " 807fc1a4cc6Sderaadt "(need at least one full cylinder)\n", 808fc1a4cc6Sderaadt stderr); 809fc1a4cc6Sderaadt return; 810fc1a4cc6Sderaadt } 8118390cf28Smillert #endif 8129fdcb4d6Skrw if (freesectors == 0) { 8136fe57b42Smillert fputs("No space left, you need to shrink a partition\n", 8146fe57b42Smillert stderr); 8156fe57b42Smillert return; 8166fe57b42Smillert } 8176fe57b42Smillert 8185caa08b2Skrw if (p == NULL) { 8195caa08b2Skrw /* 8205caa08b2Skrw * Use the first unused partition that is not 'c' as the 8215caa08b2Skrw * default partition in the prompt string. 8225caa08b2Skrw */ 8235caa08b2Skrw pp = &lp->d_partitions[0]; 8245caa08b2Skrw buf[0] = buf[1] = '\0'; 8255caa08b2Skrw for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) { 8265caa08b2Skrw if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) { 8275caa08b2Skrw buf[0] = partno + 'a'; 8285caa08b2Skrw p = &buf[0]; 8296fe57b42Smillert break; 8306fe57b42Smillert } 8315caa08b2Skrw } 832c33fcabaSmillert p = getstring("partition", 8336fe57b42Smillert "The letter of the new partition, a - p.", p); 8346fe57b42Smillert } 8355caa08b2Skrw if (p == NULL) { 8365caa08b2Skrw fputs("Command aborted\n", stderr); 8375caa08b2Skrw return; 8385caa08b2Skrw } 8395caa08b2Skrw partno = p[0] - 'a'; 8405caa08b2Skrw if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) { 8415caa08b2Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 8425caa08b2Skrw "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1); 8435caa08b2Skrw return; 8445caa08b2Skrw } 8455caa08b2Skrw pp = &lp->d_partitions[partno]; 8465caa08b2Skrw 8475caa08b2Skrw if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) { 8485caa08b2Skrw fprintf(stderr, "Partition '%c' exists. Delete it first.\n", 8495caa08b2Skrw p[0]); 8505caa08b2Skrw return; 8516fe57b42Smillert } 85296a888c6Smillert 853caf41f96Skrw /* 854caf41f96Skrw * Increase d_npartitions if necessary. Ensure all new partitions are 855855d4e83Ssobrado * zero'ed to avoid inadvertent overlaps. 856caf41f96Skrw */ 857caf41f96Skrw for(; lp->d_npartitions <= partno; lp->d_npartitions++) 858caf41f96Skrw memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp)); 85996a888c6Smillert 86089f4601dSkrw /* Make sure selected partition is zero'd too. */ 86189f4601dSkrw memset(pp, 0, sizeof(*pp)); 86215c15d8aSkrw chunks = free_chunks(lp); 86315c15d8aSkrw 86415c15d8aSkrw /* 86515c15d8aSkrw * Since we know there's free space, there must be at least one 86615c15d8aSkrw * chunk. So find the largest chunk and assume we want to add the 86715c15d8aSkrw * partition in that free space. 86815c15d8aSkrw */ 86915c15d8aSkrw new_size = new_offset = 0; 87015c15d8aSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 87115c15d8aSkrw if (chunks[i].stop - chunks[i].start > new_size) { 87215c15d8aSkrw new_size = chunks[i].stop - chunks[i].start; 87315c15d8aSkrw new_offset = chunks[i].start; 87415c15d8aSkrw } 87515c15d8aSkrw } 8761e0ad43cSotto DL_SETPSIZE(pp, new_size); 8771e0ad43cSotto DL_SETPOFFSET(pp, new_offset); 87896a888c6Smillert pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS; 879c88f83bdSotto pp->p_cpg = 1; 880c88f83bdSotto 881c88f83bdSotto if (get_offset(lp, partno) == 0 && 882c88f83bdSotto get_size(lp, partno) == 0) { 8836e312d52Sotto fragsize = 2048; 884c88f83bdSotto new_size = DL_GETPSIZE(pp) * lp->d_secsize; 885c88f83bdSotto if (new_size > 128ULL * 1024 * 1024 * 1024) 886c88f83bdSotto fragsize *= 2; 887c88f83bdSotto if (new_size > 512ULL * 1024 * 1024 * 1024) 888c88f83bdSotto fragsize *= 2; 8894a8b9208Stedu #if defined (__sparc__) && !defined(__sparc64__) 890d98d4df7Stedu /* can't boot from > 8k boot blocks */ 891ddfcbf38Sotto pp->p_fragblock = 8926e312d52Sotto DISKLABELV1_FFS_FRAGBLOCK(partno == 0 ? 1024 : fragsize, 8); 893d98d4df7Stedu #else 8946e312d52Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8); 895d98d4df7Stedu #endif 896c88f83bdSotto if (get_fstype(lp, partno) == 0 && 89734ae4198Skrw get_mp(lp, partno) == 0 && 898a4c87e64Skrw get_fsize(lp, partno) == 0 && 899a4c87e64Skrw get_bsize(lp, partno) == 0) 90096a888c6Smillert return; 901c88f83bdSotto } 902a4c87e64Skrw /* Bailed out at some point, so effectively delete the partition. */ 903a4c87e64Skrw DL_SETPSIZE(pp, 0); 9046fe57b42Smillert } 9056fe57b42Smillert 9066fe57b42Smillert /* 907bd6726faSmillert * Set the mountpoint of an existing partition ('name'). 908bd6726faSmillert */ 909bd6726faSmillert void 91034ae4198Skrw editor_name(struct disklabel *lp, char *p) 911bd6726faSmillert { 912bd6726faSmillert struct partition *pp; 913bd6726faSmillert int partno; 914bd6726faSmillert 915bd6726faSmillert /* Change which partition? */ 916bd6726faSmillert if (p == NULL) { 917c33fcabaSmillert p = getstring("partition to name", 918bd6726faSmillert "The letter of the partition to name, a - p.", NULL); 919bd6726faSmillert } 920bd6726faSmillert if (p == NULL) { 921bd6726faSmillert fputs("Command aborted\n", stderr); 922bd6726faSmillert return; 923bd6726faSmillert } 924bd6726faSmillert partno = p[0] - 'a'; 9256c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9266c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9276c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 928bd6726faSmillert return; 92966df1f0cSkrw } 93066df1f0cSkrw pp = &lp->d_partitions[partno]; 93166df1f0cSkrw 93266df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 93366df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 934bd6726faSmillert return; 935bd6726faSmillert } 936bd6726faSmillert 937bd6726faSmillert /* Not all fstypes can be named */ 938bd6726faSmillert if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP || 939bd387921Stodd pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER || 940bd387921Stodd pp->p_fstype == FS_RAID) { 941bd6726faSmillert fprintf(stderr, "You cannot name a filesystem of type %s.\n", 942baa55472Smillert fstypenames[lp->d_partitions[partno].p_fstype]); 943bd6726faSmillert return; 944bd6726faSmillert } 945bd6726faSmillert 94634ae4198Skrw get_mp(lp, partno); 947bd6726faSmillert } 948bd6726faSmillert 949bd6726faSmillert /* 9506fe57b42Smillert * Change an existing partition. 9516fe57b42Smillert */ 9526fe57b42Smillert void 95334ae4198Skrw editor_modify(struct disklabel *lp, char *p) 9546fe57b42Smillert { 9556fe57b42Smillert struct partition origpart, *pp; 956f8ab7229Schl int partno; 9576fe57b42Smillert 9586fe57b42Smillert /* Change which partition? */ 9596fe57b42Smillert if (p == NULL) { 960c33fcabaSmillert p = getstring("partition to modify", 9616fe57b42Smillert "The letter of the partition to modify, a - p.", NULL); 9626fe57b42Smillert } 96396a888c6Smillert if (p == NULL) { 96496a888c6Smillert fputs("Command aborted\n", stderr); 96596a888c6Smillert return; 96696a888c6Smillert } 9676fe57b42Smillert partno = p[0] - 'a'; 9686c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9696c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9706c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 9716fe57b42Smillert return; 97266df1f0cSkrw } 97366df1f0cSkrw pp = &lp->d_partitions[partno]; 97466df1f0cSkrw 97566df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 97666df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 9776fe57b42Smillert return; 9786fe57b42Smillert } 9796fe57b42Smillert 98066df1f0cSkrw origpart = *pp; 98166df1f0cSkrw 982a4c87e64Skrw if (get_offset(lp, partno) == 0 && 983a4c87e64Skrw get_size(lp, partno) == 0 && 984a4c87e64Skrw get_fstype(lp, partno) == 0 && 98534ae4198Skrw get_mp(lp, partno) == 0 && 986a4c87e64Skrw get_fsize(lp, partno) == 0 && 987a4c87e64Skrw get_bsize(lp, partno) == 0) 98896a888c6Smillert return; 9896fe57b42Smillert 990a4c87e64Skrw /* Bailed out at some point, so undo any changes. */ 991a4c87e64Skrw *pp = origpart; 9926fe57b42Smillert } 9936fe57b42Smillert 9946fe57b42Smillert /* 9956fe57b42Smillert * Delete an existing partition. 9966fe57b42Smillert */ 9976fe57b42Smillert void 99834ae4198Skrw editor_delete(struct disklabel *lp, char *p) 9996fe57b42Smillert { 100066df1f0cSkrw struct partition *pp; 1001135c90d1Skrw int partno; 10026fe57b42Smillert 10036fe57b42Smillert if (p == NULL) { 1004c33fcabaSmillert p = getstring("partition to delete", 1005945ae268Smillert "The letter of the partition to delete, a - p, or '*'.", 1006945ae268Smillert NULL); 10076fe57b42Smillert } 100896a888c6Smillert if (p == NULL) { 100996a888c6Smillert fputs("Command aborted\n", stderr); 101096a888c6Smillert return; 101196a888c6Smillert } 1012945ae268Smillert if (p[0] == '*') { 10139fdcb4d6Skrw zero_partitions(lp); 1014945ae268Smillert return; 1015945ae268Smillert } 1016135c90d1Skrw partno = p[0] - 'a'; 1017135c90d1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 10186c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 10196c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 102033262abfSmiod return; 102166df1f0cSkrw } 1022135c90d1Skrw pp = &lp->d_partitions[partno]; 102366df1f0cSkrw 102466df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 102566df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 102633262abfSmiod return; 102766df1f0cSkrw } 102866df1f0cSkrw 10296fe57b42Smillert /* Really delete it (as opposed to just setting to "unused") */ 1030135c90d1Skrw memset(pp, 0, sizeof(*pp)); 103134ae4198Skrw free(mountpoints[partno]); 103234ae4198Skrw mountpoints[partno] = NULL; 10336fe57b42Smillert } 10346fe57b42Smillert 10356fe57b42Smillert /* 10366fe57b42Smillert * Change the size of an existing partition. 10376fe57b42Smillert */ 10386fe57b42Smillert void 10399fdcb4d6Skrw editor_change(struct disklabel *lp, char *p) 10406fe57b42Smillert { 10414b9a3bdaSmillert struct partition *pp; 104266df1f0cSkrw int partno; 10436fe57b42Smillert 10446fe57b42Smillert if (p == NULL) { 1045c33fcabaSmillert p = getstring("partition to change size", 10466fe57b42Smillert "The letter of the partition to change size, a - p.", NULL); 10476fe57b42Smillert } 104896a888c6Smillert if (p == NULL) { 104996a888c6Smillert fputs("Command aborted\n", stderr); 105096a888c6Smillert return; 105196a888c6Smillert } 10526fe57b42Smillert partno = p[0] - 'a'; 10536c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 10546c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 10556c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 10566fe57b42Smillert return; 10576fe57b42Smillert } 10584b9a3bdaSmillert pp = &lp->d_partitions[partno]; 10596fe57b42Smillert 106066df1f0cSkrw if (DL_GETPSIZE(pp) == 0) { 106166df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 106266df1f0cSkrw return; 106366df1f0cSkrw } 106466df1f0cSkrw 106514192793Skrw printf("Partition %c is currently %llu sectors in size, and can have " 106614192793Skrw "a maximum\nsize of %llu sectors.\n", 106714192793Skrw p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno)); 10687da73705Skrw 106959ccf790Skrw /* Get new size */ 10709fdcb4d6Skrw get_size(lp, partno); 10716fe57b42Smillert } 10726fe57b42Smillert 10736fe57b42Smillert /* 10746fe57b42Smillert * Sort the partitions based on starting offset. 10756fe57b42Smillert * This assumes there can be no overlap. 10766fe57b42Smillert */ 10776fe57b42Smillert int 10788809fabbSderaadt partition_cmp(const void *e1, const void *e2) 10796fe57b42Smillert { 10806fe57b42Smillert struct partition *p1 = *(struct partition **)e1; 10816fe57b42Smillert struct partition *p2 = *(struct partition **)e2; 10821e0ad43cSotto u_int64_t o1 = DL_GETPOFFSET(p1); 10831e0ad43cSotto u_int64_t o2 = DL_GETPOFFSET(p2); 10846fe57b42Smillert 10851e0ad43cSotto if (o1 < o2) 1086651d5bd9Sotto return -1; 10871e0ad43cSotto else if (o1 > o2) 1088651d5bd9Sotto return 1; 1089651d5bd9Sotto else 1090651d5bd9Sotto return 0; 10916fe57b42Smillert } 10926fe57b42Smillert 10936fe57b42Smillert char * 10948809fabbSderaadt getstring(char *prompt, char *helpstring, char *oval) 10956fe57b42Smillert { 10966fe57b42Smillert static char buf[BUFSIZ]; 10976fe57b42Smillert int n; 10986fe57b42Smillert 10996fe57b42Smillert buf[0] = '\0'; 11006fe57b42Smillert do { 11016fe57b42Smillert printf("%s: [%s] ", prompt, oval ? oval : ""); 11026e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1103260513deSmillert buf[0] = '\0'; 110496a888c6Smillert if (feof(stdin)) { 110524c6582eSmillert clearerr(stdin); 110696a888c6Smillert putchar('\n'); 110796a888c6Smillert return(NULL); 110896a888c6Smillert } 11096e0becc5Smillert } 11106fe57b42Smillert n = strlen(buf); 11116fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 11126fe57b42Smillert buf[--n] = '\0'; 11136fe57b42Smillert if (buf[0] == '?') 11146fe57b42Smillert puts(helpstring); 11154fb6ab7cSmillert else if (oval != NULL && buf[0] == '\0') 11164fb6ab7cSmillert strlcpy(buf, oval, sizeof(buf)); 11176fe57b42Smillert } while (buf[0] == '?'); 11186fe57b42Smillert 11196fe57b42Smillert return(&buf[0]); 11206fe57b42Smillert } 11216fe57b42Smillert 11226fe57b42Smillert /* 11231e0ad43cSotto * Returns ULLONG_MAX on error 112424a2c1a4Smillert * Usually only called by helper functions. 11256fe57b42Smillert */ 11261e0ad43cSotto u_int64_t 1127dea75673Skrw getuint(struct disklabel *lp, char *prompt, char *helpstring, 11281e0ad43cSotto u_int64_t oval, u_int64_t maxval, u_int64_t offset, int flags) 11296fe57b42Smillert { 11306fe57b42Smillert char buf[BUFSIZ], *endptr, *p, operator = '\0'; 11311e0ad43cSotto u_int64_t rval = oval; 11326fe57b42Smillert size_t n; 11336fe57b42Smillert int mult = 1; 113414cc915fSmillert double d, percent = 1.0; 11356fe57b42Smillert 11364b9a3bdaSmillert /* We only care about the remainder */ 11374b9a3bdaSmillert offset = offset % lp->d_secpercyl; 11384b9a3bdaSmillert 11396fe57b42Smillert buf[0] = '\0'; 11406fe57b42Smillert do { 11411e0ad43cSotto printf("%s: [%llu] ", prompt, oval); 11426e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 11436e0becc5Smillert buf[0] = '\0'; 114496a888c6Smillert if (feof(stdin)) { 114524c6582eSmillert clearerr(stdin); 114696a888c6Smillert putchar('\n'); 11471e0ad43cSotto return(ULLONG_MAX - 1); 114896a888c6Smillert } 11496e0becc5Smillert } 11506fe57b42Smillert n = strlen(buf); 11516fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 11526fe57b42Smillert buf[--n] = '\0'; 11536fe57b42Smillert if (buf[0] == '?') 11546fe57b42Smillert puts(helpstring); 11556fe57b42Smillert } while (buf[0] == '?'); 11566fe57b42Smillert 11576fe57b42Smillert if (buf[0] == '*' && buf[1] == '\0') { 11586fe57b42Smillert rval = maxval; 11596fe57b42Smillert } else { 11606fe57b42Smillert /* deal with units */ 11616fe57b42Smillert if (buf[0] != '\0' && n > 0) { 11626fe57b42Smillert if ((flags & DO_CONVERSIONS)) { 116396a888c6Smillert switch (tolower(buf[n-1])) { 11646fe57b42Smillert 11656fe57b42Smillert case 'c': 11666fe57b42Smillert mult = lp->d_secpercyl; 11676fe57b42Smillert buf[--n] = '\0'; 11686fe57b42Smillert break; 11696fe57b42Smillert case 'b': 11706fe57b42Smillert mult = -lp->d_secsize; 11716fe57b42Smillert buf[--n] = '\0'; 11726fe57b42Smillert break; 11736fe57b42Smillert case 'k': 117450c0f47aSkrw if (lp->d_secsize > 1024) 117550c0f47aSkrw mult = -lp->d_secsize / 1024; 117650c0f47aSkrw else 11776fe57b42Smillert mult = 1024 / lp->d_secsize; 11786fe57b42Smillert buf[--n] = '\0'; 11796fe57b42Smillert break; 11806fe57b42Smillert case 'm': 11816fe57b42Smillert mult = 1048576 / lp->d_secsize; 11826fe57b42Smillert buf[--n] = '\0'; 11836fe57b42Smillert break; 11841a51a1eeSmillert case 'g': 11851a51a1eeSmillert mult = 1073741824 / lp->d_secsize; 11861a51a1eeSmillert buf[--n] = '\0'; 11871a51a1eeSmillert break; 118814cc915fSmillert case '%': 118914cc915fSmillert buf[--n] = '\0'; 119014cc915fSmillert percent = strtod(buf, NULL) / 100.0; 11911e0ad43cSotto snprintf(buf, sizeof(buf), "%lld", 11921e0ad43cSotto DL_GETDSIZE(lp)); 119314cc915fSmillert break; 119414cc915fSmillert case '&': 119514cc915fSmillert buf[--n] = '\0'; 119614cc915fSmillert percent = strtod(buf, NULL) / 100.0; 11971e0ad43cSotto snprintf(buf, sizeof(buf), "%lld", 119814cc915fSmillert maxval); 119914cc915fSmillert break; 12006fe57b42Smillert } 120196a888c6Smillert } 12026fe57b42Smillert 12036fe57b42Smillert /* Did they give us an operator? */ 12046fe57b42Smillert p = &buf[0]; 12056fe57b42Smillert if (*p == '+' || *p == '-') 12066fe57b42Smillert operator = *p++; 12076fe57b42Smillert 12086fe57b42Smillert endptr = p; 120996a888c6Smillert errno = 0; 121096a888c6Smillert d = strtod(p, &endptr); 121196a888c6Smillert if (errno == ERANGE) 12121e0ad43cSotto rval = ULLONG_MAX; /* too big/small */ 121396a888c6Smillert else if (*endptr != '\0') { 12146fe57b42Smillert errno = EINVAL; /* non-numbers in str */ 12151e0ad43cSotto rval = ULLONG_MAX; 12166fe57b42Smillert } else { 121796a888c6Smillert /* XXX - should check for overflow */ 121896a888c6Smillert if (mult > 0) 121914cc915fSmillert rval = d * mult * percent; 122096a888c6Smillert else 122196a888c6Smillert /* Negative mult means divide (fancy) */ 122214cc915fSmillert rval = d / (-mult) * percent; 12236fe57b42Smillert 122496a888c6Smillert /* Apply the operator */ 12256fe57b42Smillert if (operator == '+') 12266fe57b42Smillert rval += oval; 12276fe57b42Smillert else if (operator == '-') 12286fe57b42Smillert rval = oval - rval; 12296fe57b42Smillert } 12306fe57b42Smillert } 12316fe57b42Smillert } 12328390cf28Smillert if ((flags & DO_ROUNDING) && rval != ULLONG_MAX) { 123396a888c6Smillert /* Round to nearest cylinder unless given in sectors */ 12348390cf28Smillert if ( 1235fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 1236fc1a4cc6Sderaadt ((lp->d_flags & D_VENDOR) || mult != 1) && 1237fc1a4cc6Sderaadt #else 12388390cf28Smillert mult != 1 && 1239dbffb156Smillert #endif 12408390cf28Smillert (rval + offset) % lp->d_secpercyl != 0) { 12411e0ad43cSotto u_int64_t cyls; 1242dbffb156Smillert 12438390cf28Smillert /* Round to higher cylinder but no more than maxval */ 12448390cf28Smillert cyls = (rval / lp->d_secpercyl) + 1; 12458390cf28Smillert if ((cyls * lp->d_secpercyl) - offset > maxval) 1246dbffb156Smillert cyls--; 12474b9a3bdaSmillert rval = (cyls * lp->d_secpercyl) - offset; 12488390cf28Smillert printf("Rounding to cylinder: %llu\n", rval); 12496fe57b42Smillert } 12504b9a3bdaSmillert } 12516fe57b42Smillert 12526fe57b42Smillert return(rval); 12536fe57b42Smillert } 12546fe57b42Smillert 12556fe57b42Smillert /* 12561f0f871dSkrw * Check for partition overlap in lp and prompt the user to resolve the overlap 12571f0f871dSkrw * if any is found. Returns 1 if unable to resolve, else 0. 12586fe57b42Smillert */ 12596fe57b42Smillert int 12601f0f871dSkrw has_overlap(struct disklabel *lp) 12616fe57b42Smillert { 12626fe57b42Smillert struct partition **spp; 1263e6aa8bafSmillert int c, i, j; 1264e6aa8bafSmillert char buf[BUFSIZ]; 12656fe57b42Smillert 12660fbd3c97Skrw /* Get a sorted list of the in-use partitions. */ 12670fbd3c97Skrw spp = sort_partitions(lp); 12686fe57b42Smillert 12690fbd3c97Skrw /* If there are less than two partitions in use, there is no overlap. */ 12700fbd3c97Skrw if (spp[1] == NULL) 12710fbd3c97Skrw return(0); 12726fe57b42Smillert 12736fe57b42Smillert /* Now that we have things sorted by starting sector check overlap */ 12740fbd3c97Skrw for (i = 0; spp[i] != NULL; i++) { 12750fbd3c97Skrw for (j = i + 1; spp[j] != NULL; j++) { 12766fe57b42Smillert /* `if last_sec_in_part + 1 > first_sec_in_next_part' */ 12771e0ad43cSotto if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) > DL_GETPOFFSET(spp[j])) { 12786fe57b42Smillert /* Overlap! Convert to real part numbers. */ 12796fe57b42Smillert i = ((char *)spp[i] - (char *)lp->d_partitions) 12806fe57b42Smillert / sizeof(**spp); 12816fe57b42Smillert j = ((char *)spp[j] - (char *)lp->d_partitions) 12826fe57b42Smillert / sizeof(**spp); 12836fe57b42Smillert printf("\nError, partitions %c and %c overlap:\n", 12846fe57b42Smillert 'a' + i, 'a' + j); 1285366bf641Skrw printf("# %16.16s %16.16s fstype " 1286651d5bd9Sotto "[fsize bsize cpg]\n", "size", "offset"); 128734ae4198Skrw display_partition(stdout, lp, i, 0); 128834ae4198Skrw display_partition(stdout, lp, j, 0); 12896fe57b42Smillert 1290e6aa8bafSmillert /* Get partition to disable or ^D */ 1291e6aa8bafSmillert do { 1292616cd1c4Smillert printf("Disable which one? (^D to abort) [%c %c] ", 12936fe57b42Smillert 'a' + i, 'a' + j); 1294e6aa8bafSmillert buf[0] = '\0'; 1295616cd1c4Smillert if (!fgets(buf, sizeof(buf), stdin)) { 1296616cd1c4Smillert putchar('\n'); 1297e6aa8bafSmillert return(1); /* ^D */ 1298616cd1c4Smillert } 1299e6aa8bafSmillert c = buf[0] - 'a'; 1300e6aa8bafSmillert } while (buf[1] != '\n' && buf[1] != '\0' && 1301e6aa8bafSmillert c != i && c != j); 1302e6aa8bafSmillert 1303e6aa8bafSmillert /* Mark the selected one as unused */ 13046fe57b42Smillert lp->d_partitions[c].p_fstype = FS_UNUSED; 13051f0f871dSkrw return (has_overlap(lp)); 13066fe57b42Smillert } 13076fe57b42Smillert } 13086fe57b42Smillert } 1309f0b4d0a9Smillert 1310e6aa8bafSmillert return(0); 13116fe57b42Smillert } 13126fe57b42Smillert 13136fe57b42Smillert void 13149fdcb4d6Skrw edit_parms(struct disklabel *lp) 13156fe57b42Smillert { 13166fe57b42Smillert char *p; 13179fdcb4d6Skrw u_int64_t freesectors, ui; 131896a888c6Smillert struct disklabel oldlabel = *lp; 13196fe57b42Smillert 1320ea37abd3Sderaadt printf("Changing device parameters for %s:\n", specname); 13216fe57b42Smillert 13220f820bbbSmillert /* disk type */ 13230f820bbbSmillert for (;;) { 1324c33fcabaSmillert p = getstring("disk type", 132541282a2aSmillert "What kind of disk is this? Usually SCSI, ESDI, ST506, or " 132641282a2aSmillert "floppy (use ESDI for IDE).", dktypenames[lp->d_type]); 132796a888c6Smillert if (p == NULL) { 132896a888c6Smillert fputs("Command aborted\n", stderr); 132996a888c6Smillert return; 133096a888c6Smillert } 133141282a2aSmillert if (strcasecmp(p, "IDE") == 0) 133241282a2aSmillert ui = DTYPE_ESDI; 133341282a2aSmillert else 133441282a2aSmillert for (ui = 1; ui < DKMAXTYPES && 133541282a2aSmillert strcasecmp(p, dktypenames[ui]); ui++) 13360f820bbbSmillert ; 13370f820bbbSmillert if (ui < DKMAXTYPES) { 13380f820bbbSmillert break; 13390f820bbbSmillert } else { 13400f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", p); 13410f820bbbSmillert fputs("Valid types are: ", stdout); 13420f820bbbSmillert for (ui = 1; ui < DKMAXTYPES; ui++) { 13430f820bbbSmillert printf("\"%s\"", dktypenames[ui]); 13440f820bbbSmillert if (ui < DKMAXTYPES - 1) 13450f820bbbSmillert fputs(", ", stdout); 13460f820bbbSmillert } 13470f820bbbSmillert putchar('\n'); 13480f820bbbSmillert } 13490f820bbbSmillert } 13500f820bbbSmillert lp->d_type = ui; 13510f820bbbSmillert 13526fe57b42Smillert /* pack/label id */ 1353c33fcabaSmillert p = getstring("label name", 13546fe57b42Smillert "15 char string that describes this label, usually the disk name.", 13556fe57b42Smillert lp->d_packname); 135696a888c6Smillert if (p == NULL) { 135796a888c6Smillert fputs("Command aborted\n", stderr); 135896a888c6Smillert *lp = oldlabel; /* undo damage */ 135996a888c6Smillert return; 136096a888c6Smillert } 13614fb6ab7cSmillert strncpy(lp->d_packname, p, sizeof(lp->d_packname)); /* checked */ 13626fe57b42Smillert 13636fe57b42Smillert /* sectors/track */ 13646fe57b42Smillert for (;;) { 1365dea75673Skrw ui = getuint(lp, "sectors/track", 1366cfd24250Skrw "The Number of sectors per track.", lp->d_nsectors, 13674b9a3bdaSmillert lp->d_nsectors, 0, 0); 13681e0ad43cSotto if (ui == ULLONG_MAX - 1) { 136996a888c6Smillert fputs("Command aborted\n", stderr); 137096a888c6Smillert *lp = oldlabel; /* undo damage */ 137196a888c6Smillert return; 13721e0ad43cSotto } if (ui == ULLONG_MAX) 13736fe57b42Smillert fputs("Invalid entry\n", stderr); 13746fe57b42Smillert else 13756fe57b42Smillert break; 13766fe57b42Smillert } 13776fe57b42Smillert lp->d_nsectors = ui; 13786fe57b42Smillert 13796fe57b42Smillert /* tracks/cylinder */ 13806fe57b42Smillert for (;;) { 1381dea75673Skrw ui = getuint(lp, "tracks/cylinder", 13826fe57b42Smillert "The number of tracks per cylinder.", lp->d_ntracks, 13834b9a3bdaSmillert lp->d_ntracks, 0, 0); 13841e0ad43cSotto if (ui == ULLONG_MAX - 1) { 138596a888c6Smillert fputs("Command aborted\n", stderr); 138696a888c6Smillert *lp = oldlabel; /* undo damage */ 138796a888c6Smillert return; 13881e0ad43cSotto } else if (ui == ULLONG_MAX) 13896fe57b42Smillert fputs("Invalid entry\n", stderr); 13906fe57b42Smillert else 13916fe57b42Smillert break; 13926fe57b42Smillert } 13936fe57b42Smillert lp->d_ntracks = ui; 13946fe57b42Smillert 13956fe57b42Smillert /* sectors/cylinder */ 1396148b6188Smillert for (;;) { 1397dea75673Skrw ui = getuint(lp, "sectors/cylinder", 1398148b6188Smillert "The number of sectors per cylinder (Usually sectors/track " 13994b9a3bdaSmillert "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl, 14004b9a3bdaSmillert 0, 0); 14011e0ad43cSotto if (ui == ULLONG_MAX - 1) { 140296a888c6Smillert fputs("Command aborted\n", stderr); 140396a888c6Smillert *lp = oldlabel; /* undo damage */ 140496a888c6Smillert return; 14051e0ad43cSotto } else if (ui == ULLONG_MAX) 1406148b6188Smillert fputs("Invalid entry\n", stderr); 1407148b6188Smillert else 1408148b6188Smillert break; 1409148b6188Smillert } 1410148b6188Smillert lp->d_secpercyl = ui; 14116fe57b42Smillert 14126fe57b42Smillert /* number of cylinders */ 14136fe57b42Smillert for (;;) { 1414dea75673Skrw ui = getuint(lp, "number of cylinders", 14156fe57b42Smillert "The total number of cylinders on the disk.", 14164b9a3bdaSmillert lp->d_ncylinders, lp->d_ncylinders, 0, 0); 14171e0ad43cSotto if (ui == ULLONG_MAX - 1) { 141896a888c6Smillert fputs("Command aborted\n", stderr); 141996a888c6Smillert *lp = oldlabel; /* undo damage */ 142096a888c6Smillert return; 14211e0ad43cSotto } else if (ui == ULLONG_MAX) 14226fe57b42Smillert fputs("Invalid entry\n", stderr); 14236fe57b42Smillert else 14246fe57b42Smillert break; 14256fe57b42Smillert } 14266fe57b42Smillert lp->d_ncylinders = ui; 14276fe57b42Smillert 14286fe57b42Smillert /* total sectors */ 14296fe57b42Smillert for (;;) { 143034af67a3Sotto u_int64_t nsec = MAX(DL_GETDSIZE(lp), 143134af67a3Sotto (u_int64_t)lp->d_ncylinders * lp->d_secpercyl); 1432dea75673Skrw ui = getuint(lp, "total sectors", 14336fe57b42Smillert "The total number of sectors on the disk.", 1434baaa8969Smillert nsec, nsec, 0, 0); 14351e0ad43cSotto if (ui == ULLONG_MAX - 1) { 143696a888c6Smillert fputs("Command aborted\n", stderr); 143796a888c6Smillert *lp = oldlabel; /* undo damage */ 143896a888c6Smillert return; 14391e0ad43cSotto } else if (ui == ULLONG_MAX) 14406fe57b42Smillert fputs("Invalid entry\n", stderr); 14411e0ad43cSotto else if (ui > DL_GETDSIZE(lp) && 14421e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 1443f98aebd4Smillert puts("You may want to increase the size of the 'c' " 1444f98aebd4Smillert "partition."); 14456fe57b42Smillert break; 14461e0ad43cSotto } else if (ui < DL_GETDSIZE(lp) && 14471e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 14486fe57b42Smillert /* shrink free count */ 14499fdcb4d6Skrw freesectors = editor_countfree(lp); 14509fdcb4d6Skrw if (DL_GETDSIZE(lp) - ui > freesectors) 14516fe57b42Smillert fprintf(stderr, 14521e0ad43cSotto "Not enough free space to shrink by %llu " 14531e0ad43cSotto "sectors (only %llu sectors left)\n", 14549fdcb4d6Skrw DL_GETDSIZE(lp) - ui, freesectors); 1455c4f83f03Skrw else 14566fe57b42Smillert break; 14576fe57b42Smillert } else 14586fe57b42Smillert break; 14596fe57b42Smillert } 146041ed49b7Smillert /* Adjust ending_sector if necessary. */ 146196a888c6Smillert if (ending_sector > ui) 146296a888c6Smillert ending_sector = ui; 14631e0ad43cSotto DL_SETDSIZE(lp, ui); 14646fe57b42Smillert } 1465a7e61405Smillert 1466a7e61405Smillert struct partition ** 14670fbd3c97Skrw sort_partitions(struct disklabel *lp) 1468a7e61405Smillert { 1469d18c2a43Skrw static struct partition *spp[MAXPARTITIONS+2]; 14700fbd3c97Skrw int i, npartitions; 1471a7e61405Smillert 1472d18c2a43Skrw memset(spp, 0, sizeof(spp)); 1473d18c2a43Skrw 1474a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1475a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1476a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 14771e0ad43cSotto DL_GETPSIZE(&lp->d_partitions[i]) != 0) 1478a7e61405Smillert spp[npartitions++] = &lp->d_partitions[i]; 1479a7e61405Smillert } 1480a7e61405Smillert 1481a7e61405Smillert /* 1482a7e61405Smillert * Sort the partitions based on starting offset. 1483a7e61405Smillert * This is safe because we guarantee no overlap. 1484a7e61405Smillert */ 1485a7e61405Smillert if (npartitions > 1) 1486a7e61405Smillert if (heapsort((void *)spp, npartitions, sizeof(spp[0]), 1487a7e61405Smillert partition_cmp)) 1488a7e61405Smillert err(4, "failed to sort partition table"); 1489a7e61405Smillert 1490a7e61405Smillert return(spp); 1491a7e61405Smillert } 14920f820bbbSmillert 14930f820bbbSmillert /* 14940f820bbbSmillert * Get a valid disk type if necessary. 14950f820bbbSmillert */ 14960f820bbbSmillert void 14978809fabbSderaadt getdisktype(struct disklabel *lp, char *banner, char *dev) 14980f820bbbSmillert { 14990f820bbbSmillert int i; 1500803ff7d5Smillert char *s, *def = "SCSI"; 1501803ff7d5Smillert struct dtypes { 1502803ff7d5Smillert char *dev; 1503803ff7d5Smillert char *type; 1504803ff7d5Smillert } dtypes[] = { 1505c33fcabaSmillert { "sd", "SCSI" }, 1506c33fcabaSmillert { "rz", "SCSI" }, 1507c33fcabaSmillert { "wd", "IDE" }, 1508c33fcabaSmillert { "fd", "FLOPPY" }, 1509c33fcabaSmillert { "xd", "SMD" }, 1510c33fcabaSmillert { "xy", "SMD" }, 1511c33fcabaSmillert { "hd", "HP-IB" }, 1512c33fcabaSmillert { "ccd", "CCD" }, 1513c33fcabaSmillert { "vnd", "VND" }, 1514c33fcabaSmillert { "svnd", "VND" }, 1515c33fcabaSmillert { NULL, NULL } 1516803ff7d5Smillert }; 1517803ff7d5Smillert 1518803ff7d5Smillert if ((s = basename(dev)) != NULL) { 1519803ff7d5Smillert if (*s == 'r') 1520803ff7d5Smillert s++; 1521803ff7d5Smillert i = strcspn(s, "0123456789"); 1522803ff7d5Smillert s[i] = '\0'; 1523803ff7d5Smillert dev = s; 1524803ff7d5Smillert for (i = 0; dtypes[i].dev != NULL; i++) { 1525803ff7d5Smillert if (strcmp(dev, dtypes[i].dev) == 0) { 1526803ff7d5Smillert def = dtypes[i].type; 1527803ff7d5Smillert break; 1528803ff7d5Smillert } 1529803ff7d5Smillert } 1530803ff7d5Smillert } 15310f820bbbSmillert 15320f820bbbSmillert if (lp->d_type > DKMAXTYPES || lp->d_type == 0) { 15330f820bbbSmillert puts(banner); 15340f820bbbSmillert puts("Possible values are:"); 1535eb5dd924Sderaadt printf("\"IDE\", "); 15360f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15370f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15380f820bbbSmillert if (i < DKMAXTYPES - 1) 15390f820bbbSmillert fputs(", ", stdout); 15400f820bbbSmillert } 15410f820bbbSmillert putchar('\n'); 15420f820bbbSmillert 15430f820bbbSmillert for (;;) { 1544c33fcabaSmillert s = getstring("Disk type", 1545803ff7d5Smillert "What kind of disk is this? Usually SCSI, IDE, " 1546803ff7d5Smillert "ESDI, CCD, ST506, or floppy.", def); 154796a888c6Smillert if (s == NULL) 154896a888c6Smillert continue; 15495b412421Smillert if (strcasecmp(s, "IDE") == 0) { 15505b412421Smillert lp->d_type = DTYPE_ESDI; 15515b412421Smillert return; 15525b412421Smillert } 15530f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) 15540f820bbbSmillert if (strcasecmp(s, dktypenames[i]) == 0) { 15550f820bbbSmillert lp->d_type = i; 15560f820bbbSmillert return; 15570f820bbbSmillert } 15580f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", s); 15590f820bbbSmillert fputs("Valid types are: ", stdout); 15600f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15610f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15620f820bbbSmillert if (i < DKMAXTYPES - 1) 15630f820bbbSmillert fputs(", ", stdout); 15640f820bbbSmillert } 15650f820bbbSmillert putchar('\n'); 15660f820bbbSmillert } 15670f820bbbSmillert } 15680f820bbbSmillert } 156996a888c6Smillert 157096a888c6Smillert /* 157196a888c6Smillert * Get beginning and ending sectors of the OpenBSD portion of the disk 157296a888c6Smillert * from the user. 157396a888c6Smillert */ 157496a888c6Smillert void 15759fdcb4d6Skrw set_bounds(struct disklabel *lp) 157696a888c6Smillert { 15771e0ad43cSotto u_int64_t ui, start_temp; 157896a888c6Smillert 157996a888c6Smillert /* Starting sector */ 158096a888c6Smillert do { 1581dea75673Skrw ui = getuint(lp, "Starting sector", 158296a888c6Smillert "The start of the OpenBSD portion of the disk.", 15831e0ad43cSotto starting_sector, DL_GETDSIZE(lp), 0, 0); 15841e0ad43cSotto if (ui == ULLONG_MAX - 1) { 158596a888c6Smillert fputs("Command aborted\n", stderr); 158696a888c6Smillert return; 158796a888c6Smillert } 15881e0ad43cSotto } while (ui >= DL_GETDSIZE(lp)); 158996a888c6Smillert start_temp = ui; 159096a888c6Smillert 15914793b14cSmillert /* Size */ 159296a888c6Smillert do { 1593dea75673Skrw ui = getuint(lp, "Size ('*' for entire disk)", 1594f98aebd4Smillert "The size of the OpenBSD portion of the disk ('*' for the " 1595f98aebd4Smillert "entire disk).", ending_sector - starting_sector, 15961e0ad43cSotto DL_GETDSIZE(lp) - start_temp, 0, 0); 15971e0ad43cSotto if (ui == ULLONG_MAX - 1) { 159896a888c6Smillert fputs("Command aborted\n", stderr); 159996a888c6Smillert return; 160096a888c6Smillert } 16011e0ad43cSotto } while (ui > DL_GETDSIZE(lp) - start_temp); 16024793b14cSmillert ending_sector = start_temp + ui; 160396a888c6Smillert starting_sector = start_temp; 160496a888c6Smillert } 160596a888c6Smillert 160696a888c6Smillert /* 16070d63cfbaSjsing * Allow user to interactively change disklabel UID. 16080d63cfbaSjsing */ 16090d63cfbaSjsing void 16100d63cfbaSjsing set_uid(struct disklabel *lp) 16110d63cfbaSjsing { 16120d63cfbaSjsing u_int uid[8]; 16130d63cfbaSjsing char *s; 16140d63cfbaSjsing int i; 16150d63cfbaSjsing 16160d63cfbaSjsing printf("The disklabel UID is currently: "); 16170d63cfbaSjsing uid_print(stdout, lp); 16180d63cfbaSjsing printf("\n"); 16190d63cfbaSjsing 16200d63cfbaSjsing do { 16210d63cfbaSjsing s = getstring("uid", "The disklabel UID, given as a 16 " 16220d63cfbaSjsing "character hexadecimal string.", NULL); 1623ce98d1aeShalex if (s == NULL || strlen(s) == 0) { 16240d63cfbaSjsing fputs("Command aborted\n", stderr); 16250d63cfbaSjsing return; 16260d63cfbaSjsing } 16270d63cfbaSjsing i = uid_parse(lp, s); 16280d63cfbaSjsing if (i != 0) 16290d63cfbaSjsing fputs("Invalid UID entered.\n", stderr); 16300d63cfbaSjsing } while (i != 0); 16310d63cfbaSjsing } 16320d63cfbaSjsing 16330d63cfbaSjsing /* 163496a888c6Smillert * Return a list of the "chunks" of free space available 163596a888c6Smillert */ 163696a888c6Smillert struct diskchunk * 16378809fabbSderaadt free_chunks(struct disklabel *lp) 163896a888c6Smillert { 163996a888c6Smillert struct partition **spp; 164096a888c6Smillert static struct diskchunk chunks[MAXPARTITIONS + 2]; 164199bd27d2Skrw u_int64_t start, stop; 164296a888c6Smillert int i, numchunks; 164396a888c6Smillert 16440fbd3c97Skrw /* Sort the in-use partitions based on offset */ 16450fbd3c97Skrw spp = sort_partitions(lp); 164696a888c6Smillert 164796a888c6Smillert /* If there are no partitions, it's all free. */ 16480fbd3c97Skrw if (spp[0] == NULL) { 16492d8451b0Smillert chunks[0].start = starting_sector; 165096a888c6Smillert chunks[0].stop = ending_sector; 165196a888c6Smillert chunks[1].start = chunks[1].stop = 0; 165296a888c6Smillert return(chunks); 165396a888c6Smillert } 165496a888c6Smillert 165596a888c6Smillert /* Find chunks of free space */ 165696a888c6Smillert numchunks = 0; 16570fbd3c97Skrw if (DL_GETPOFFSET(spp[0]) > starting_sector) { 16582d8451b0Smillert chunks[0].start = starting_sector; 16591e0ad43cSotto chunks[0].stop = DL_GETPOFFSET(spp[0]); 166096a888c6Smillert numchunks++; 166196a888c6Smillert } 16620fbd3c97Skrw for (i = 0; spp[i] != NULL; i++) { 166399bd27d2Skrw start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]); 1664aff3f969Sotto if (start < starting_sector) 1665aff3f969Sotto start = starting_sector; 1666aff3f969Sotto else if (start > ending_sector) 1667aff3f969Sotto start = ending_sector; 166899bd27d2Skrw if (spp[i + 1] != NULL) 166999bd27d2Skrw stop = DL_GETPOFFSET(spp[i+1]); 167099bd27d2Skrw else 167199bd27d2Skrw stop = ending_sector; 1672aff3f969Sotto if (stop < starting_sector) 1673aff3f969Sotto stop = starting_sector; 1674aff3f969Sotto else if (stop > ending_sector) 1675aff3f969Sotto stop = ending_sector; 167699bd27d2Skrw if (start < stop) { 167799bd27d2Skrw chunks[numchunks].start = start; 167899bd27d2Skrw chunks[numchunks].stop = stop; 167996a888c6Smillert numchunks++; 168096a888c6Smillert } 168196a888c6Smillert } 168296a888c6Smillert 168396a888c6Smillert /* Terminate and return */ 168496a888c6Smillert chunks[numchunks].start = chunks[numchunks].stop = 0; 168596a888c6Smillert return(chunks); 168696a888c6Smillert } 16874793b14cSmillert 16884793b14cSmillert void 168987023ed9Skrw find_bounds(struct disklabel *lp) 16904793b14cSmillert { 16916534e983Sderaadt starting_sector = DL_GETBSTART(lp); 16926534e983Sderaadt ending_sector = DL_GETBEND(lp); 1693b2d4a455Smiod 16946534e983Sderaadt if (ending_sector) { 169534ae4198Skrw if (verbose) 169634ae4198Skrw printf("Treating sectors %llu-%llu as the OpenBSD" 169734ae4198Skrw " portion of the disk.\nYou can use the 'b'" 169834ae4198Skrw " command to change this.\n\n", starting_sector, 169934ae4198Skrw ending_sector); 1700b2d4a455Smiod } else { 1701b2d4a455Smiod #if (NUMBOOT == 1) 1702d3f02056Smillert /* Boot blocks take up the first cylinder */ 1703d3f02056Smillert starting_sector = lp->d_secpercyl; 170434ae4198Skrw if (verbose) 170534ae4198Skrw printf("Reserving the first data cylinder for boot" 170634ae4198Skrw " blocks.\nYou can use the 'b' command to change" 170734ae4198Skrw " this.\n\n"); 17084793b14cSmillert #endif 17094793b14cSmillert } 1710b2d4a455Smiod } 1711c0bdc608Smillert 1712c0bdc608Smillert /* 1713c0bdc608Smillert * Calculate free space. 1714c0bdc608Smillert */ 17159fdcb4d6Skrw u_int64_t 17169fdcb4d6Skrw editor_countfree(struct disklabel *lp) 1717c0bdc608Smillert { 1718d93cb2bbSkrw struct diskchunk *chunks; 17199fdcb4d6Skrw u_int64_t freesectors = 0; 1720c0bdc608Smillert int i; 1721c0bdc608Smillert 1722d93cb2bbSkrw chunks = free_chunks(lp); 1723509930fbSotto 1724d93cb2bbSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) 17259fdcb4d6Skrw freesectors += chunks[i].stop - chunks[i].start; 17269fdcb4d6Skrw 17279fdcb4d6Skrw return (freesectors); 1728c0bdc608Smillert } 1729617e6e4aSmillert 1730617e6e4aSmillert void 17314d812bb6Slum editor_help(void) 1732617e6e4aSmillert { 1733617e6e4aSmillert puts("Available commands:"); 1734617e6e4aSmillert puts( 17354d812bb6Slum " ? | h - show help n [part] - set mount point\n" 173649159a67Skrw " A - auto partition all space p [unit] - print partitions\n" 173749159a67Skrw " a [part] - add partition q - quit & save changes\n" 17386aaa4aabSotto " b - set OpenBSD boundaries R [part] - resize a partition\n" 173949159a67Skrw " c [part] - change partition size r - display free space\n" 17406aaa4aabSotto " D - reset label to default s [path] - save label to file\n" 17416aaa4aabSotto " d [part] - delete partition U - undo all changes\n" 17426aaa4aabSotto " e - edit drive parameters u - undo last change\n" 17436aaa4aabSotto " g [d|u] - [d]isk or [u]ser geometry w - write label to disk\n" 17440d63cfbaSjsing " i - modify disklabel UID X - toggle expert mode\n" 17450d63cfbaSjsing " l [unit] - print disk label header x - exit & lose changes\n" 17460d63cfbaSjsing " M - disklabel(8) man page z - delete all partitions\n" 17470d63cfbaSjsing " m [part] - modify partition\n" 1748c4884206Skrw "\n" 1749c4884206Skrw "Suffixes can be used to indicate units other than sectors:\n" 1750c4884206Skrw "\t'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes)\n" 1751c4884206Skrw "\t'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n" 1752c4884206Skrw "Values in non-sector units are truncated to the nearest cylinder boundary."); 17534d812bb6Slum 1754617e6e4aSmillert } 1755bd6726faSmillert 17564f3bbbf0Skrw void 17578809fabbSderaadt mpcopy(char **to, char **from) 1758bd6726faSmillert { 1759bd6726faSmillert int i; 17600612d09dSderaadt char *top; 1761bd6726faSmillert 1762bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1763bd6726faSmillert if (from[i] != NULL) { 1764dcab0d16Sderaadt int len = strlen(from[i]) + 1; 1765dcab0d16Sderaadt 17660612d09dSderaadt top = realloc(to[i], len); 17670612d09dSderaadt if (top == NULL) 1768bd6726faSmillert errx(4, "out of memory"); 17690612d09dSderaadt to[i] = top; 1770dcab0d16Sderaadt (void)strlcpy(to[i], from[i], len); 1771bd6726faSmillert } else if (to[i] != NULL) { 1772bd6726faSmillert free(to[i]); 1773bd6726faSmillert to[i] = NULL; 1774bd6726faSmillert } 1775bd6726faSmillert } 1776bd6726faSmillert } 1777bd6726faSmillert 1778bd6726faSmillert int 17798809fabbSderaadt mpequal(char **mp1, char **mp2) 1780bd6726faSmillert { 1781bd6726faSmillert int i; 1782bd6726faSmillert 1783bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1784bd6726faSmillert if (mp1[i] == NULL && mp2[i] == NULL) 1785bd6726faSmillert continue; 1786bd6726faSmillert 1787bd6726faSmillert if ((mp1[i] != NULL && mp2[i] == NULL) || 1788bd6726faSmillert (mp1[i] == NULL && mp2[i] != NULL) || 1789bd6726faSmillert (strcmp(mp1[i], mp2[i]) != 0)) 1790bd6726faSmillert return(0); 1791bd6726faSmillert } 1792bd6726faSmillert return(1); 1793bd6726faSmillert } 1794bd6726faSmillert 179593160b9bSkrw void 179634ae4198Skrw mpsave(struct disklabel *lp) 1797bd6726faSmillert { 1798d8b446ceSderaadt int i, j; 1799bd6726faSmillert char bdev[MAXPATHLEN], *p; 18003f843443Smillert struct mountinfo mi[MAXPARTITIONS]; 1801bd6726faSmillert FILE *fp; 1802bd6726faSmillert 180393160b9bSkrw if (!fstabfile) 180493160b9bSkrw return; 180593160b9bSkrw 18063f843443Smillert memset(&mi, 0, sizeof(mi)); 18073f843443Smillert 1808d8b446ceSderaadt for (i = 0; i < MAXPARTITIONS; i++) { 180934ae4198Skrw if (mountpoints[i] != NULL) { 181034ae4198Skrw mi[i].mountpoint = mountpoints[i]; 18113f843443Smillert mi[i].partno = i; 1812bd6726faSmillert } 1813bd6726faSmillert } 1814bd6726faSmillert 181534ae4198Skrw /* Convert specname to bdev */ 181634ae4198Skrw if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 && 181734ae4198Skrw specname[sizeof(_PATH_DEV) - 1] == 'r') { 1818bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV, 181934ae4198Skrw &specname[sizeof(_PATH_DEV)]); 1820bd6726faSmillert } else { 182134ae4198Skrw if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r') 182293160b9bSkrw return; 1823bd6726faSmillert *p = '\0'; 182434ae4198Skrw snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1); 1825bd6726faSmillert *p = 'r'; 1826bd6726faSmillert } 1827bd6726faSmillert bdev[strlen(bdev) - 1] = '\0'; 1828bd6726faSmillert 18293f843443Smillert /* Sort mountpoints so we don't try to mount /usr/local before /usr */ 18303f843443Smillert qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp); 18313f843443Smillert 183293160b9bSkrw if (fp = fopen(fstabfile, "w")) { 183393160b9bSkrw for (i = 0; i < MAXPARTITIONS && mi[i].mountpoint; i++) { 18345fea0b85Smillert j = mi[i].partno; 18355fea0b85Smillert fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 'a' + j, 18363f843443Smillert mi[i].mountpoint, 18375fea0b85Smillert fstypesnames[lp->d_partitions[j].p_fstype], 18385fea0b85Smillert j == 0 ? 1 : 2); 1839bd6726faSmillert } 1840bd6726faSmillert fclose(fp); 184193160b9bSkrw } 1842bd6726faSmillert } 184324a2c1a4Smillert 184424a2c1a4Smillert int 1845604d3bdeSkrw get_offset(struct disklabel *lp, int partno) 184624a2c1a4Smillert { 1847604d3bdeSkrw struct diskchunk *chunks; 184824a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 184915c15d8aSkrw u_int64_t ui, maxsize; 1850604d3bdeSkrw int i, fstype; 185124a2c1a4Smillert 1852dea75673Skrw ui = getuint(lp, "offset", 18531e0ad43cSotto "Starting sector for this partition.", 18541e0ad43cSotto DL_GETPOFFSET(pp), 18551e0ad43cSotto DL_GETPOFFSET(pp), 0, DO_CONVERSIONS | 185624a2c1a4Smillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 1857e9ff19beSkrw 1858e9ff19beSkrw if (ui == ULLONG_MAX - 1) 185924a2c1a4Smillert fputs("Command aborted\n", stderr); 1860e9ff19beSkrw else if (ui == ULLONG_MAX) 186124a2c1a4Smillert fputs("Invalid entry\n", stderr); 186240e98e9fSkrw else if (ui < starting_sector || ui >= ending_sector) 1863e9ff19beSkrw fprintf(stderr, "The offset must be >= %llu and < %llu, " 1864e9ff19beSkrw "the limits of the OpenBSD portion\n" 1865e9ff19beSkrw "of the disk. The 'b' command can change these limits.\n", 186640e98e9fSkrw starting_sector, ending_sector); 1867fc1a4cc6Sderaadt #ifdef SUN_AAT0 186849bf537cSderaadt else if (partno == 0 && ui != 0) 186949bf537cSderaadt fprintf(stderr, "This architecture requires that " 187040f544cdSderaadt "partition 'a' start at sector 0.\n"); 187149bf537cSderaadt #endif 187215c15d8aSkrw else { 1873604d3bdeSkrw fstype = pp->p_fstype; 1874604d3bdeSkrw pp->p_fstype = FS_UNUSED; 1875604d3bdeSkrw chunks = free_chunks(lp); 1876604d3bdeSkrw pp->p_fstype = fstype; 1877e9ff19beSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 1878e9ff19beSkrw if (ui < chunks[i].start || ui >= chunks[i].stop) 187915c15d8aSkrw continue; 18801e0ad43cSotto DL_SETPOFFSET(pp, ui); 188115c15d8aSkrw maxsize = chunks[i].stop - DL_GETPOFFSET(pp); 188215c15d8aSkrw if (DL_GETPSIZE(pp) > maxsize) 188315c15d8aSkrw DL_SETPSIZE(pp, maxsize); 188424a2c1a4Smillert return (0); 188524a2c1a4Smillert } 188615c15d8aSkrw fputs("The offset must be in a free area.\n", stderr); 188715c15d8aSkrw } 1888e9ff19beSkrw 1889e9ff19beSkrw /* Partition offset was not set. */ 1890e9ff19beSkrw return (1); 189115c15d8aSkrw } 189224a2c1a4Smillert 189324a2c1a4Smillert int 18949fdcb4d6Skrw get_size(struct disklabel *lp, int partno) 189524a2c1a4Smillert { 189624a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 189714192793Skrw u_int64_t maxsize, ui; 189814192793Skrw 189914192793Skrw maxsize = max_partition_size(lp, partno); 190024a2c1a4Smillert 1901dea75673Skrw ui = getuint(lp, "size", "Size of the partition. " 19027da73705Skrw "You may also say +/- amount for a relative change.", 190314192793Skrw DL_GETPSIZE(pp), maxsize, DL_GETPOFFSET(pp), 1904525051f1Sotto DO_CONVERSIONS | ((pp->p_fstype == FS_BSDFFS || 1905525051f1Sotto pp->p_fstype == FS_SWAP) ? DO_ROUNDING : 0)); 1906e9ff19beSkrw 1907e9ff19beSkrw if (ui == ULLONG_MAX - 1) 190824a2c1a4Smillert fputs("Command aborted\n", stderr); 1909e9ff19beSkrw else if (ui == ULLONG_MAX) 191024a2c1a4Smillert fputs("Invalid entry\n", stderr); 191128e3704eSkrw else if (ui == 0) 191228e3704eSkrw fputs("The size must be > 0\n", stderr); 191340e98e9fSkrw else if (ui + DL_GETPOFFSET(pp) > ending_sector) 191440e98e9fSkrw fprintf(stderr, "The size can't be more than " 191540e98e9fSkrw "%llu sectors, or the partition would\n" 191640e98e9fSkrw "extend beyond the last sector (%llu) of the " 191740e98e9fSkrw "OpenBSD portion of\nthe disk. " 191840e98e9fSkrw "The 'b' command can change this limit.\n", 191940e98e9fSkrw ending_sector - DL_GETPOFFSET(pp), ending_sector); 192014192793Skrw else if (ui > maxsize) 192114192793Skrw fprintf(stderr,"Sorry, there are only %llu sectors left\n", 192214192793Skrw maxsize); 192359ccf790Skrw else { 192459ccf790Skrw DL_SETPSIZE(pp, ui); 192524a2c1a4Smillert return (0); 192624a2c1a4Smillert } 1927e9ff19beSkrw 1928e9ff19beSkrw /* Partition size was not set. */ 1929e9ff19beSkrw return (1); 1930e9ff19beSkrw } 193124a2c1a4Smillert 193224a2c1a4Smillert int 19338809fabbSderaadt get_fsize(struct disklabel *lp, int partno) 193424a2c1a4Smillert { 19351e0ad43cSotto u_int64_t ui, fsize, frag; 193624a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 193724a2c1a4Smillert 1938a4c87e64Skrw if (!expert || pp->p_fstype != FS_BSDFFS) 1939a4c87e64Skrw return (0); 1940a4c87e64Skrw 1941ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 1942ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 1943ddfcbf38Sotto if (fsize == 0) 1944ddfcbf38Sotto frag = 8; 1945ddfcbf38Sotto 194624a2c1a4Smillert for (;;) { 1947dea75673Skrw ui = getuint(lp, "fragment size", 19483c92d7f2Stedu "Size of fs block fragments. Usually 2048 or 512.", 1949ddfcbf38Sotto fsize, fsize, 0, 0); 19501e0ad43cSotto if (ui == ULLONG_MAX - 1) { 195124a2c1a4Smillert fputs("Command aborted\n", stderr); 195224a2c1a4Smillert return(1); 19531e0ad43cSotto } else if (ui == ULLONG_MAX) 195424a2c1a4Smillert fputs("Invalid entry\n", stderr); 195524a2c1a4Smillert else 195624a2c1a4Smillert break; 195724a2c1a4Smillert } 195824a2c1a4Smillert if (ui == 0) 195924a2c1a4Smillert puts("Zero fragment size implies zero block size"); 1960ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag); 196124a2c1a4Smillert return(0); 196224a2c1a4Smillert } 196324a2c1a4Smillert 196424a2c1a4Smillert int 19658809fabbSderaadt get_bsize(struct disklabel *lp, int partno) 196624a2c1a4Smillert { 1967*a49bdda8Skrw u_int64_t adj, ui, bsize, frag, fsize; 196824a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 196924a2c1a4Smillert 1970*a49bdda8Skrw if (pp->p_fstype != FS_BSDFFS) 1971a4c87e64Skrw return (0); 1972a4c87e64Skrw 197324a2c1a4Smillert /* Avoid dividing by zero... */ 1974ddfcbf38Sotto if (pp->p_fragblock == 0) 197524a2c1a4Smillert return(1); 1976ddfcbf38Sotto 1977*a49bdda8Skrw if (!expert) 1978*a49bdda8Skrw goto align; 1979*a49bdda8Skrw 1980ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 1981ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 198224a2c1a4Smillert 198324a2c1a4Smillert for (;;) { 1984dea75673Skrw ui = getuint(lp, "block size", 19853c92d7f2Stedu "Size of filesystem blocks. Usually 16384 or 4096.", 1986ddfcbf38Sotto fsize * frag, fsize * frag, 198724a2c1a4Smillert 0, 0); 198824a2c1a4Smillert 198924a2c1a4Smillert /* sanity checks */ 19901e0ad43cSotto if (ui == ULLONG_MAX - 1) { 199124a2c1a4Smillert fputs("Command aborted\n", stderr); 199224a2c1a4Smillert return(1); 19931e0ad43cSotto } else if (ui == ULLONG_MAX) 199424a2c1a4Smillert fputs("Invalid entry\n", stderr); 199524a2c1a4Smillert else if (ui < getpagesize()) 199624a2c1a4Smillert fprintf(stderr, 199724a2c1a4Smillert "Error: block size must be at least as big " 199824a2c1a4Smillert "as page size (%d).\n", getpagesize()); 1999ddfcbf38Sotto else if (ui % fsize != 0) 200024a2c1a4Smillert fputs("Error: block size must be a multiple of the " 200124a2c1a4Smillert "fragment size.\n", stderr); 2002ddfcbf38Sotto else if (ui / fsize < 1) 200324a2c1a4Smillert fputs("Error: block size must be at least as big as " 200424a2c1a4Smillert "fragment size.\n", stderr); 200524a2c1a4Smillert else 200624a2c1a4Smillert break; 200724a2c1a4Smillert } 2008ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui / frag, frag); 2009*a49bdda8Skrw 2010*a49bdda8Skrw align: 2011*a49bdda8Skrw #ifndef SUN_CYLCHECK 2012*a49bdda8Skrw bsize = (DISKLABELV1_FFS_FRAG(pp->p_fragblock) * 2013*a49bdda8Skrw DISKLABELV1_FFS_FSIZE(pp->p_fragblock)) / lp->d_secsize; 2014*a49bdda8Skrw if (DL_GETPOFFSET(pp) != starting_sector) { 2015*a49bdda8Skrw /* Can't change offset of first partition. */ 2016*a49bdda8Skrw adj = bsize - (DL_GETPOFFSET(pp) % bsize); 2017*a49bdda8Skrw if (adj != 0 && adj != bsize) { 2018*a49bdda8Skrw DL_SETPOFFSET(pp, DL_GETPOFFSET(pp) + adj); 2019*a49bdda8Skrw DL_SETPSIZE(pp, DL_GETPSIZE(pp) - adj); 2020*a49bdda8Skrw } 2021*a49bdda8Skrw } 2022*a49bdda8Skrw /* Always align end. */ 2023*a49bdda8Skrw adj = (DL_GETPOFFSET(pp) + DL_GETPSIZE(pp)) % bsize; 2024*a49bdda8Skrw if (adj > 0) 2025*a49bdda8Skrw DL_SETPSIZE(pp, DL_GETPSIZE(pp) - adj); 2026*a49bdda8Skrw #endif 202724a2c1a4Smillert return(0); 202824a2c1a4Smillert } 202924a2c1a4Smillert 203024a2c1a4Smillert int 20318809fabbSderaadt get_fstype(struct disklabel *lp, int partno) 203224a2c1a4Smillert { 203324a2c1a4Smillert char *p; 20341e0ad43cSotto u_int64_t ui; 203524a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 203624a2c1a4Smillert 203724a2c1a4Smillert if (pp->p_fstype < FSMAXTYPES) { 2038c33fcabaSmillert p = getstring("FS type", 203924a2c1a4Smillert "Filesystem type (usually 4.2BSD or swap)", 204024a2c1a4Smillert fstypenames[pp->p_fstype]); 204124a2c1a4Smillert if (p == NULL) { 204224a2c1a4Smillert fputs("Command aborted\n", stderr); 204324a2c1a4Smillert return(1); 204424a2c1a4Smillert } 204524a2c1a4Smillert for (ui = 0; ui < FSMAXTYPES; ui++) { 204624a2c1a4Smillert if (!strcasecmp(p, fstypenames[ui])) { 204724a2c1a4Smillert pp->p_fstype = ui; 204824a2c1a4Smillert break; 204924a2c1a4Smillert } 205024a2c1a4Smillert } 205124a2c1a4Smillert if (ui >= FSMAXTYPES) { 205224a2c1a4Smillert printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p); 205324a2c1a4Smillert pp->p_fstype = FS_OTHER; 205424a2c1a4Smillert } 205524a2c1a4Smillert } else { 205624a2c1a4Smillert for (;;) { 2057dea75673Skrw ui = getuint(lp, "FS type (decimal)", 205824a2c1a4Smillert "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", 205924a2c1a4Smillert pp->p_fstype, pp->p_fstype, 0, 0); 20601e0ad43cSotto if (ui == ULLONG_MAX - 1) { 206124a2c1a4Smillert fputs("Command aborted\n", stderr); 206224a2c1a4Smillert return(1); 20631e0ad43cSotto } if (ui == ULLONG_MAX) 206424a2c1a4Smillert fputs("Invalid entry\n", stderr); 206524a2c1a4Smillert else 206624a2c1a4Smillert break; 206724a2c1a4Smillert } 206824a2c1a4Smillert pp->p_fstype = ui; 206924a2c1a4Smillert } 207024a2c1a4Smillert return(0); 207124a2c1a4Smillert } 207224a2c1a4Smillert 207324a2c1a4Smillert int 207434ae4198Skrw get_mp(struct disklabel *lp, int partno) 207524a2c1a4Smillert { 207624a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 2077ec9fde5fSkrw char *p; 2078ec9fde5fSkrw int i; 207924a2c1a4Smillert 208034ae4198Skrw if (fstabfile && pp->p_fstype != FS_UNUSED && 208124a2c1a4Smillert pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT && 208224a2c1a4Smillert pp->p_fstype != FS_OTHER) { 2083ddaff619Smillert for (;;) { 2084c33fcabaSmillert p = getstring("mount point", 208524a2c1a4Smillert "Where to mount this filesystem (ie: / /var /usr)", 208634ae4198Skrw mountpoints[partno] ? mountpoints[partno] : "none"); 208724a2c1a4Smillert if (p == NULL) { 208824a2c1a4Smillert fputs("Command aborted\n", stderr); 208924a2c1a4Smillert return(1); 209024a2c1a4Smillert } 2091ddaff619Smillert if (strcasecmp(p, "none") == 0) { 209234ae4198Skrw free(mountpoints[partno]); 209334ae4198Skrw mountpoints[partno] = NULL; 2094ddaff619Smillert break; 2095ddaff619Smillert } 2096ec9fde5fSkrw for (i = 0; i < MAXPARTITIONS; i++) 209793160b9bSkrw if (mountpoints[i] != NULL && i != partno && 2098ec9fde5fSkrw strcmp(p, mountpoints[i]) == 0) 2099ec9fde5fSkrw break; 2100ec9fde5fSkrw if (i < MAXPARTITIONS) { 210193160b9bSkrw fprintf(stderr, "'%c' already being mounted at " 210293160b9bSkrw "'%s'\n", 'a'+i, p); 2103ec9fde5fSkrw break; 2104ec9fde5fSkrw } 2105ddaff619Smillert if (*p == '/') { 2106ddaff619Smillert /* XXX - might as well realloc */ 210734ae4198Skrw free(mountpoints[partno]); 210834ae4198Skrw if ((mountpoints[partno] = strdup(p)) == NULL) 210924a2c1a4Smillert errx(4, "out of memory"); 2110ddaff619Smillert break; 2111ddaff619Smillert } 2112ddaff619Smillert fputs("Mount points must start with '/'\n", stderr); 211324a2c1a4Smillert } 211424a2c1a4Smillert } 211524a2c1a4Smillert return(0); 211624a2c1a4Smillert } 21173f843443Smillert 21183f843443Smillert int 21198809fabbSderaadt micmp(const void *a1, const void *a2) 21203f843443Smillert { 21213f843443Smillert struct mountinfo *mi1 = (struct mountinfo *)a1; 21223f843443Smillert struct mountinfo *mi2 = (struct mountinfo *)a2; 21233f843443Smillert 21243f843443Smillert /* We want all the NULLs at the end... */ 21253f843443Smillert if (mi1->mountpoint == NULL && mi2->mountpoint == NULL) 21263f843443Smillert return(0); 21273f843443Smillert else if (mi1->mountpoint == NULL) 21283f843443Smillert return(1); 21293f843443Smillert else if (mi2->mountpoint == NULL) 21303f843443Smillert return(-1); 21313f843443Smillert else 21323f843443Smillert return(strcmp(mi1->mountpoint, mi2->mountpoint)); 21333f843443Smillert } 2134c33fcabaSmillert 2135c33fcabaSmillert void 213687023ed9Skrw get_geometry(int f, struct disklabel **dgpp) 2137c33fcabaSmillert { 2138c33fcabaSmillert struct stat st; 2139c33fcabaSmillert struct disklabel *disk_geop; 214087023ed9Skrw 2141c33fcabaSmillert if (fstat(f, &st) == -1) 2142c33fcabaSmillert err(4, "Can't stat device"); 2143c33fcabaSmillert 2144c33fcabaSmillert /* Get disk geometry */ 2145c33fcabaSmillert if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL) 2146c33fcabaSmillert errx(4, "out of memory"); 2147c33fcabaSmillert if (ioctl(f, DIOCGPDINFO, disk_geop) < 0 && 2148c33fcabaSmillert ioctl(f, DIOCGDINFO, disk_geop) < 0) 2149c33fcabaSmillert err(4, "ioctl DIOCGDINFO"); 2150c33fcabaSmillert *dgpp = disk_geop; 2151c33fcabaSmillert } 2152c33fcabaSmillert 2153c33fcabaSmillert void 21548809fabbSderaadt set_geometry(struct disklabel *lp, struct disklabel *dgp, 215587023ed9Skrw struct disklabel *ugp, char *p) 2156c33fcabaSmillert { 2157c33fcabaSmillert if (p == NULL) { 21589a36aa41Ssthen p = getstring("[d]isk or [u]ser geometry", 2159c33fcabaSmillert "Enter 'd' to use the geometry based on what the disk " 21609a36aa41Ssthen "itself thinks it is, or 'u' to use the geometry that " 21619a36aa41Ssthen "was found in the label.", 2162c33fcabaSmillert "d"); 2163c33fcabaSmillert } 2164c33fcabaSmillert if (p == NULL) { 2165c33fcabaSmillert fputs("Command aborted\n", stderr); 2166c33fcabaSmillert return; 2167c33fcabaSmillert } 2168c33fcabaSmillert switch (*p) { 2169c33fcabaSmillert case 'd': 2170c33fcabaSmillert case 'D': 2171c33fcabaSmillert if (dgp == NULL) 2172c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2173c33fcabaSmillert else { 2174c33fcabaSmillert lp->d_secsize = dgp->d_secsize; 2175c33fcabaSmillert lp->d_nsectors = dgp->d_nsectors; 2176c33fcabaSmillert lp->d_ntracks = dgp->d_ntracks; 2177c33fcabaSmillert lp->d_ncylinders = dgp->d_ncylinders; 2178c33fcabaSmillert lp->d_secpercyl = dgp->d_secpercyl; 217934af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(dgp)); 2180c33fcabaSmillert } 2181c33fcabaSmillert break; 2182c33fcabaSmillert case 'u': 2183c33fcabaSmillert case 'U': 2184c33fcabaSmillert if (ugp == NULL) 2185c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2186c33fcabaSmillert else { 2187c33fcabaSmillert lp->d_secsize = ugp->d_secsize; 2188c33fcabaSmillert lp->d_nsectors = ugp->d_nsectors; 2189c33fcabaSmillert lp->d_ntracks = ugp->d_ntracks; 2190c33fcabaSmillert lp->d_ncylinders = ugp->d_ncylinders; 2191c33fcabaSmillert lp->d_secpercyl = ugp->d_secpercyl; 219234af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(ugp)); 2193c33fcabaSmillert if (dgp != NULL && ugp->d_secsize == dgp->d_secsize && 2194c33fcabaSmillert ugp->d_nsectors == dgp->d_nsectors && 2195c33fcabaSmillert ugp->d_ntracks == dgp->d_ntracks && 2196c33fcabaSmillert ugp->d_ncylinders == dgp->d_ncylinders && 2197c33fcabaSmillert ugp->d_secpercyl == dgp->d_secpercyl && 219834af67a3Sotto DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp)) 2199c33fcabaSmillert fputs("Note: user geometry is the same as disk " 2200c33fcabaSmillert "geometry.\n", stderr); 2201c33fcabaSmillert } 2202c33fcabaSmillert break; 2203c33fcabaSmillert default: 22049a36aa41Ssthen fputs("You must enter either 'd' or 'u'.\n", stderr); 2205c33fcabaSmillert break; 2206c33fcabaSmillert } 2207c33fcabaSmillert } 22089afbe9eeSmillert 22099afbe9eeSmillert void 22109fdcb4d6Skrw zero_partitions(struct disklabel *lp) 22119afbe9eeSmillert { 22129afbe9eeSmillert int i; 22139afbe9eeSmillert 2214b4ed6301Skrw for (i = 0; i < MAXPARTITIONS; i++) { 22159afbe9eeSmillert memset(&lp->d_partitions[i], 0, sizeof(struct partition)); 2216b4ed6301Skrw free(mountpoints[i]); 2217b4ed6301Skrw mountpoints[i] = NULL; 2218b4ed6301Skrw } 2219b4ed6301Skrw 222034af67a3Sotto DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); 22219afbe9eeSmillert } 222214192793Skrw 222314192793Skrw u_int64_t 222414192793Skrw max_partition_size(struct disklabel *lp, int partno) 222514192793Skrw { 222614192793Skrw struct partition *pp = &lp->d_partitions[partno]; 222714192793Skrw struct diskchunk *chunks; 222844ffe03bSotto u_int64_t maxsize = 0, offset; 222914192793Skrw int fstype, i; 223014192793Skrw 223114192793Skrw fstype = pp->p_fstype; 223214192793Skrw pp->p_fstype = FS_UNUSED; 223314192793Skrw chunks = free_chunks(lp); 223414192793Skrw pp->p_fstype = fstype; 223514192793Skrw 223614192793Skrw offset = DL_GETPOFFSET(pp); 223714192793Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 223814192793Skrw if (offset < chunks[i].start || offset >= chunks[i].stop) 223914192793Skrw continue; 224014192793Skrw maxsize = chunks[i].stop - offset; 224114192793Skrw break; 224214192793Skrw } 224314192793Skrw return (maxsize); 224414192793Skrw } 2245aff3f969Sotto 2246aff3f969Sotto void 2247aff3f969Sotto psize(daddr64_t sz, char unit, struct disklabel *lp) 2248aff3f969Sotto { 2249aff3f969Sotto double d = scale(sz, unit, lp); 2250aff3f969Sotto if (d < 0) 2251aff3f969Sotto printf("%llu", sz); 2252aff3f969Sotto else 2253aff3f969Sotto printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit); 2254aff3f969Sotto } 2255aff3f969Sotto 2256aff3f969Sotto void 225734ae4198Skrw display_edit(struct disklabel *lp, char unit, u_int64_t fr) 2258aff3f969Sotto { 2259aff3f969Sotto int i; 2260aff3f969Sotto 2261352d199bSkrw unit = canonical_unit(lp, unit); 2262aff3f969Sotto 2263aff3f969Sotto printf("OpenBSD area: "); 226459882f1dSkrw psize(starting_sector, 0, lp); 2265aff3f969Sotto printf("-"); 226659882f1dSkrw psize(ending_sector, 0, lp); 2267aff3f969Sotto printf("; size: "); 2268aff3f969Sotto psize(ending_sector - starting_sector, unit, lp); 2269aff3f969Sotto printf("; free: "); 2270aff3f969Sotto psize(fr, unit, lp); 2271aff3f969Sotto 2272aff3f969Sotto printf("\n# %16.16s %16.16s fstype [fsize bsize cpg]\n", 2273aff3f969Sotto "size", "offset"); 2274aff3f969Sotto for (i = 0; i < lp->d_npartitions; i++) 227534ae4198Skrw display_partition(stdout, lp, i, unit); 2276aff3f969Sotto } 2277aff3f969Sotto 2278