1*d7878011Sderaadt /* $OpenBSD: editor.c,v 1.259 2011/10/06 21:16:01 deraadt 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" }, 802cb42124Sotto { GIG(1), GIG(2), 2, "/usr/src" }, 81001bee15Sotto #ifdef STATICLINKING 82001bee15Sotto { MEG(2600), GIG(3), 4, "/usr/obj" }, 83001bee15Sotto #else 842cb42124Sotto { MEG(1300), GIG(2), 4, "/usr/obj" }, 85001bee15Sotto #endif 866e1f4775Sotto { GIG(1), GIG(300), 45, "/home" } 874ab111d2Sderaadt /* Anything beyond this leave for the user to decide */ 888dde8bb6Sotto }; 898dde8bb6Sotto 908dde8bb6Sotto const struct space_allocation alloc_medium[] = { 91905e8239Sderaadt { MEG(800), GIG(2), 5, "/" }, 928dde8bb6Sotto { MEG(80), MEG(256), 10, "swap" }, 93905e8239Sderaadt { MEG(900), GIG(3), 78, "/usr" }, 94905e8239Sderaadt { MEG(256), GIG(2), 7, "/home" } 958dde8bb6Sotto }; 968dde8bb6Sotto 978dde8bb6Sotto const struct space_allocation alloc_small[] = { 9892adb55fSderaadt { MEG(700), GIG(4), 95, "/" }, 998dde8bb6Sotto { MEG(1), MEG(256), 5, "swap" } 1008dde8bb6Sotto }; 1018dde8bb6Sotto 1028dde8bb6Sotto const struct space_allocation alloc_stupid[] = { 1038dde8bb6Sotto { MEG(1), MEG(2048), 100, "/" } 1048dde8bb6Sotto }; 1058dde8bb6Sotto 106b2813ff1Sderaadt #ifndef nitems 107b2813ff1Sderaadt #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 108b2813ff1Sderaadt #endif 109b2813ff1Sderaadt 1108a862940Sderaadt const struct { 1118a862940Sderaadt const struct space_allocation *table; 1128a862940Sderaadt int sz; 1138a862940Sderaadt } alloc_table[] = { 1148dde8bb6Sotto { alloc_big, nitems(alloc_big) }, 1158dde8bb6Sotto { alloc_medium, nitems(alloc_medium) }, 1168dde8bb6Sotto { alloc_small, nitems(alloc_small) }, 1178dde8bb6Sotto { alloc_stupid, nitems(alloc_stupid) } 118557f712bSkrw }; 119557f712bSkrw 1209fdcb4d6Skrw void edit_parms(struct disklabel *); 1216aaa4aabSotto void editor_resize(struct disklabel *, char *); 12234ae4198Skrw void editor_add(struct disklabel *, char *); 1239fdcb4d6Skrw void editor_change(struct disklabel *, char *); 1249fdcb4d6Skrw u_int64_t editor_countfree(struct disklabel *); 12534ae4198Skrw void editor_delete(struct disklabel *, char *); 1264d812bb6Slum void editor_help(void); 12734ae4198Skrw void editor_modify(struct disklabel *, char *); 12834ae4198Skrw void editor_name(struct disklabel *, char *); 129c72b5b24Smillert char *getstring(char *, char *, char *); 130dea75673Skrw u_int64_t getuint(struct disklabel *, char *, char *, u_int64_t, u_int64_t, u_int64_t, int); 1311f0f871dSkrw int has_overlap(struct disklabel *); 132c72b5b24Smillert int partition_cmp(const void *, const void *); 1330fbd3c97Skrw struct partition **sort_partitions(struct disklabel *); 134c72b5b24Smillert void getdisktype(struct disklabel *, char *, char *); 13587023ed9Skrw void find_bounds(struct disklabel *); 1369fdcb4d6Skrw void set_bounds(struct disklabel *); 13769a6ffbcSjsing void set_duid(struct disklabel *); 138c72b5b24Smillert struct diskchunk *free_chunks(struct disklabel *); 1394f3bbbf0Skrw void mpcopy(char **, char **); 140c72b5b24Smillert int micmp(const void *, const void *); 141c72b5b24Smillert int mpequal(char **, char **); 142c72b5b24Smillert int get_bsize(struct disklabel *, int); 143c72b5b24Smillert int get_fsize(struct disklabel *, int); 144c72b5b24Smillert int get_fstype(struct disklabel *, int); 14534ae4198Skrw int get_mp(struct disklabel *, int); 146604d3bdeSkrw int get_offset(struct disklabel *, int); 1479fdcb4d6Skrw int get_size(struct disklabel *, int); 14887023ed9Skrw void get_geometry(int, struct disklabel **); 14987023ed9Skrw void set_geometry(struct disklabel *, struct disklabel *, struct disklabel *, 15087023ed9Skrw char *); 1519fdcb4d6Skrw void zero_partitions(struct disklabel *); 15214192793Skrw u_int64_t max_partition_size(struct disklabel *, int); 15334ae4198Skrw void display_edit(struct disklabel *, char, u_int64_t); 15496a888c6Smillert 1551e0ad43cSotto static u_int64_t starting_sector; 1561e0ad43cSotto static u_int64_t ending_sector; 1572d8451b0Smillert static int expert; 158fc6e9c48Sotto static int overlap; 1596fe57b42Smillert 1606fe57b42Smillert /* 1614d4a335eSkrw * Simple partition editor. 1626fe57b42Smillert */ 1636fe57b42Smillert int 164d6d80bb0Skrw editor(int f) 1656fe57b42Smillert { 166d6d80bb0Skrw struct disklabel origlabel, lastlabel, tmplabel, newlab = lab; 1677e28fb0fSderaadt struct disklabel *disk_geop = NULL; 16896a888c6Smillert struct partition *pp; 1696fe57b42Smillert FILE *fp; 1706fe57b42Smillert char buf[BUFSIZ], *cmd, *arg; 17134ae4198Skrw char **omountpoints = NULL; 1724f3bbbf0Skrw char **origmountpoints = NULL, **tmpmountpoints = NULL; 1737e28fb0fSderaadt int i, error = 0; 174bd6726faSmillert 175bd6726faSmillert /* Alloc and init mount point info */ 17634ae4198Skrw if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 1774f3bbbf0Skrw !(origmountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 178bd6726faSmillert !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *)))) 179bd6726faSmillert errx(4, "out of memory"); 1806fe57b42Smillert 18196a888c6Smillert /* Don't allow disk type of "unknown" */ 182d6d80bb0Skrw getdisktype(&newlab, "You need to specify a type for this disk.", specname); 1836fe57b42Smillert 18487023ed9Skrw /* Get the on-disk geometries if possible */ 18587023ed9Skrw get_geometry(f, &disk_geop); 186c33fcabaSmillert 187d09f3941Smillert /* How big is the OpenBSD portion of the disk? */ 188d6d80bb0Skrw find_bounds(&newlab); 189d09f3941Smillert 19096a888c6Smillert /* Make sure there is no partition overlap. */ 191d6d80bb0Skrw if (has_overlap(&newlab)) 1926fe57b42Smillert errx(1, "can't run when there is partition overlap."); 1936fe57b42Smillert 19496a888c6Smillert /* If we don't have a 'c' partition, create one. */ 195d6d80bb0Skrw pp = &newlab.d_partitions[RAW_PART]; 196d6d80bb0Skrw if (newlab.d_npartitions < 3 || DL_GETPSIZE(pp) == 0) { 19796a888c6Smillert puts("No 'c' partition found, adding one that spans the disk."); 198d6d80bb0Skrw if (newlab.d_npartitions < 3) 199d6d80bb0Skrw newlab.d_npartitions = 3; 20034af67a3Sotto DL_SETPOFFSET(pp, 0); 201d6d80bb0Skrw DL_SETPSIZE(pp, DL_GETDSIZE(&newlab)); 20296a888c6Smillert pp->p_fstype = FS_UNUSED; 203ddfcbf38Sotto pp->p_fragblock = pp->p_cpg = 0; 20496a888c6Smillert } 2050f820bbbSmillert 206fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 207d6d80bb0Skrw if (newlab.d_flags & D_VENDOR) { 208fc1a4cc6Sderaadt puts("This platform requires that partition offsets/sizes " 209fc1a4cc6Sderaadt "be on cylinder boundaries.\n" 210fc1a4cc6Sderaadt "Partition offsets/sizes will be rounded to the " 211fc1a4cc6Sderaadt "nearest cylinder automatically."); 212fc1a4cc6Sderaadt } 2136fe57b42Smillert #endif 2146fe57b42Smillert 215bd6726faSmillert /* Set d_bbsize and d_sbsize as necessary */ 216d6d80bb0Skrw if (newlab.d_bbsize == 0) 217d6d80bb0Skrw newlab.d_bbsize = BBSIZE; 218d6d80bb0Skrw if (newlab.d_sbsize == 0) 219d6d80bb0Skrw newlab.d_sbsize = SBSIZE; 220f98aebd4Smillert 22193160b9bSkrw /* Save the (U|u)ndo labels and mountpoints. */ 22293160b9bSkrw mpcopy(origmountpoints, mountpoints); 223d6d80bb0Skrw origlabel = newlab; 224d6d80bb0Skrw lastlabel = newlab; 22534ae4198Skrw 22634ae4198Skrw puts("Label editor (enter '?' for help at any prompt)"); 2276fe57b42Smillert for (;;) { 2286fe57b42Smillert fputs("> ", stdout); 2296e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 2306e0becc5Smillert putchar('\n'); 2316e0becc5Smillert buf[0] = 'q'; 2326e0becc5Smillert buf[1] = '\0'; 2336e0becc5Smillert } 234260513deSmillert if ((cmd = strtok(buf, " \t\r\n")) == NULL) 235260513deSmillert continue; 236260513deSmillert arg = strtok(NULL, " \t\r\n"); 2376fe57b42Smillert 2384f3bbbf0Skrw if ((*cmd != 'u') && (*cmd != 'U')) { 2394f3bbbf0Skrw /* 2404f3bbbf0Skrw * Save undo info in case the command tries to make 2414f3bbbf0Skrw * changes but decides not to. 2424f3bbbf0Skrw */ 2434f3bbbf0Skrw tmplabel = lastlabel; 244d6d80bb0Skrw lastlabel = newlab; 2454f3bbbf0Skrw mpcopy(tmpmountpoints, omountpoints); 2464f3bbbf0Skrw mpcopy(omountpoints, mountpoints); 2474f3bbbf0Skrw } 2486fe57b42Smillert 2494f3bbbf0Skrw switch (*cmd) { 2506fe57b42Smillert case '?': 251ea37abd3Sderaadt case 'h': 2524d812bb6Slum editor_help(); 2536fe57b42Smillert break; 2546fe57b42Smillert 255557f712bSkrw case 'A': 256d6d80bb0Skrw if (ioctl(f, DIOCGPDINFO, &newlab) == 0) { 257ab20a3eaSkrw aflag = 1; 258d6d80bb0Skrw editor_allocspace(&newlab); 259ab20a3eaSkrw } else 260d6d80bb0Skrw newlab = lastlabel; 261557f712bSkrw break; 2626fe57b42Smillert case 'a': 263d6d80bb0Skrw editor_add(&newlab, arg); 26496a888c6Smillert break; 26596a888c6Smillert 26696a888c6Smillert case 'b': 267d6d80bb0Skrw set_bounds(&newlab); 2686fe57b42Smillert break; 2696fe57b42Smillert 2706fe57b42Smillert case 'c': 271d6d80bb0Skrw editor_change(&newlab, arg); 2726fe57b42Smillert break; 2736fe57b42Smillert 2749afbe9eeSmillert case 'D': 275d6d80bb0Skrw if (ioctl(f, DIOCGPDINFO, &newlab) == 0) { 27671bba4ecSkrw dflag = 1; 27793160b9bSkrw for (i=0; i<MAXPARTITIONS; i++) { 27893160b9bSkrw free(mountpoints[i]); 27993160b9bSkrw mountpoints[i] = NULL; 28093160b9bSkrw } 28193160b9bSkrw } else 282cdd7eb76Smillert warn("unable to get default partition table"); 2839afbe9eeSmillert break; 2849afbe9eeSmillert 2856fe57b42Smillert case 'd': 286d6d80bb0Skrw editor_delete(&newlab, arg); 2876fe57b42Smillert break; 2886fe57b42Smillert 2899afbe9eeSmillert case 'e': 290d6d80bb0Skrw edit_parms(&newlab); 2919afbe9eeSmillert break; 2929afbe9eeSmillert 293c33fcabaSmillert case 'g': 294d6d80bb0Skrw set_geometry(&newlab, disk_geop, &lab, arg); 295c33fcabaSmillert break; 296c33fcabaSmillert 2970d63cfbaSjsing case 'i': 298d6d80bb0Skrw set_duid(&newlab); 2990d63cfbaSjsing break; 3000d63cfbaSjsing 3016fe57b42Smillert case 'm': 302d6d80bb0Skrw editor_modify(&newlab, arg); 303bd6726faSmillert break; 304bd6726faSmillert 305bd6726faSmillert case 'n': 3065c79e1cfSkrw if (!fstabfile) { 307bd6726faSmillert fputs("This option is not valid when run " 30884d0bb16Sderaadt "without the -f flag.\n", stderr); 309bd6726faSmillert break; 310bd6726faSmillert } 311d6d80bb0Skrw editor_name(&newlab, arg); 3126fe57b42Smillert break; 3136fe57b42Smillert 3146fe57b42Smillert case 'p': 315d6d80bb0Skrw display_edit(&newlab, arg ? *arg : 0, 316d6d80bb0Skrw editor_countfree(&newlab)); 3176fe57b42Smillert break; 3186fe57b42Smillert 319aff3f969Sotto case 'l': 320d6d80bb0Skrw display(stdout, &newlab, arg ? *arg : 0, 0); 321aff3f969Sotto break; 322aff3f969Sotto 323508086e9Smillert case 'M': { 324508086e9Smillert sig_t opipe = signal(SIGPIPE, SIG_IGN); 32545decb36Sderaadt char *pager, *comm = NULL; 326e7936562Sderaadt extern const u_char manpage[]; 32708f8e31fSotto extern const int manpage_sz; 3285d12b01bSderaadt 329489bd112Spjanzen if ((pager = getenv("PAGER")) == NULL || *pager == '\0') 330508086e9Smillert pager = _PATH_LESS; 33108f8e31fSotto 33245decb36Sderaadt if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 && 33345decb36Sderaadt (fp = popen(comm, "w")) != NULL) { 33408f8e31fSotto (void) fwrite(manpage, manpage_sz, 1, fp); 3355d12b01bSderaadt pclose(fp); 336508086e9Smillert } else 337508086e9Smillert warn("unable to execute %s", pager); 338508086e9Smillert 33945decb36Sderaadt free(comm); 340508086e9Smillert (void)signal(SIGPIPE, opipe); 3415d12b01bSderaadt break; 342508086e9Smillert } 3435d12b01bSderaadt 3446fe57b42Smillert case 'q': 34569220492Smillert if (donothing) { 34669220492Smillert puts("In no change mode, not writing label."); 3477e28fb0fSderaadt goto done; 34869220492Smillert } 34993160b9bSkrw 35071bba4ecSkrw /* 35193160b9bSkrw * If we haven't changed the original label, and it 35293160b9bSkrw * wasn't a default label or an auto-allocated label, 35393160b9bSkrw * there is no need to do anything before exiting. Note 35493160b9bSkrw * that 'w' will reset dflag and aflag to allow 'q' to 35593160b9bSkrw * exit without further questions. 35671bba4ecSkrw */ 357ab20a3eaSkrw if (!dflag && !aflag && 358d6d80bb0Skrw memcmp(&lab, &newlab, sizeof(newlab)) == 0) { 359bd6726faSmillert puts("No label changes."); 360d6d80bb0Skrw /* Save mountpoint info. */ 361d6d80bb0Skrw mpsave(&newlab); 3627e28fb0fSderaadt goto done; 3636fe57b42Smillert } 3646fe57b42Smillert do { 365d0e67762Smillert arg = getstring("Write new label?", 366d0e67762Smillert "Write the modified label to disk?", 367d0e67762Smillert "y"); 36896a888c6Smillert } while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n'); 36996a888c6Smillert if (arg && tolower(*arg) == 'y') { 370d6d80bb0Skrw if (writelabel(f, bootarea, &newlab) == 0) { 371d6d80bb0Skrw newlab = lab; /* lab now has UID info */ 3727e28fb0fSderaadt goto done; 3736fe57b42Smillert } 374d0e67762Smillert warnx("unable to write label"); 375d0e67762Smillert } 3767e28fb0fSderaadt error = 1; 3777e28fb0fSderaadt goto done; 3786fe57b42Smillert /* NOTREACHED */ 3796fe57b42Smillert break; 3806fe57b42Smillert 3816aaa4aabSotto case 'R': 382fc6e9c48Sotto if (aflag && !overlap) 383d6d80bb0Skrw editor_resize(&newlab, arg); 3846aaa4aabSotto else 3856aaa4aabSotto fputs("Resize only implemented for auto " 386fc6e9c48Sotto "allocated labels\n", stderr); 3876aaa4aabSotto break; 3886aaa4aabSotto 38925f9c360Skrw case 'r': { 39025f9c360Skrw struct diskchunk *chunks; 39125f9c360Skrw int i; 3929fdcb4d6Skrw /* Display free space. */ 393d6d80bb0Skrw chunks = free_chunks(&newlab); 39425f9c360Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; 39525f9c360Skrw i++) 39625f9c360Skrw fprintf(stderr, "Free sectors: %16llu - %16llu " 39725f9c360Skrw "(%16llu)\n", 39825f9c360Skrw chunks[i].start, chunks[i].stop - 1, 39925f9c360Skrw chunks[i].stop - chunks[i].start); 40025f9c360Skrw fprintf(stderr, "Total free sectors: %llu.\n", 401d6d80bb0Skrw editor_countfree(&newlab)); 402c0bdc608Smillert break; 40325f9c360Skrw } 404c0bdc608Smillert 4056fe57b42Smillert case 's': 4066fe57b42Smillert if (arg == NULL) { 407c33fcabaSmillert arg = getstring("Filename", 4086fe57b42Smillert "Name of the file to save label into.", 4096fe57b42Smillert NULL); 410e97229a3Scnst if (arg == NULL || *arg == '\0') 4116fe57b42Smillert break; 4126fe57b42Smillert } 4136fe57b42Smillert if ((fp = fopen(arg, "w")) == NULL) { 4146fe57b42Smillert warn("cannot open %s", arg); 4156fe57b42Smillert } else { 416d6d80bb0Skrw display(fp, &newlab, 0, 1); 4176fe57b42Smillert (void)fclose(fp); 4186fe57b42Smillert } 4196fe57b42Smillert break; 4206fe57b42Smillert 4214f3bbbf0Skrw case 'U': 42293160b9bSkrw /* 42393160b9bSkrw * If we allow 'U' repeatedly, information would be lost. This way 42493160b9bSkrw * multiple 'U's followed by 'u' would undo the 'U's. 42593160b9bSkrw */ 426d6d80bb0Skrw if (memcmp(&newlab, &origlabel, sizeof(newlab)) || 42793160b9bSkrw !mpequal(mountpoints, origmountpoints)) { 428d6d80bb0Skrw tmplabel = newlab; 429d6d80bb0Skrw newlab = origlabel; 4304f3bbbf0Skrw lastlabel = tmplabel; 4314f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 4324f3bbbf0Skrw mpcopy(mountpoints, origmountpoints); 4334f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4344f3bbbf0Skrw } 43593160b9bSkrw puts("Original label and mount points restored."); 4364f3bbbf0Skrw break; 4374f3bbbf0Skrw 4386fe57b42Smillert case 'u': 439d6d80bb0Skrw tmplabel = newlab; 440d6d80bb0Skrw newlab = lastlabel; 4416fe57b42Smillert lastlabel = tmplabel; 4424f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 443bd6726faSmillert mpcopy(mountpoints, omountpoints); 4444f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4456fe57b42Smillert puts("Last change undone."); 4466fe57b42Smillert break; 4476fe57b42Smillert 448040947cfSmillert case 'w': 449bd6726faSmillert if (donothing) { 450040947cfSmillert puts("In no change mode, not writing label."); 451bd6726faSmillert break; 452bd6726faSmillert } 45393160b9bSkrw 45441f684b9Skrw /* Write label to disk. */ 455d6d80bb0Skrw if (writelabel(f, bootarea, &newlab) != 0) 456040947cfSmillert warnx("unable to write label"); 45771bba4ecSkrw else { 458ab20a3eaSkrw dflag = aflag = 0; 459d6d80bb0Skrw newlab = lab; /* lab now has UID info */ 46071bba4ecSkrw } 461040947cfSmillert break; 462040947cfSmillert 4632d8451b0Smillert case 'X': 4642d8451b0Smillert expert = !expert; 4652d8451b0Smillert printf("%s expert mode\n", expert ? "Entering" : 4662d8451b0Smillert "Exiting"); 4672d8451b0Smillert break; 4682d8451b0Smillert 4696fe57b42Smillert case 'x': 4707e28fb0fSderaadt goto done; 4716fe57b42Smillert break; 4726fe57b42Smillert 4739afbe9eeSmillert case 'z': 474d6d80bb0Skrw zero_partitions(&newlab); 4756fe57b42Smillert break; 4766fe57b42Smillert 4779afbe9eeSmillert case '\n': 4786fe57b42Smillert break; 4796fe57b42Smillert 4806fe57b42Smillert default: 4816fe57b42Smillert printf("Unknown option: %c ('?' for help)\n", *cmd); 4826fe57b42Smillert break; 4836fe57b42Smillert } 4844f3bbbf0Skrw 4854f3bbbf0Skrw /* 4864f3bbbf0Skrw * If no changes were made to label or mountpoints, then 4874f3bbbf0Skrw * restore undo info. 4884f3bbbf0Skrw */ 489d6d80bb0Skrw if (memcmp(&newlab, &lastlabel, sizeof(newlab)) == 0 && 49093160b9bSkrw (mpequal(mountpoints, omountpoints))) { 4914f3bbbf0Skrw lastlabel = tmplabel; 4924f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4934f3bbbf0Skrw } 4946fe57b42Smillert } 4957e28fb0fSderaadt done: 4967e28fb0fSderaadt free(omountpoints); 4977e28fb0fSderaadt free(origmountpoints); 4987e28fb0fSderaadt free(tmpmountpoints); 4997e28fb0fSderaadt if (disk_geop) 5007e28fb0fSderaadt free(disk_geop); 5017e28fb0fSderaadt return(error); 5026fe57b42Smillert } 5036fe57b42Smillert 5048dde8bb6Sotto int64_t 5058dde8bb6Sotto getphysmem(void) 5068dde8bb6Sotto { 5078dde8bb6Sotto int64_t physmem; 5088dde8bb6Sotto size_t sz = sizeof(physmem); 5098dde8bb6Sotto int mib[] = { CTL_HW, HW_PHYSMEM64 }; 5108dde8bb6Sotto if (sysctl(mib, 2, &physmem, &sz, NULL, (size_t)0) == -1) 5118dde8bb6Sotto errx(4, "can't get mem size"); 5128dde8bb6Sotto return physmem; 5138dde8bb6Sotto } 5148dde8bb6Sotto 5156fe57b42Smillert /* 516557f712bSkrw * Allocate all disk space according to standard recommendations for a 517557f712bSkrw * root disk. 518557f712bSkrw */ 519557f712bSkrw void 5208dde8bb6Sotto editor_allocspace(struct disklabel *lp_org) 521557f712bSkrw { 5228dde8bb6Sotto struct disklabel *lp, label; 5238dde8bb6Sotto struct space_allocation *alloc; 52434ae4198Skrw struct space_allocation *ap; 525557f712bSkrw struct partition *pp; 52634ae4198Skrw struct diskchunk *chunks; 52734ae4198Skrw daddr64_t secs, chunkstart, chunksize, cylsecs, totsecs, xtrasecs; 52834ae4198Skrw char **partmp; 529a49bdda8Skrw int i, j, lastalloc, index = 0, fragsize, partno; 5308dde8bb6Sotto int64_t physmem; 5318dde8bb6Sotto 53234ae4198Skrw /* How big is the OpenBSD portion of the disk? */ 5338dde8bb6Sotto find_bounds(lp_org); 534557f712bSkrw 535fc6e9c48Sotto overlap = 0; 536fc6e9c48Sotto for (i = 0; i < MAXPARTITIONS; i++) { 537fc6e9c48Sotto daddr64_t psz, pstart, pend; 538fc6e9c48Sotto 539fc6e9c48Sotto pp = &lp_org->d_partitions[i]; 540fc6e9c48Sotto psz = DL_GETPSIZE(pp); 541fc6e9c48Sotto pstart = DL_GETPOFFSET(pp); 542fc6e9c48Sotto pend = pstart + psz; 543fc6e9c48Sotto if (i != RAW_PART && psz != 0 && 544fc6e9c48Sotto ((pstart >= starting_sector && pstart <= ending_sector) || 545fc6e9c48Sotto (pend > starting_sector && pend < ending_sector))) { 546fc6e9c48Sotto overlap = 1; 547fc6e9c48Sotto break; 548fc6e9c48Sotto } 549fc6e9c48Sotto } 550fc6e9c48Sotto 551fc6e9c48Sotto physmem = getphysmem() / lp_org->d_secsize; 552fc6e9c48Sotto 5538dde8bb6Sotto cylsecs = lp_org->d_secpercyl; 5548dde8bb6Sotto again: 5558dde8bb6Sotto lp = &label; 5563d98fc8cSkrw for (i=0; i<MAXPARTITIONS; i++) { 5573d98fc8cSkrw free(mountpoints[i]); 5583d98fc8cSkrw mountpoints[i] = NULL; 5593d98fc8cSkrw } 5608dde8bb6Sotto memcpy(lp, lp_org, sizeof(struct disklabel)); 5610a7398ceSderaadt lp->d_npartitions = MAXPARTITIONS; 5628dde8bb6Sotto lastalloc = alloc_table[index].sz; 5638dde8bb6Sotto alloc = malloc(lastalloc * sizeof(struct space_allocation)); 5648dde8bb6Sotto if (alloc == NULL) 5658dde8bb6Sotto errx(4, "out of memory"); 5668dde8bb6Sotto memcpy(alloc, alloc_table[index].table, 5678dde8bb6Sotto lastalloc * sizeof(struct space_allocation)); 5688dde8bb6Sotto 5698dde8bb6Sotto /* bump max swap based on phys mem, little physmem gets 2x swap */ 5708dde8bb6Sotto if (index == 0) { 5718dde8bb6Sotto if (physmem < 256LL * 1024 * 1024 / lp->d_secsize) 5728dde8bb6Sotto alloc[1].maxsz = 2 * physmem; 5738dde8bb6Sotto else 5748dde8bb6Sotto alloc[1].maxsz += physmem; 5758dde8bb6Sotto /* bump max /var to make room for 2 crash dumps */ 5768dde8bb6Sotto alloc[3].maxsz += 2 * physmem; 5778dde8bb6Sotto } 5788dde8bb6Sotto 57934ae4198Skrw xtrasecs = totsecs = editor_countfree(lp); 580557f712bSkrw 58134ae4198Skrw for (i = 0; i < lastalloc; i++) { 5825f3e1104Skrw alloc[i].minsz = DL_BLKTOSEC(lp, alloc[i].minsz); 5835f3e1104Skrw alloc[i].maxsz = DL_BLKTOSEC(lp, alloc[i].maxsz); 58434ae4198Skrw if (xtrasecs > alloc[i].minsz) 58534ae4198Skrw xtrasecs -= alloc[i].minsz; 58634ae4198Skrw else 58734ae4198Skrw xtrasecs = 0; 588557f712bSkrw } 589557f712bSkrw 59034ae4198Skrw for (i = 0; i < lastalloc; i++) { 59134ae4198Skrw /* Find next available partition. */ 59234ae4198Skrw for (j = 0; j < MAXPARTITIONS; j++) 59334ae4198Skrw if (DL_GETPSIZE(&lp->d_partitions[j]) == 0) 59434ae4198Skrw break; 595a243d7b5Skrw if (j == MAXPARTITIONS) { 596a243d7b5Skrw /* It did not work out, try next strategy */ 597a243d7b5Skrw free(alloc); 598a243d7b5Skrw if (++index < nitems(alloc_table)) 599a243d7b5Skrw goto again; 600a243d7b5Skrw else 60134ae4198Skrw return; 602a243d7b5Skrw } 603a49bdda8Skrw partno = j; 60434ae4198Skrw pp = &lp->d_partitions[j]; 60534ae4198Skrw partmp = &mountpoints[j]; 60634ae4198Skrw ap = &alloc[i]; 607557f712bSkrw 60834ae4198Skrw /* Figure out the size of the partition. */ 60934ae4198Skrw if (i == lastalloc - 1) { 61034ae4198Skrw if (totsecs > ap->maxsz) 61134ae4198Skrw secs = ap->maxsz; 612557f712bSkrw else 6135f3e1104Skrw secs = totsecs; 6141f5ea549Skrw #ifdef SUN_CYLCHECK 6151f5ea549Skrw goto cylinderalign; 6161f5ea549Skrw #endif 617557f712bSkrw } else { 61834ae4198Skrw secs = ap->minsz; 6195f3e1104Skrw if (xtrasecs > 0) 62034ae4198Skrw secs += (xtrasecs / 100) * ap->rate; 62134ae4198Skrw if (secs > ap->maxsz) 62234ae4198Skrw secs = ap->maxsz; 6231f5ea549Skrw #ifdef SUN_CYLCHECK 6241f5ea549Skrw cylinderalign: 6255f3e1104Skrw secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; 6261f5ea549Skrw #endif 6275f3e1104Skrw totsecs -= secs; 6281f5ea549Skrw #ifdef SUN_CYLCHECK 6295f3e1104Skrw while (totsecs < 0) { 6305f3e1104Skrw secs -= cylsecs; 6315f3e1104Skrw totsecs += cylsecs; 632557f712bSkrw } 6331f5ea549Skrw #endif 634557f712bSkrw } 63534ae4198Skrw 63634ae4198Skrw /* Find largest chunk of free space. */ 63734ae4198Skrw chunks = free_chunks(lp); 63834ae4198Skrw chunkstart = 0; 63934ae4198Skrw chunksize = 0; 64034ae4198Skrw for (j = 0; chunks[j].start != 0 || chunks[j].stop != 0; j++) 64134ae4198Skrw if ((chunks[j].stop - chunks[j].start) > chunksize) { 64234ae4198Skrw chunkstart = chunks[j].start; 64334ae4198Skrw chunksize = chunks[j].stop - chunks[j].start; 644557f712bSkrw } 64534ae4198Skrw #ifdef SUN_CYLCHECK 64634ae4198Skrw if (lp->d_flags & D_VENDOR) { 64734ae4198Skrw /* Align chunk to cylinder boundaries. */ 64834ae4198Skrw chunksize -= chunksize % cylsecs; 6496ab0bb66Skrw chunkstart = ((chunkstart + cylsecs - 1) / cylsecs) * 6506ab0bb66Skrw cylsecs; 65134ae4198Skrw } 65234ae4198Skrw #endif 65334ae4198Skrw /* See if partition can fit into chunk. */ 65434ae4198Skrw if (secs > chunksize) { 65534ae4198Skrw totsecs += secs - chunksize; 65634ae4198Skrw secs = chunksize; 65734ae4198Skrw } 65834ae4198Skrw if (secs < ap->minsz) { 6598dde8bb6Sotto /* It did not work out, try next strategy */ 6608dde8bb6Sotto free(alloc); 6618dde8bb6Sotto if (++index < nitems(alloc_table)) 6628dde8bb6Sotto goto again; 6638dde8bb6Sotto else 6648dde8bb6Sotto return; 665557f712bSkrw } 66634ae4198Skrw 66734ae4198Skrw /* Everything seems ok so configure the partition. */ 6685f3e1104Skrw DL_SETPSIZE(pp, secs); 66934ae4198Skrw DL_SETPOFFSET(pp, chunkstart); 670ef93a5eeSkrw fragsize = (lp->d_secsize == DEV_BSIZE) ? 2048 : 671ef93a5eeSkrw lp->d_secsize; 672c88f83bdSotto if (secs * lp->d_secsize > 128ULL * 1024 * 1024 * 1024) 673c88f83bdSotto fragsize *= 2; 674c88f83bdSotto if (secs * lp->d_secsize > 512ULL * 1024 * 1024 * 1024) 675c88f83bdSotto fragsize *= 2; 676557f712bSkrw #if defined (__sparc__) && !defined(__sparc64__) 677557f712bSkrw /* can't boot from > 8k boot blocks */ 678557f712bSkrw pp->p_fragblock = 6796e312d52Sotto DISKLABELV1_FFS_FRAGBLOCK(i == 0 ? 1024 : fragsize, 8); 680557f712bSkrw #else 6816e312d52Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8); 682557f712bSkrw #endif 683557f712bSkrw pp->p_cpg = 1; 68434ae4198Skrw if (ap->mp[0] != '/') 68534ae4198Skrw pp->p_fstype = FS_SWAP; 68634ae4198Skrw else { 68734ae4198Skrw pp->p_fstype = FS_BSDFFS; 688a49bdda8Skrw get_bsize(lp, partno); 68934ae4198Skrw free(*partmp); 69034ae4198Skrw if ((*partmp = strdup(ap->mp)) == NULL) 691557f712bSkrw errx(4, "out of memory"); 692557f712bSkrw } 693557f712bSkrw } 694557f712bSkrw 6958dde8bb6Sotto free(alloc); 6968dde8bb6Sotto memcpy(lp_org, lp, sizeof(struct disklabel)); 697557f712bSkrw } 698557f712bSkrw 699557f712bSkrw /* 7006aaa4aabSotto * Resize a partition, moving all subsequent partitions 7016aaa4aabSotto */ 7026aaa4aabSotto void 7036aaa4aabSotto editor_resize(struct disklabel *lp, char *p) 7046aaa4aabSotto { 7056aaa4aabSotto struct disklabel label; 7066aaa4aabSotto struct partition *pp, *prev; 7076aaa4aabSotto daddr64_t secs, sz, off; 7086aaa4aabSotto #ifdef SUN_CYLCHECK 7096aaa4aabSotto daddr64_t cylsecs; 7106aaa4aabSotto #endif 7116aaa4aabSotto int partno, i; 7126aaa4aabSotto 7136aaa4aabSotto label = *lp; 7146aaa4aabSotto 7156aaa4aabSotto /* Change which partition? */ 7166aaa4aabSotto if (p == NULL) { 7176aaa4aabSotto p = getstring("partition to resize", 7186aaa4aabSotto "The letter of the partition to name, a - p.", NULL); 7196aaa4aabSotto } 7206aaa4aabSotto if (p == NULL) { 7216aaa4aabSotto fputs("Command aborted\n", stderr); 7226aaa4aabSotto return; 7236aaa4aabSotto } 7246aaa4aabSotto partno = p[0] - 'a'; 7256aaa4aabSotto if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 7266aaa4aabSotto fprintf(stderr, "Partition must be between 'a' and '%c' " 7276aaa4aabSotto "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 7286aaa4aabSotto return; 7296aaa4aabSotto } 7306aaa4aabSotto 7316aaa4aabSotto pp = &label.d_partitions[partno]; 732fc6e9c48Sotto sz = DL_GETPSIZE(pp); 733fc6e9c48Sotto if (sz == 0) { 734fc6e9c48Sotto fputs("No such partition\n", stderr); 735fc6e9c48Sotto return; 736fc6e9c48Sotto } 737fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) { 738fc6e9c48Sotto fputs("Cannot resize spoofed partition\n", stderr); 739fc6e9c48Sotto return; 740fc6e9c48Sotto } 7414659aa0dSotto secs = getuint(lp, "[+|-]new size (with unit)", 7424659aa0dSotto "new size or amount to grow (+) or shrink (-) partition including unit", 7434659aa0dSotto sz, editor_countfree(lp), 0, DO_CONVERSIONS); 7446aaa4aabSotto 7454659aa0dSotto if (secs <= 0) { 7466aaa4aabSotto fputs("Command aborted\n", stderr); 7476aaa4aabSotto return; 7486aaa4aabSotto } 7496aaa4aabSotto 7506aaa4aabSotto #ifdef SUN_CYLCHECK 7516aaa4aabSotto cylsecs = lp->d_secpercyl; 7526aaa4aabSotto if (secs > 0) 7536aaa4aabSotto secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; 7546aaa4aabSotto else 7556aaa4aabSotto secs = ((secs - cylsecs + 1) / cylsecs) * cylsecs; 7566aaa4aabSotto #endif 7574659aa0dSotto if (DL_GETPOFFSET(pp) + secs > ending_sector) { 7586aaa4aabSotto fputs("Amount too big\n", stderr); 7596aaa4aabSotto return; 7606aaa4aabSotto } 7616aaa4aabSotto 7624659aa0dSotto DL_SETPSIZE(pp, secs); 763e5f81948Sotto get_bsize(&label, partno); 7646aaa4aabSotto 7656aaa4aabSotto /* 7666aaa4aabSotto * Pack partitions above the resized partition, leaving unused 7676aaa4aabSotto * partions alone. 7686aaa4aabSotto */ 7696aaa4aabSotto prev = pp; 7706aaa4aabSotto for (i = partno + 1; i < MAXPARTITIONS; i++) { 7716aaa4aabSotto if (i == RAW_PART) 7726aaa4aabSotto continue; 773fc6e9c48Sotto pp = &label.d_partitions[i]; 774fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) 775fc6e9c48Sotto continue; 776fc6e9c48Sotto sz = DL_GETPSIZE(pp); 7776aaa4aabSotto if (sz == 0) 7786aaa4aabSotto continue; 7796aaa4aabSotto 7806aaa4aabSotto off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev); 7816aaa4aabSotto 7826aaa4aabSotto if (off < ending_sector) { 7836aaa4aabSotto DL_SETPOFFSET(pp, off); 7846aaa4aabSotto if (off + DL_GETPSIZE(pp) > ending_sector) { 7856aaa4aabSotto DL_SETPSIZE(pp, ending_sector - off); 7866aaa4aabSotto fprintf(stderr, 7876aaa4aabSotto "Partition %c shrunk to make room\n", 7886aaa4aabSotto i + 'a'); 7896aaa4aabSotto } 7906aaa4aabSotto } else { 7916aaa4aabSotto fputs("No room left for all partitions\n", stderr); 7926aaa4aabSotto return; 7936aaa4aabSotto } 794e5f81948Sotto get_bsize(&label, i); 7956aaa4aabSotto prev = pp; 7966aaa4aabSotto } 7976aaa4aabSotto *lp = label; 7986aaa4aabSotto } 7996aaa4aabSotto 8006aaa4aabSotto /* 8016fe57b42Smillert * Add a new partition. 8026fe57b42Smillert */ 8036fe57b42Smillert void 80434ae4198Skrw editor_add(struct disklabel *lp, char *p) 8056fe57b42Smillert { 80696a888c6Smillert struct partition *pp; 80796a888c6Smillert struct diskchunk *chunks; 8085caa08b2Skrw char buf[2]; 8096e312d52Sotto int i, partno, fragsize; 810f8ab7229Schl u_int64_t freesectors, new_offset, new_size; 8119fdcb4d6Skrw 8129fdcb4d6Skrw freesectors = editor_countfree(lp); 8136fe57b42Smillert 8146fe57b42Smillert /* XXX - prompt user to steal space from another partition instead */ 815fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 8169fdcb4d6Skrw if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) { 817fc1a4cc6Sderaadt fputs("No space left, you need to shrink a partition " 818fc1a4cc6Sderaadt "(need at least one full cylinder)\n", 819fc1a4cc6Sderaadt stderr); 820fc1a4cc6Sderaadt return; 821fc1a4cc6Sderaadt } 8228390cf28Smillert #endif 8239fdcb4d6Skrw if (freesectors == 0) { 8246fe57b42Smillert fputs("No space left, you need to shrink a partition\n", 8256fe57b42Smillert stderr); 8266fe57b42Smillert return; 8276fe57b42Smillert } 8286fe57b42Smillert 8295caa08b2Skrw if (p == NULL) { 8305caa08b2Skrw /* 8315caa08b2Skrw * Use the first unused partition that is not 'c' as the 8325caa08b2Skrw * default partition in the prompt string. 8335caa08b2Skrw */ 8345caa08b2Skrw pp = &lp->d_partitions[0]; 8355caa08b2Skrw buf[0] = buf[1] = '\0'; 8365caa08b2Skrw for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) { 8375caa08b2Skrw if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) { 8385caa08b2Skrw buf[0] = partno + 'a'; 8395caa08b2Skrw p = &buf[0]; 8406fe57b42Smillert break; 8416fe57b42Smillert } 8425caa08b2Skrw } 843c33fcabaSmillert p = getstring("partition", 8446fe57b42Smillert "The letter of the new partition, a - p.", p); 8456fe57b42Smillert } 8465caa08b2Skrw if (p == NULL) { 8475caa08b2Skrw fputs("Command aborted\n", stderr); 8485caa08b2Skrw return; 8495caa08b2Skrw } 8505caa08b2Skrw partno = p[0] - 'a'; 8515caa08b2Skrw if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) { 8525caa08b2Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 8535caa08b2Skrw "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1); 8545caa08b2Skrw return; 8555caa08b2Skrw } 8565caa08b2Skrw pp = &lp->d_partitions[partno]; 8575caa08b2Skrw 8585caa08b2Skrw if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) { 8595caa08b2Skrw fprintf(stderr, "Partition '%c' exists. Delete it first.\n", 8605caa08b2Skrw p[0]); 8615caa08b2Skrw return; 8626fe57b42Smillert } 86396a888c6Smillert 864caf41f96Skrw /* 865caf41f96Skrw * Increase d_npartitions if necessary. Ensure all new partitions are 866855d4e83Ssobrado * zero'ed to avoid inadvertent overlaps. 867caf41f96Skrw */ 868caf41f96Skrw for(; lp->d_npartitions <= partno; lp->d_npartitions++) 869caf41f96Skrw memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp)); 87096a888c6Smillert 87189f4601dSkrw /* Make sure selected partition is zero'd too. */ 87289f4601dSkrw memset(pp, 0, sizeof(*pp)); 87315c15d8aSkrw chunks = free_chunks(lp); 87415c15d8aSkrw 87515c15d8aSkrw /* 87615c15d8aSkrw * Since we know there's free space, there must be at least one 87715c15d8aSkrw * chunk. So find the largest chunk and assume we want to add the 87815c15d8aSkrw * partition in that free space. 87915c15d8aSkrw */ 88015c15d8aSkrw new_size = new_offset = 0; 88115c15d8aSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 88215c15d8aSkrw if (chunks[i].stop - chunks[i].start > new_size) { 88315c15d8aSkrw new_size = chunks[i].stop - chunks[i].start; 88415c15d8aSkrw new_offset = chunks[i].start; 88515c15d8aSkrw } 88615c15d8aSkrw } 8871e0ad43cSotto DL_SETPSIZE(pp, new_size); 8881e0ad43cSotto DL_SETPOFFSET(pp, new_offset); 88996a888c6Smillert pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS; 890c88f83bdSotto pp->p_cpg = 1; 891c88f83bdSotto 892c88f83bdSotto if (get_offset(lp, partno) == 0 && 893c88f83bdSotto get_size(lp, partno) == 0) { 8946e312d52Sotto fragsize = 2048; 895c88f83bdSotto new_size = DL_GETPSIZE(pp) * lp->d_secsize; 896c88f83bdSotto if (new_size > 128ULL * 1024 * 1024 * 1024) 897c88f83bdSotto fragsize *= 2; 898c88f83bdSotto if (new_size > 512ULL * 1024 * 1024 * 1024) 899c88f83bdSotto fragsize *= 2; 9004a8b9208Stedu #if defined (__sparc__) && !defined(__sparc64__) 901d98d4df7Stedu /* can't boot from > 8k boot blocks */ 902ddfcbf38Sotto pp->p_fragblock = 9036e312d52Sotto DISKLABELV1_FFS_FRAGBLOCK(partno == 0 ? 1024 : fragsize, 8); 904d98d4df7Stedu #else 9056e312d52Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8); 906d98d4df7Stedu #endif 907c88f83bdSotto if (get_fstype(lp, partno) == 0 && 90834ae4198Skrw get_mp(lp, partno) == 0 && 909a4c87e64Skrw get_fsize(lp, partno) == 0 && 910a4c87e64Skrw get_bsize(lp, partno) == 0) 91196a888c6Smillert return; 912c88f83bdSotto } 913a4c87e64Skrw /* Bailed out at some point, so effectively delete the partition. */ 914da2bd3f5Skrw memset(pp, 0, sizeof(*pp)); 9156fe57b42Smillert } 9166fe57b42Smillert 9176fe57b42Smillert /* 918bd6726faSmillert * Set the mountpoint of an existing partition ('name'). 919bd6726faSmillert */ 920bd6726faSmillert void 92134ae4198Skrw editor_name(struct disklabel *lp, char *p) 922bd6726faSmillert { 923bd6726faSmillert struct partition *pp; 924bd6726faSmillert int partno; 925bd6726faSmillert 926bd6726faSmillert /* Change which partition? */ 927bd6726faSmillert if (p == NULL) { 928c33fcabaSmillert p = getstring("partition to name", 929bd6726faSmillert "The letter of the partition to name, a - p.", NULL); 930bd6726faSmillert } 931bd6726faSmillert if (p == NULL) { 932bd6726faSmillert fputs("Command aborted\n", stderr); 933bd6726faSmillert return; 934bd6726faSmillert } 935bd6726faSmillert partno = p[0] - 'a'; 9366c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9376c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9386c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 939bd6726faSmillert return; 94066df1f0cSkrw } 94166df1f0cSkrw pp = &lp->d_partitions[partno]; 94266df1f0cSkrw 94366df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 94466df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 945bd6726faSmillert return; 946bd6726faSmillert } 947bd6726faSmillert 948bd6726faSmillert /* Not all fstypes can be named */ 949bd6726faSmillert if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP || 950bd387921Stodd pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER || 951bd387921Stodd pp->p_fstype == FS_RAID) { 952bd6726faSmillert fprintf(stderr, "You cannot name a filesystem of type %s.\n", 953baa55472Smillert fstypenames[lp->d_partitions[partno].p_fstype]); 954bd6726faSmillert return; 955bd6726faSmillert } 956bd6726faSmillert 95734ae4198Skrw get_mp(lp, partno); 958bd6726faSmillert } 959bd6726faSmillert 960bd6726faSmillert /* 9616fe57b42Smillert * Change an existing partition. 9626fe57b42Smillert */ 9636fe57b42Smillert void 96434ae4198Skrw editor_modify(struct disklabel *lp, char *p) 9656fe57b42Smillert { 9666fe57b42Smillert struct partition origpart, *pp; 967f8ab7229Schl int partno; 9686fe57b42Smillert 9696fe57b42Smillert /* Change which partition? */ 9706fe57b42Smillert if (p == NULL) { 971c33fcabaSmillert p = getstring("partition to modify", 9726fe57b42Smillert "The letter of the partition to modify, a - p.", NULL); 9736fe57b42Smillert } 97496a888c6Smillert if (p == NULL) { 97596a888c6Smillert fputs("Command aborted\n", stderr); 97696a888c6Smillert return; 97796a888c6Smillert } 9786fe57b42Smillert partno = p[0] - 'a'; 9796c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9806c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9816c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 9826fe57b42Smillert return; 98366df1f0cSkrw } 98466df1f0cSkrw pp = &lp->d_partitions[partno]; 98566df1f0cSkrw 98666df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 98766df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 9886fe57b42Smillert return; 9896fe57b42Smillert } 9906fe57b42Smillert 99166df1f0cSkrw origpart = *pp; 99266df1f0cSkrw 993a4c87e64Skrw if (get_offset(lp, partno) == 0 && 994a4c87e64Skrw get_size(lp, partno) == 0 && 995a4c87e64Skrw get_fstype(lp, partno) == 0 && 99634ae4198Skrw get_mp(lp, partno) == 0 && 997a4c87e64Skrw get_fsize(lp, partno) == 0 && 998a4c87e64Skrw get_bsize(lp, partno) == 0) 99996a888c6Smillert return; 10006fe57b42Smillert 1001a4c87e64Skrw /* Bailed out at some point, so undo any changes. */ 1002a4c87e64Skrw *pp = origpart; 10036fe57b42Smillert } 10046fe57b42Smillert 10056fe57b42Smillert /* 10066fe57b42Smillert * Delete an existing partition. 10076fe57b42Smillert */ 10086fe57b42Smillert void 100934ae4198Skrw editor_delete(struct disklabel *lp, char *p) 10106fe57b42Smillert { 101166df1f0cSkrw struct partition *pp; 1012135c90d1Skrw int partno; 10136fe57b42Smillert 10146fe57b42Smillert if (p == NULL) { 1015c33fcabaSmillert p = getstring("partition to delete", 1016945ae268Smillert "The letter of the partition to delete, a - p, or '*'.", 1017945ae268Smillert NULL); 10186fe57b42Smillert } 101996a888c6Smillert if (p == NULL) { 102096a888c6Smillert fputs("Command aborted\n", stderr); 102196a888c6Smillert return; 102296a888c6Smillert } 1023945ae268Smillert if (p[0] == '*') { 10249fdcb4d6Skrw zero_partitions(lp); 1025945ae268Smillert return; 1026945ae268Smillert } 1027135c90d1Skrw partno = p[0] - 'a'; 1028135c90d1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 10296c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 10306c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 103133262abfSmiod return; 103266df1f0cSkrw } 1033135c90d1Skrw pp = &lp->d_partitions[partno]; 103466df1f0cSkrw 103566df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 103666df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 103733262abfSmiod return; 103866df1f0cSkrw } 103966df1f0cSkrw 10406fe57b42Smillert /* Really delete it (as opposed to just setting to "unused") */ 1041135c90d1Skrw memset(pp, 0, sizeof(*pp)); 104234ae4198Skrw free(mountpoints[partno]); 104334ae4198Skrw mountpoints[partno] = NULL; 10446fe57b42Smillert } 10456fe57b42Smillert 10466fe57b42Smillert /* 10476fe57b42Smillert * Change the size of an existing partition. 10486fe57b42Smillert */ 10496fe57b42Smillert void 10509fdcb4d6Skrw editor_change(struct disklabel *lp, char *p) 10516fe57b42Smillert { 10524b9a3bdaSmillert struct partition *pp; 105366df1f0cSkrw int partno; 10546fe57b42Smillert 10556fe57b42Smillert if (p == NULL) { 1056c33fcabaSmillert p = getstring("partition to change size", 10576fe57b42Smillert "The letter of the partition to change size, a - p.", NULL); 10586fe57b42Smillert } 105996a888c6Smillert if (p == NULL) { 106096a888c6Smillert fputs("Command aborted\n", stderr); 106196a888c6Smillert return; 106296a888c6Smillert } 10636fe57b42Smillert partno = p[0] - 'a'; 10646c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 10656c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 10666c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 10676fe57b42Smillert return; 10686fe57b42Smillert } 10694b9a3bdaSmillert pp = &lp->d_partitions[partno]; 10706fe57b42Smillert 107166df1f0cSkrw if (DL_GETPSIZE(pp) == 0) { 107266df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 107366df1f0cSkrw return; 107466df1f0cSkrw } 107566df1f0cSkrw 107614192793Skrw printf("Partition %c is currently %llu sectors in size, and can have " 107714192793Skrw "a maximum\nsize of %llu sectors.\n", 107814192793Skrw p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno)); 10797da73705Skrw 108059ccf790Skrw /* Get new size */ 10819fdcb4d6Skrw get_size(lp, partno); 10826fe57b42Smillert } 10836fe57b42Smillert 10846fe57b42Smillert /* 10856fe57b42Smillert * Sort the partitions based on starting offset. 10866fe57b42Smillert * This assumes there can be no overlap. 10876fe57b42Smillert */ 10886fe57b42Smillert int 10898809fabbSderaadt partition_cmp(const void *e1, const void *e2) 10906fe57b42Smillert { 10916fe57b42Smillert struct partition *p1 = *(struct partition **)e1; 10926fe57b42Smillert struct partition *p2 = *(struct partition **)e2; 10931e0ad43cSotto u_int64_t o1 = DL_GETPOFFSET(p1); 10941e0ad43cSotto u_int64_t o2 = DL_GETPOFFSET(p2); 10956fe57b42Smillert 10961e0ad43cSotto if (o1 < o2) 1097651d5bd9Sotto return -1; 10981e0ad43cSotto else if (o1 > o2) 1099651d5bd9Sotto return 1; 1100651d5bd9Sotto else 1101651d5bd9Sotto return 0; 11026fe57b42Smillert } 11036fe57b42Smillert 11046fe57b42Smillert char * 11058809fabbSderaadt getstring(char *prompt, char *helpstring, char *oval) 11066fe57b42Smillert { 11076fe57b42Smillert static char buf[BUFSIZ]; 11086fe57b42Smillert int n; 11096fe57b42Smillert 11106fe57b42Smillert buf[0] = '\0'; 11116fe57b42Smillert do { 11126fe57b42Smillert printf("%s: [%s] ", prompt, oval ? oval : ""); 11136e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1114260513deSmillert buf[0] = '\0'; 111596a888c6Smillert if (feof(stdin)) { 111624c6582eSmillert clearerr(stdin); 111796a888c6Smillert putchar('\n'); 111896a888c6Smillert return(NULL); 111996a888c6Smillert } 11206e0becc5Smillert } 11216fe57b42Smillert n = strlen(buf); 11226fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 11236fe57b42Smillert buf[--n] = '\0'; 11246fe57b42Smillert if (buf[0] == '?') 11256fe57b42Smillert puts(helpstring); 11264fb6ab7cSmillert else if (oval != NULL && buf[0] == '\0') 11274fb6ab7cSmillert strlcpy(buf, oval, sizeof(buf)); 11286fe57b42Smillert } while (buf[0] == '?'); 11296fe57b42Smillert 11306fe57b42Smillert return(&buf[0]); 11316fe57b42Smillert } 11326fe57b42Smillert 11336fe57b42Smillert /* 11341e0ad43cSotto * Returns ULLONG_MAX on error 113524a2c1a4Smillert * Usually only called by helper functions. 11366fe57b42Smillert */ 11371e0ad43cSotto u_int64_t 1138dea75673Skrw getuint(struct disklabel *lp, char *prompt, char *helpstring, 11391e0ad43cSotto u_int64_t oval, u_int64_t maxval, u_int64_t offset, int flags) 11406fe57b42Smillert { 11416fe57b42Smillert char buf[BUFSIZ], *endptr, *p, operator = '\0'; 11421e0ad43cSotto u_int64_t rval = oval; 1143e04edc8bSkrw int64_t mult = 1; 11446fe57b42Smillert size_t n; 114514cc915fSmillert double d, percent = 1.0; 11466fe57b42Smillert 11474b9a3bdaSmillert /* We only care about the remainder */ 11484b9a3bdaSmillert offset = offset % lp->d_secpercyl; 11494b9a3bdaSmillert 11506fe57b42Smillert buf[0] = '\0'; 11516fe57b42Smillert do { 11521e0ad43cSotto printf("%s: [%llu] ", prompt, oval); 11536e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 11546e0becc5Smillert buf[0] = '\0'; 115596a888c6Smillert if (feof(stdin)) { 115624c6582eSmillert clearerr(stdin); 115796a888c6Smillert putchar('\n'); 11581e0ad43cSotto return(ULLONG_MAX - 1); 115996a888c6Smillert } 11606e0becc5Smillert } 11616fe57b42Smillert n = strlen(buf); 11626fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 11636fe57b42Smillert buf[--n] = '\0'; 11646fe57b42Smillert if (buf[0] == '?') 11656fe57b42Smillert puts(helpstring); 11666fe57b42Smillert } while (buf[0] == '?'); 11676fe57b42Smillert 11686fe57b42Smillert if (buf[0] == '*' && buf[1] == '\0') { 11696fe57b42Smillert rval = maxval; 11706fe57b42Smillert } else { 11716fe57b42Smillert /* deal with units */ 11726fe57b42Smillert if (buf[0] != '\0' && n > 0) { 11736fe57b42Smillert if ((flags & DO_CONVERSIONS)) { 117496a888c6Smillert switch (tolower(buf[n-1])) { 11756fe57b42Smillert 11766fe57b42Smillert case 'c': 11776fe57b42Smillert mult = lp->d_secpercyl; 11786fe57b42Smillert buf[--n] = '\0'; 11796fe57b42Smillert break; 11806fe57b42Smillert case 'b': 11816fe57b42Smillert mult = -lp->d_secsize; 11826fe57b42Smillert buf[--n] = '\0'; 11836fe57b42Smillert break; 11846fe57b42Smillert case 'k': 118550c0f47aSkrw if (lp->d_secsize > 1024) 1186e04edc8bSkrw mult = -lp->d_secsize / 1024LL; 118750c0f47aSkrw else 1188e04edc8bSkrw mult = 1024LL / lp->d_secsize; 11896fe57b42Smillert buf[--n] = '\0'; 11906fe57b42Smillert break; 11916fe57b42Smillert case 'm': 1192e04edc8bSkrw mult = (1024LL * 1024) / lp->d_secsize; 11936fe57b42Smillert buf[--n] = '\0'; 11946fe57b42Smillert break; 11951a51a1eeSmillert case 'g': 1196e04edc8bSkrw mult = (1024LL * 1024 * 1024) / 1197e04edc8bSkrw lp->d_secsize; 1198e04edc8bSkrw buf[--n] = '\0'; 1199e04edc8bSkrw break; 1200e04edc8bSkrw case 't': 1201e04edc8bSkrw mult = (1024LL * 1024 * 1024 * 1024) / 1202e04edc8bSkrw lp->d_secsize; 12031a51a1eeSmillert buf[--n] = '\0'; 12041a51a1eeSmillert break; 120514cc915fSmillert case '%': 120614cc915fSmillert buf[--n] = '\0'; 12074659aa0dSotto p = &buf[0]; 12084659aa0dSotto if (*p == '+' || *p == '-') 12094659aa0dSotto operator = *p++; 12104659aa0dSotto percent = strtod(p, NULL) / 100.0; 12111e0ad43cSotto snprintf(buf, sizeof(buf), "%lld", 12121e0ad43cSotto DL_GETDSIZE(lp)); 121314cc915fSmillert break; 121414cc915fSmillert case '&': 121514cc915fSmillert buf[--n] = '\0'; 12164659aa0dSotto p = &buf[0]; 12174659aa0dSotto if (*p == '+' || *p == '-') 12184659aa0dSotto operator = *p++; 12194659aa0dSotto percent = strtod(p, NULL) / 100.0; 12201e0ad43cSotto snprintf(buf, sizeof(buf), "%lld", 122114cc915fSmillert maxval); 122214cc915fSmillert break; 12236fe57b42Smillert } 122496a888c6Smillert } 12256fe57b42Smillert 12266fe57b42Smillert /* Did they give us an operator? */ 12276fe57b42Smillert p = &buf[0]; 12286fe57b42Smillert if (*p == '+' || *p == '-') 12296fe57b42Smillert operator = *p++; 12306fe57b42Smillert 12316fe57b42Smillert endptr = p; 123296a888c6Smillert errno = 0; 123396a888c6Smillert d = strtod(p, &endptr); 123496a888c6Smillert if (errno == ERANGE) 12351e0ad43cSotto rval = ULLONG_MAX; /* too big/small */ 123696a888c6Smillert else if (*endptr != '\0') { 12376fe57b42Smillert errno = EINVAL; /* non-numbers in str */ 12381e0ad43cSotto rval = ULLONG_MAX; 12396fe57b42Smillert } else { 124096a888c6Smillert /* XXX - should check for overflow */ 124196a888c6Smillert if (mult > 0) 124214cc915fSmillert rval = d * mult * percent; 124396a888c6Smillert else 124496a888c6Smillert /* Negative mult means divide (fancy) */ 124514cc915fSmillert rval = d / (-mult) * percent; 12466fe57b42Smillert 124796a888c6Smillert /* Apply the operator */ 12486fe57b42Smillert if (operator == '+') 12496fe57b42Smillert rval += oval; 12506fe57b42Smillert else if (operator == '-') 12516fe57b42Smillert rval = oval - rval; 12526fe57b42Smillert } 12536fe57b42Smillert } 12546fe57b42Smillert } 12558390cf28Smillert if ((flags & DO_ROUNDING) && rval != ULLONG_MAX) { 125696a888c6Smillert /* Round to nearest cylinder unless given in sectors */ 12578390cf28Smillert if ( 1258fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 1259fc1a4cc6Sderaadt ((lp->d_flags & D_VENDOR) || mult != 1) && 1260fc1a4cc6Sderaadt #else 12618390cf28Smillert mult != 1 && 1262dbffb156Smillert #endif 12638390cf28Smillert (rval + offset) % lp->d_secpercyl != 0) { 12641e0ad43cSotto u_int64_t cyls; 1265dbffb156Smillert 12668390cf28Smillert /* Round to higher cylinder but no more than maxval */ 12678390cf28Smillert cyls = (rval / lp->d_secpercyl) + 1; 12688390cf28Smillert if ((cyls * lp->d_secpercyl) - offset > maxval) 1269dbffb156Smillert cyls--; 12704b9a3bdaSmillert rval = (cyls * lp->d_secpercyl) - offset; 12718390cf28Smillert printf("Rounding to cylinder: %llu\n", rval); 12726fe57b42Smillert } 12734b9a3bdaSmillert } 12746fe57b42Smillert 12756fe57b42Smillert return(rval); 12766fe57b42Smillert } 12776fe57b42Smillert 12786fe57b42Smillert /* 12791f0f871dSkrw * Check for partition overlap in lp and prompt the user to resolve the overlap 12801f0f871dSkrw * if any is found. Returns 1 if unable to resolve, else 0. 12816fe57b42Smillert */ 12826fe57b42Smillert int 12831f0f871dSkrw has_overlap(struct disklabel *lp) 12846fe57b42Smillert { 12856fe57b42Smillert struct partition **spp; 1286e6aa8bafSmillert int c, i, j; 1287e6aa8bafSmillert char buf[BUFSIZ]; 12886fe57b42Smillert 12890fbd3c97Skrw /* Get a sorted list of the in-use partitions. */ 12900fbd3c97Skrw spp = sort_partitions(lp); 12916fe57b42Smillert 12920fbd3c97Skrw /* If there are less than two partitions in use, there is no overlap. */ 12930fbd3c97Skrw if (spp[1] == NULL) 12940fbd3c97Skrw return(0); 12956fe57b42Smillert 12966fe57b42Smillert /* Now that we have things sorted by starting sector check overlap */ 12970fbd3c97Skrw for (i = 0; spp[i] != NULL; i++) { 12980fbd3c97Skrw for (j = i + 1; spp[j] != NULL; j++) { 12996fe57b42Smillert /* `if last_sec_in_part + 1 > first_sec_in_next_part' */ 13001e0ad43cSotto if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) > DL_GETPOFFSET(spp[j])) { 13016fe57b42Smillert /* Overlap! Convert to real part numbers. */ 13026fe57b42Smillert i = ((char *)spp[i] - (char *)lp->d_partitions) 13036fe57b42Smillert / sizeof(**spp); 13046fe57b42Smillert j = ((char *)spp[j] - (char *)lp->d_partitions) 13056fe57b42Smillert / sizeof(**spp); 13066fe57b42Smillert printf("\nError, partitions %c and %c overlap:\n", 13076fe57b42Smillert 'a' + i, 'a' + j); 1308366bf641Skrw printf("# %16.16s %16.16s fstype " 1309651d5bd9Sotto "[fsize bsize cpg]\n", "size", "offset"); 131034ae4198Skrw display_partition(stdout, lp, i, 0); 131134ae4198Skrw display_partition(stdout, lp, j, 0); 13126fe57b42Smillert 1313e6aa8bafSmillert /* Get partition to disable or ^D */ 1314e6aa8bafSmillert do { 1315616cd1c4Smillert printf("Disable which one? (^D to abort) [%c %c] ", 13166fe57b42Smillert 'a' + i, 'a' + j); 1317e6aa8bafSmillert buf[0] = '\0'; 1318616cd1c4Smillert if (!fgets(buf, sizeof(buf), stdin)) { 1319616cd1c4Smillert putchar('\n'); 1320e6aa8bafSmillert return(1); /* ^D */ 1321616cd1c4Smillert } 1322e6aa8bafSmillert c = buf[0] - 'a'; 1323e6aa8bafSmillert } while (buf[1] != '\n' && buf[1] != '\0' && 1324e6aa8bafSmillert c != i && c != j); 1325e6aa8bafSmillert 1326e6aa8bafSmillert /* Mark the selected one as unused */ 13276fe57b42Smillert lp->d_partitions[c].p_fstype = FS_UNUSED; 13281f0f871dSkrw return (has_overlap(lp)); 13296fe57b42Smillert } 13306fe57b42Smillert } 13316fe57b42Smillert } 1332f0b4d0a9Smillert 1333e6aa8bafSmillert return(0); 13346fe57b42Smillert } 13356fe57b42Smillert 13366fe57b42Smillert void 13379fdcb4d6Skrw edit_parms(struct disklabel *lp) 13386fe57b42Smillert { 13396fe57b42Smillert char *p; 13409fdcb4d6Skrw u_int64_t freesectors, ui; 134196a888c6Smillert struct disklabel oldlabel = *lp; 13426fe57b42Smillert 1343ea37abd3Sderaadt printf("Changing device parameters for %s:\n", specname); 13446fe57b42Smillert 13450f820bbbSmillert /* disk type */ 13460f820bbbSmillert for (;;) { 1347c33fcabaSmillert p = getstring("disk type", 134841282a2aSmillert "What kind of disk is this? Usually SCSI, ESDI, ST506, or " 134941282a2aSmillert "floppy (use ESDI for IDE).", dktypenames[lp->d_type]); 135096a888c6Smillert if (p == NULL) { 135196a888c6Smillert fputs("Command aborted\n", stderr); 135296a888c6Smillert return; 135396a888c6Smillert } 135441282a2aSmillert if (strcasecmp(p, "IDE") == 0) 135541282a2aSmillert ui = DTYPE_ESDI; 135641282a2aSmillert else 135741282a2aSmillert for (ui = 1; ui < DKMAXTYPES && 135841282a2aSmillert strcasecmp(p, dktypenames[ui]); ui++) 13590f820bbbSmillert ; 13600f820bbbSmillert if (ui < DKMAXTYPES) { 13610f820bbbSmillert break; 13620f820bbbSmillert } else { 13630f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", p); 13640f820bbbSmillert fputs("Valid types are: ", stdout); 13650f820bbbSmillert for (ui = 1; ui < DKMAXTYPES; ui++) { 13660f820bbbSmillert printf("\"%s\"", dktypenames[ui]); 13670f820bbbSmillert if (ui < DKMAXTYPES - 1) 13680f820bbbSmillert fputs(", ", stdout); 13690f820bbbSmillert } 13700f820bbbSmillert putchar('\n'); 13710f820bbbSmillert } 13720f820bbbSmillert } 13730f820bbbSmillert lp->d_type = ui; 13740f820bbbSmillert 13756fe57b42Smillert /* pack/label id */ 1376c33fcabaSmillert p = getstring("label name", 13776fe57b42Smillert "15 char string that describes this label, usually the disk name.", 13786fe57b42Smillert lp->d_packname); 137996a888c6Smillert if (p == NULL) { 138096a888c6Smillert fputs("Command aborted\n", stderr); 138196a888c6Smillert *lp = oldlabel; /* undo damage */ 138296a888c6Smillert return; 138396a888c6Smillert } 13844fb6ab7cSmillert strncpy(lp->d_packname, p, sizeof(lp->d_packname)); /* checked */ 13856fe57b42Smillert 13866fe57b42Smillert /* sectors/track */ 13876fe57b42Smillert for (;;) { 1388dea75673Skrw ui = getuint(lp, "sectors/track", 1389cfd24250Skrw "The Number of sectors per track.", lp->d_nsectors, 13904b9a3bdaSmillert lp->d_nsectors, 0, 0); 13911e0ad43cSotto if (ui == ULLONG_MAX - 1) { 139296a888c6Smillert fputs("Command aborted\n", stderr); 139396a888c6Smillert *lp = oldlabel; /* undo damage */ 139496a888c6Smillert return; 13951e0ad43cSotto } if (ui == ULLONG_MAX) 13966fe57b42Smillert fputs("Invalid entry\n", stderr); 13976fe57b42Smillert else 13986fe57b42Smillert break; 13996fe57b42Smillert } 14006fe57b42Smillert lp->d_nsectors = ui; 14016fe57b42Smillert 14026fe57b42Smillert /* tracks/cylinder */ 14036fe57b42Smillert for (;;) { 1404dea75673Skrw ui = getuint(lp, "tracks/cylinder", 14056fe57b42Smillert "The number of tracks per cylinder.", lp->d_ntracks, 14064b9a3bdaSmillert lp->d_ntracks, 0, 0); 14071e0ad43cSotto if (ui == ULLONG_MAX - 1) { 140896a888c6Smillert fputs("Command aborted\n", stderr); 140996a888c6Smillert *lp = oldlabel; /* undo damage */ 141096a888c6Smillert return; 14111e0ad43cSotto } else if (ui == ULLONG_MAX) 14126fe57b42Smillert fputs("Invalid entry\n", stderr); 14136fe57b42Smillert else 14146fe57b42Smillert break; 14156fe57b42Smillert } 14166fe57b42Smillert lp->d_ntracks = ui; 14176fe57b42Smillert 14186fe57b42Smillert /* sectors/cylinder */ 1419148b6188Smillert for (;;) { 1420dea75673Skrw ui = getuint(lp, "sectors/cylinder", 1421148b6188Smillert "The number of sectors per cylinder (Usually sectors/track " 14224b9a3bdaSmillert "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl, 14234b9a3bdaSmillert 0, 0); 14241e0ad43cSotto if (ui == ULLONG_MAX - 1) { 142596a888c6Smillert fputs("Command aborted\n", stderr); 142696a888c6Smillert *lp = oldlabel; /* undo damage */ 142796a888c6Smillert return; 14281e0ad43cSotto } else if (ui == ULLONG_MAX) 1429148b6188Smillert fputs("Invalid entry\n", stderr); 1430148b6188Smillert else 1431148b6188Smillert break; 1432148b6188Smillert } 1433148b6188Smillert lp->d_secpercyl = ui; 14346fe57b42Smillert 14356fe57b42Smillert /* number of cylinders */ 14366fe57b42Smillert for (;;) { 1437dea75673Skrw ui = getuint(lp, "number of cylinders", 14386fe57b42Smillert "The total number of cylinders on the disk.", 14394b9a3bdaSmillert lp->d_ncylinders, lp->d_ncylinders, 0, 0); 14401e0ad43cSotto if (ui == ULLONG_MAX - 1) { 144196a888c6Smillert fputs("Command aborted\n", stderr); 144296a888c6Smillert *lp = oldlabel; /* undo damage */ 144396a888c6Smillert return; 14441e0ad43cSotto } else if (ui == ULLONG_MAX) 14456fe57b42Smillert fputs("Invalid entry\n", stderr); 14466fe57b42Smillert else 14476fe57b42Smillert break; 14486fe57b42Smillert } 14496fe57b42Smillert lp->d_ncylinders = ui; 14506fe57b42Smillert 14516fe57b42Smillert /* total sectors */ 14526fe57b42Smillert for (;;) { 145334af67a3Sotto u_int64_t nsec = MAX(DL_GETDSIZE(lp), 145434af67a3Sotto (u_int64_t)lp->d_ncylinders * lp->d_secpercyl); 1455dea75673Skrw ui = getuint(lp, "total sectors", 14566fe57b42Smillert "The total number of sectors on the disk.", 1457baaa8969Smillert nsec, nsec, 0, 0); 14581e0ad43cSotto if (ui == ULLONG_MAX - 1) { 145996a888c6Smillert fputs("Command aborted\n", stderr); 146096a888c6Smillert *lp = oldlabel; /* undo damage */ 146196a888c6Smillert return; 14621e0ad43cSotto } else if (ui == ULLONG_MAX) 14636fe57b42Smillert fputs("Invalid entry\n", stderr); 14641e0ad43cSotto else if (ui > DL_GETDSIZE(lp) && 14651e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 1466f98aebd4Smillert puts("You may want to increase the size of the 'c' " 1467f98aebd4Smillert "partition."); 14686fe57b42Smillert break; 14691e0ad43cSotto } else if (ui < DL_GETDSIZE(lp) && 14701e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 14716fe57b42Smillert /* shrink free count */ 14729fdcb4d6Skrw freesectors = editor_countfree(lp); 14739fdcb4d6Skrw if (DL_GETDSIZE(lp) - ui > freesectors) 14746fe57b42Smillert fprintf(stderr, 14751e0ad43cSotto "Not enough free space to shrink by %llu " 14761e0ad43cSotto "sectors (only %llu sectors left)\n", 14779fdcb4d6Skrw DL_GETDSIZE(lp) - ui, freesectors); 1478c4f83f03Skrw else 14796fe57b42Smillert break; 14806fe57b42Smillert } else 14816fe57b42Smillert break; 14826fe57b42Smillert } 148341ed49b7Smillert /* Adjust ending_sector if necessary. */ 148478f0fb17Skrw if (ending_sector > ui) { 148596a888c6Smillert ending_sector = ui; 148678f0fb17Skrw DL_SETBEND(lp, ending_sector); 148778f0fb17Skrw } 14881e0ad43cSotto DL_SETDSIZE(lp, ui); 14896fe57b42Smillert } 1490a7e61405Smillert 1491a7e61405Smillert struct partition ** 14920fbd3c97Skrw sort_partitions(struct disklabel *lp) 1493a7e61405Smillert { 1494d18c2a43Skrw static struct partition *spp[MAXPARTITIONS+2]; 14950fbd3c97Skrw int i, npartitions; 1496a7e61405Smillert 1497d18c2a43Skrw memset(spp, 0, sizeof(spp)); 1498d18c2a43Skrw 1499a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1500a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1501a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 15021e0ad43cSotto DL_GETPSIZE(&lp->d_partitions[i]) != 0) 1503a7e61405Smillert spp[npartitions++] = &lp->d_partitions[i]; 1504a7e61405Smillert } 1505a7e61405Smillert 1506a7e61405Smillert /* 1507a7e61405Smillert * Sort the partitions based on starting offset. 1508a7e61405Smillert * This is safe because we guarantee no overlap. 1509a7e61405Smillert */ 1510a7e61405Smillert if (npartitions > 1) 1511a7e61405Smillert if (heapsort((void *)spp, npartitions, sizeof(spp[0]), 1512a7e61405Smillert partition_cmp)) 1513a7e61405Smillert err(4, "failed to sort partition table"); 1514a7e61405Smillert 1515a7e61405Smillert return(spp); 1516a7e61405Smillert } 15170f820bbbSmillert 15180f820bbbSmillert /* 15190f820bbbSmillert * Get a valid disk type if necessary. 15200f820bbbSmillert */ 15210f820bbbSmillert void 15228809fabbSderaadt getdisktype(struct disklabel *lp, char *banner, char *dev) 15230f820bbbSmillert { 15240f820bbbSmillert int i; 1525803ff7d5Smillert char *s, *def = "SCSI"; 1526803ff7d5Smillert struct dtypes { 1527803ff7d5Smillert char *dev; 1528803ff7d5Smillert char *type; 1529803ff7d5Smillert } dtypes[] = { 1530c33fcabaSmillert { "sd", "SCSI" }, 1531c33fcabaSmillert { "rz", "SCSI" }, 1532c33fcabaSmillert { "wd", "IDE" }, 1533c33fcabaSmillert { "fd", "FLOPPY" }, 1534c33fcabaSmillert { "xd", "SMD" }, 1535c33fcabaSmillert { "xy", "SMD" }, 1536c33fcabaSmillert { "hd", "HP-IB" }, 1537*d7878011Sderaadt { "ccd", "CCD" }, /* deprecated */ 1538c33fcabaSmillert { "vnd", "VND" }, 1539c33fcabaSmillert { "svnd", "VND" }, 1540c33fcabaSmillert { NULL, NULL } 1541803ff7d5Smillert }; 1542803ff7d5Smillert 1543803ff7d5Smillert if ((s = basename(dev)) != NULL) { 1544803ff7d5Smillert if (*s == 'r') 1545803ff7d5Smillert s++; 1546803ff7d5Smillert i = strcspn(s, "0123456789"); 1547803ff7d5Smillert s[i] = '\0'; 1548803ff7d5Smillert dev = s; 1549803ff7d5Smillert for (i = 0; dtypes[i].dev != NULL; i++) { 1550803ff7d5Smillert if (strcmp(dev, dtypes[i].dev) == 0) { 1551803ff7d5Smillert def = dtypes[i].type; 1552803ff7d5Smillert break; 1553803ff7d5Smillert } 1554803ff7d5Smillert } 1555803ff7d5Smillert } 15560f820bbbSmillert 15570f820bbbSmillert if (lp->d_type > DKMAXTYPES || lp->d_type == 0) { 15580f820bbbSmillert puts(banner); 15590f820bbbSmillert puts("Possible values are:"); 1560eb5dd924Sderaadt printf("\"IDE\", "); 15610f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15620f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15630f820bbbSmillert if (i < DKMAXTYPES - 1) 15640f820bbbSmillert fputs(", ", stdout); 15650f820bbbSmillert } 15660f820bbbSmillert putchar('\n'); 15670f820bbbSmillert 15680f820bbbSmillert for (;;) { 1569c33fcabaSmillert s = getstring("Disk type", 1570803ff7d5Smillert "What kind of disk is this? Usually SCSI, IDE, " 1571*d7878011Sderaadt "ESDI, ST506, or floppy.", def); 157296a888c6Smillert if (s == NULL) 157396a888c6Smillert continue; 15745b412421Smillert if (strcasecmp(s, "IDE") == 0) { 15755b412421Smillert lp->d_type = DTYPE_ESDI; 15765b412421Smillert return; 15775b412421Smillert } 15780f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) 15790f820bbbSmillert if (strcasecmp(s, dktypenames[i]) == 0) { 15800f820bbbSmillert lp->d_type = i; 15810f820bbbSmillert return; 15820f820bbbSmillert } 15830f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", s); 15840f820bbbSmillert fputs("Valid types are: ", stdout); 15850f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15860f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15870f820bbbSmillert if (i < DKMAXTYPES - 1) 15880f820bbbSmillert fputs(", ", stdout); 15890f820bbbSmillert } 15900f820bbbSmillert putchar('\n'); 15910f820bbbSmillert } 15920f820bbbSmillert } 15930f820bbbSmillert } 159496a888c6Smillert 159596a888c6Smillert /* 159696a888c6Smillert * Get beginning and ending sectors of the OpenBSD portion of the disk 159796a888c6Smillert * from the user. 159896a888c6Smillert */ 159996a888c6Smillert void 16009fdcb4d6Skrw set_bounds(struct disklabel *lp) 160196a888c6Smillert { 16021e0ad43cSotto u_int64_t ui, start_temp; 160396a888c6Smillert 160496a888c6Smillert /* Starting sector */ 160596a888c6Smillert do { 1606dea75673Skrw ui = getuint(lp, "Starting sector", 160796a888c6Smillert "The start of the OpenBSD portion of the disk.", 16081e0ad43cSotto starting_sector, DL_GETDSIZE(lp), 0, 0); 16091e0ad43cSotto if (ui == ULLONG_MAX - 1) { 161096a888c6Smillert fputs("Command aborted\n", stderr); 161196a888c6Smillert return; 161296a888c6Smillert } 16131e0ad43cSotto } while (ui >= DL_GETDSIZE(lp)); 161496a888c6Smillert start_temp = ui; 161596a888c6Smillert 16164793b14cSmillert /* Size */ 161796a888c6Smillert do { 1618dea75673Skrw ui = getuint(lp, "Size ('*' for entire disk)", 1619f98aebd4Smillert "The size of the OpenBSD portion of the disk ('*' for the " 1620f98aebd4Smillert "entire disk).", ending_sector - starting_sector, 16211e0ad43cSotto DL_GETDSIZE(lp) - start_temp, 0, 0); 16221e0ad43cSotto if (ui == ULLONG_MAX - 1) { 162396a888c6Smillert fputs("Command aborted\n", stderr); 162496a888c6Smillert return; 162596a888c6Smillert } 16261e0ad43cSotto } while (ui > DL_GETDSIZE(lp) - start_temp); 16274793b14cSmillert ending_sector = start_temp + ui; 162878f0fb17Skrw DL_SETBEND(lp, ending_sector); 162996a888c6Smillert starting_sector = start_temp; 163078f0fb17Skrw DL_SETBSTART(lp, starting_sector); 163196a888c6Smillert } 163296a888c6Smillert 163396a888c6Smillert /* 16340d63cfbaSjsing * Allow user to interactively change disklabel UID. 16350d63cfbaSjsing */ 16360d63cfbaSjsing void 163769a6ffbcSjsing set_duid(struct disklabel *lp) 16380d63cfbaSjsing { 16390d63cfbaSjsing char *s; 16400d63cfbaSjsing int i; 16410d63cfbaSjsing 1642f6ad9e2dSjsing printf("The disklabel UID is currently: " 1643f6ad9e2dSjsing "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n", 1644f6ad9e2dSjsing lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3], 1645f6ad9e2dSjsing lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]); 16460d63cfbaSjsing 16470d63cfbaSjsing do { 164869a6ffbcSjsing s = getstring("duid", "The disklabel UID, given as a 16 " 16490d63cfbaSjsing "character hexadecimal string.", NULL); 1650ce98d1aeShalex if (s == NULL || strlen(s) == 0) { 16510d63cfbaSjsing fputs("Command aborted\n", stderr); 16520d63cfbaSjsing return; 16530d63cfbaSjsing } 165469a6ffbcSjsing i = duid_parse(lp, s); 16550d63cfbaSjsing if (i != 0) 16560d63cfbaSjsing fputs("Invalid UID entered.\n", stderr); 16570d63cfbaSjsing } while (i != 0); 16580d63cfbaSjsing } 16590d63cfbaSjsing 16600d63cfbaSjsing /* 166196a888c6Smillert * Return a list of the "chunks" of free space available 166296a888c6Smillert */ 166396a888c6Smillert struct diskchunk * 16648809fabbSderaadt free_chunks(struct disklabel *lp) 166596a888c6Smillert { 166696a888c6Smillert struct partition **spp; 166796a888c6Smillert static struct diskchunk chunks[MAXPARTITIONS + 2]; 166899bd27d2Skrw u_int64_t start, stop; 166996a888c6Smillert int i, numchunks; 167096a888c6Smillert 16710fbd3c97Skrw /* Sort the in-use partitions based on offset */ 16720fbd3c97Skrw spp = sort_partitions(lp); 167396a888c6Smillert 167496a888c6Smillert /* If there are no partitions, it's all free. */ 16750fbd3c97Skrw if (spp[0] == NULL) { 16762d8451b0Smillert chunks[0].start = starting_sector; 167796a888c6Smillert chunks[0].stop = ending_sector; 167896a888c6Smillert chunks[1].start = chunks[1].stop = 0; 167996a888c6Smillert return(chunks); 168096a888c6Smillert } 168196a888c6Smillert 168296a888c6Smillert /* Find chunks of free space */ 168396a888c6Smillert numchunks = 0; 16840fbd3c97Skrw if (DL_GETPOFFSET(spp[0]) > starting_sector) { 16852d8451b0Smillert chunks[0].start = starting_sector; 16861e0ad43cSotto chunks[0].stop = DL_GETPOFFSET(spp[0]); 168796a888c6Smillert numchunks++; 168896a888c6Smillert } 16890fbd3c97Skrw for (i = 0; spp[i] != NULL; i++) { 169099bd27d2Skrw start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]); 1691aff3f969Sotto if (start < starting_sector) 1692aff3f969Sotto start = starting_sector; 1693aff3f969Sotto else if (start > ending_sector) 1694aff3f969Sotto start = ending_sector; 169599bd27d2Skrw if (spp[i + 1] != NULL) 169699bd27d2Skrw stop = DL_GETPOFFSET(spp[i+1]); 169799bd27d2Skrw else 169899bd27d2Skrw stop = ending_sector; 1699aff3f969Sotto if (stop < starting_sector) 1700aff3f969Sotto stop = starting_sector; 1701aff3f969Sotto else if (stop > ending_sector) 1702aff3f969Sotto stop = ending_sector; 170399bd27d2Skrw if (start < stop) { 170499bd27d2Skrw chunks[numchunks].start = start; 170599bd27d2Skrw chunks[numchunks].stop = stop; 170696a888c6Smillert numchunks++; 170796a888c6Smillert } 170896a888c6Smillert } 170996a888c6Smillert 171096a888c6Smillert /* Terminate and return */ 171196a888c6Smillert chunks[numchunks].start = chunks[numchunks].stop = 0; 171296a888c6Smillert return(chunks); 171396a888c6Smillert } 17144793b14cSmillert 17154793b14cSmillert void 171687023ed9Skrw find_bounds(struct disklabel *lp) 17174793b14cSmillert { 17186534e983Sderaadt starting_sector = DL_GETBSTART(lp); 17196534e983Sderaadt ending_sector = DL_GETBEND(lp); 1720b2d4a455Smiod 17216534e983Sderaadt if (ending_sector) { 172234ae4198Skrw if (verbose) 172334ae4198Skrw printf("Treating sectors %llu-%llu as the OpenBSD" 172434ae4198Skrw " portion of the disk.\nYou can use the 'b'" 172534ae4198Skrw " command to change this.\n\n", starting_sector, 172634ae4198Skrw ending_sector); 1727b2d4a455Smiod } else { 1728b2d4a455Smiod #if (NUMBOOT == 1) 1729d3f02056Smillert /* Boot blocks take up the first cylinder */ 1730d3f02056Smillert starting_sector = lp->d_secpercyl; 173134ae4198Skrw if (verbose) 173234ae4198Skrw printf("Reserving the first data cylinder for boot" 173334ae4198Skrw " blocks.\nYou can use the 'b' command to change" 173434ae4198Skrw " this.\n\n"); 17354793b14cSmillert #endif 17364793b14cSmillert } 1737b2d4a455Smiod } 1738c0bdc608Smillert 1739c0bdc608Smillert /* 1740c0bdc608Smillert * Calculate free space. 1741c0bdc608Smillert */ 17429fdcb4d6Skrw u_int64_t 17439fdcb4d6Skrw editor_countfree(struct disklabel *lp) 1744c0bdc608Smillert { 1745d93cb2bbSkrw struct diskchunk *chunks; 17469fdcb4d6Skrw u_int64_t freesectors = 0; 1747c0bdc608Smillert int i; 1748c0bdc608Smillert 1749d93cb2bbSkrw chunks = free_chunks(lp); 1750509930fbSotto 1751d93cb2bbSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) 17529fdcb4d6Skrw freesectors += chunks[i].stop - chunks[i].start; 17539fdcb4d6Skrw 17549fdcb4d6Skrw return (freesectors); 1755c0bdc608Smillert } 1756617e6e4aSmillert 1757617e6e4aSmillert void 17584d812bb6Slum editor_help(void) 1759617e6e4aSmillert { 1760617e6e4aSmillert puts("Available commands:"); 1761617e6e4aSmillert puts( 17624d812bb6Slum " ? | h - show help n [part] - set mount point\n" 176349159a67Skrw " A - auto partition all space p [unit] - print partitions\n" 176449159a67Skrw " a [part] - add partition q - quit & save changes\n" 17654659aa0dSotto " b - set OpenBSD boundaries R [part] - resize auto allocated partition\n" 176649159a67Skrw " c [part] - change partition size r - display free space\n" 17676aaa4aabSotto " D - reset label to default s [path] - save label to file\n" 17686aaa4aabSotto " d [part] - delete partition U - undo all changes\n" 17696aaa4aabSotto " e - edit drive parameters u - undo last change\n" 17706aaa4aabSotto " g [d|u] - [d]isk or [u]ser geometry w - write label to disk\n" 17710d63cfbaSjsing " i - modify disklabel UID X - toggle expert mode\n" 17720d63cfbaSjsing " l [unit] - print disk label header x - exit & lose changes\n" 17730d63cfbaSjsing " M - disklabel(8) man page z - delete all partitions\n" 17740d63cfbaSjsing " m [part] - modify partition\n" 1775c4884206Skrw "\n" 1776c4884206Skrw "Suffixes can be used to indicate units other than sectors:\n" 1777e5f81948Sotto " 'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes) 't' (terabytes)\n" 1778e5f81948Sotto " 'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n" 1779c4884206Skrw "Values in non-sector units are truncated to the nearest cylinder boundary."); 17804d812bb6Slum 1781617e6e4aSmillert } 1782bd6726faSmillert 17834f3bbbf0Skrw void 17848809fabbSderaadt mpcopy(char **to, char **from) 1785bd6726faSmillert { 1786bd6726faSmillert int i; 17870612d09dSderaadt char *top; 1788bd6726faSmillert 1789bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1790bd6726faSmillert if (from[i] != NULL) { 1791dcab0d16Sderaadt int len = strlen(from[i]) + 1; 1792dcab0d16Sderaadt 17930612d09dSderaadt top = realloc(to[i], len); 17940612d09dSderaadt if (top == NULL) 1795bd6726faSmillert errx(4, "out of memory"); 17960612d09dSderaadt to[i] = top; 1797dcab0d16Sderaadt (void)strlcpy(to[i], from[i], len); 1798bd6726faSmillert } else if (to[i] != NULL) { 1799bd6726faSmillert free(to[i]); 1800bd6726faSmillert to[i] = NULL; 1801bd6726faSmillert } 1802bd6726faSmillert } 1803bd6726faSmillert } 1804bd6726faSmillert 1805bd6726faSmillert int 18068809fabbSderaadt mpequal(char **mp1, char **mp2) 1807bd6726faSmillert { 1808bd6726faSmillert int i; 1809bd6726faSmillert 1810bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1811bd6726faSmillert if (mp1[i] == NULL && mp2[i] == NULL) 1812bd6726faSmillert continue; 1813bd6726faSmillert 1814bd6726faSmillert if ((mp1[i] != NULL && mp2[i] == NULL) || 1815bd6726faSmillert (mp1[i] == NULL && mp2[i] != NULL) || 1816bd6726faSmillert (strcmp(mp1[i], mp2[i]) != 0)) 1817bd6726faSmillert return(0); 1818bd6726faSmillert } 1819bd6726faSmillert return(1); 1820bd6726faSmillert } 1821bd6726faSmillert 182293160b9bSkrw void 182334ae4198Skrw mpsave(struct disklabel *lp) 1824bd6726faSmillert { 1825d8b446ceSderaadt int i, j; 1826bd6726faSmillert char bdev[MAXPATHLEN], *p; 18273f843443Smillert struct mountinfo mi[MAXPARTITIONS]; 1828bd6726faSmillert FILE *fp; 1829fe01da94Skrw u_int8_t fstype; 1830bd6726faSmillert 183193160b9bSkrw if (!fstabfile) 183293160b9bSkrw return; 183393160b9bSkrw 18343f843443Smillert memset(&mi, 0, sizeof(mi)); 18353f843443Smillert 1836d8b446ceSderaadt for (i = 0; i < MAXPARTITIONS; i++) { 1837fe01da94Skrw fstype = lp->d_partitions[i].p_fstype; 1838fe01da94Skrw if (mountpoints[i] != NULL || fstype == FS_SWAP) { 183934ae4198Skrw mi[i].mountpoint = mountpoints[i]; 18403f843443Smillert mi[i].partno = i; 1841bd6726faSmillert } 1842bd6726faSmillert } 1843bd6726faSmillert 184434ae4198Skrw /* Convert specname to bdev */ 1845d6d80bb0Skrw if (uidflag) { 1846d6d80bb0Skrw snprintf(bdev, sizeof(bdev), 1847d6d80bb0Skrw "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 1848d6d80bb0Skrw lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3], 1849d6d80bb0Skrw lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7], 1850d6d80bb0Skrw specname[strlen(specname)-1]); 1851d6d80bb0Skrw } else if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 && 185234ae4198Skrw specname[sizeof(_PATH_DEV) - 1] == 'r') { 1853bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV, 185434ae4198Skrw &specname[sizeof(_PATH_DEV)]); 1855bd6726faSmillert } else { 185634ae4198Skrw if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r') 185793160b9bSkrw return; 1858bd6726faSmillert *p = '\0'; 185934ae4198Skrw snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1); 1860bd6726faSmillert *p = 'r'; 1861bd6726faSmillert } 1862bd6726faSmillert bdev[strlen(bdev) - 1] = '\0'; 1863bd6726faSmillert 18643f843443Smillert /* Sort mountpoints so we don't try to mount /usr/local before /usr */ 18653f843443Smillert qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp); 18663f843443Smillert 1867d71533c9Stedu if ((fp = fopen(fstabfile, "w"))) { 1868fe01da94Skrw for (i = 0; i < MAXPARTITIONS; i++) { 18695fea0b85Smillert j = mi[i].partno; 1870fe01da94Skrw fstype = lp->d_partitions[j].p_fstype; 1871fe01da94Skrw if (fstype == FS_SWAP) { 1872fe01da94Skrw fprintf(fp, "%s%c none swap sw\n", bdev, 'a'+j); 1873fe01da94Skrw } else if (mi[i].mountpoint) { 1874fe01da94Skrw fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 1875fe01da94Skrw 'a' + j, mi[i].mountpoint, 1876fe01da94Skrw fstypesnames[fstype], j == 0 ? 1 : 2); 1877fe01da94Skrw } 1878bd6726faSmillert } 1879bd6726faSmillert fclose(fp); 188093160b9bSkrw } 1881bd6726faSmillert } 188224a2c1a4Smillert 188324a2c1a4Smillert int 1884604d3bdeSkrw get_offset(struct disklabel *lp, int partno) 188524a2c1a4Smillert { 1886604d3bdeSkrw struct diskchunk *chunks; 188724a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 188815c15d8aSkrw u_int64_t ui, maxsize; 1889604d3bdeSkrw int i, fstype; 189024a2c1a4Smillert 1891dea75673Skrw ui = getuint(lp, "offset", 18921e0ad43cSotto "Starting sector for this partition.", 18931e0ad43cSotto DL_GETPOFFSET(pp), 18941e0ad43cSotto DL_GETPOFFSET(pp), 0, DO_CONVERSIONS | 189524a2c1a4Smillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 1896e9ff19beSkrw 1897e9ff19beSkrw if (ui == ULLONG_MAX - 1) 189824a2c1a4Smillert fputs("Command aborted\n", stderr); 1899e9ff19beSkrw else if (ui == ULLONG_MAX) 190024a2c1a4Smillert fputs("Invalid entry\n", stderr); 190140e98e9fSkrw else if (ui < starting_sector || ui >= ending_sector) 1902e9ff19beSkrw fprintf(stderr, "The offset must be >= %llu and < %llu, " 1903e9ff19beSkrw "the limits of the OpenBSD portion\n" 1904e9ff19beSkrw "of the disk. The 'b' command can change these limits.\n", 190540e98e9fSkrw starting_sector, ending_sector); 1906fc1a4cc6Sderaadt #ifdef SUN_AAT0 190749bf537cSderaadt else if (partno == 0 && ui != 0) 190849bf537cSderaadt fprintf(stderr, "This architecture requires that " 190940f544cdSderaadt "partition 'a' start at sector 0.\n"); 191049bf537cSderaadt #endif 191115c15d8aSkrw else { 1912604d3bdeSkrw fstype = pp->p_fstype; 1913604d3bdeSkrw pp->p_fstype = FS_UNUSED; 1914604d3bdeSkrw chunks = free_chunks(lp); 1915604d3bdeSkrw pp->p_fstype = fstype; 1916e9ff19beSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 1917e9ff19beSkrw if (ui < chunks[i].start || ui >= chunks[i].stop) 191815c15d8aSkrw continue; 19191e0ad43cSotto DL_SETPOFFSET(pp, ui); 192015c15d8aSkrw maxsize = chunks[i].stop - DL_GETPOFFSET(pp); 192115c15d8aSkrw if (DL_GETPSIZE(pp) > maxsize) 192215c15d8aSkrw DL_SETPSIZE(pp, maxsize); 192324a2c1a4Smillert return (0); 192424a2c1a4Smillert } 192515c15d8aSkrw fputs("The offset must be in a free area.\n", stderr); 192615c15d8aSkrw } 1927e9ff19beSkrw 1928e9ff19beSkrw /* Partition offset was not set. */ 1929e9ff19beSkrw return (1); 193015c15d8aSkrw } 193124a2c1a4Smillert 193224a2c1a4Smillert int 19339fdcb4d6Skrw get_size(struct disklabel *lp, int partno) 193424a2c1a4Smillert { 193524a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 193614192793Skrw u_int64_t maxsize, ui; 193714192793Skrw 193814192793Skrw maxsize = max_partition_size(lp, partno); 193924a2c1a4Smillert 1940dea75673Skrw ui = getuint(lp, "size", "Size of the partition. " 19417da73705Skrw "You may also say +/- amount for a relative change.", 194214192793Skrw DL_GETPSIZE(pp), maxsize, DL_GETPOFFSET(pp), 1943525051f1Sotto DO_CONVERSIONS | ((pp->p_fstype == FS_BSDFFS || 1944525051f1Sotto pp->p_fstype == FS_SWAP) ? DO_ROUNDING : 0)); 1945e9ff19beSkrw 1946e9ff19beSkrw if (ui == ULLONG_MAX - 1) 194724a2c1a4Smillert fputs("Command aborted\n", stderr); 1948e9ff19beSkrw else if (ui == ULLONG_MAX) 194924a2c1a4Smillert fputs("Invalid entry\n", stderr); 195028e3704eSkrw else if (ui == 0) 195128e3704eSkrw fputs("The size must be > 0\n", stderr); 195240e98e9fSkrw else if (ui + DL_GETPOFFSET(pp) > ending_sector) 195340e98e9fSkrw fprintf(stderr, "The size can't be more than " 195440e98e9fSkrw "%llu sectors, or the partition would\n" 195540e98e9fSkrw "extend beyond the last sector (%llu) of the " 195640e98e9fSkrw "OpenBSD portion of\nthe disk. " 195740e98e9fSkrw "The 'b' command can change this limit.\n", 195840e98e9fSkrw ending_sector - DL_GETPOFFSET(pp), ending_sector); 195914192793Skrw else if (ui > maxsize) 196014192793Skrw fprintf(stderr,"Sorry, there are only %llu sectors left\n", 196114192793Skrw maxsize); 196259ccf790Skrw else { 196359ccf790Skrw DL_SETPSIZE(pp, ui); 196424a2c1a4Smillert return (0); 196524a2c1a4Smillert } 1966e9ff19beSkrw 1967e9ff19beSkrw /* Partition size was not set. */ 1968e9ff19beSkrw return (1); 1969e9ff19beSkrw } 197024a2c1a4Smillert 197124a2c1a4Smillert int 19728809fabbSderaadt get_fsize(struct disklabel *lp, int partno) 197324a2c1a4Smillert { 19741e0ad43cSotto u_int64_t ui, fsize, frag; 197524a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 197624a2c1a4Smillert 1977a4c87e64Skrw if (!expert || pp->p_fstype != FS_BSDFFS) 1978a4c87e64Skrw return (0); 1979a4c87e64Skrw 1980ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 1981ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 1982ddfcbf38Sotto if (fsize == 0) 1983ddfcbf38Sotto frag = 8; 1984ddfcbf38Sotto 198524a2c1a4Smillert for (;;) { 1986dea75673Skrw ui = getuint(lp, "fragment size", 19873c92d7f2Stedu "Size of fs block fragments. Usually 2048 or 512.", 1988ddfcbf38Sotto fsize, fsize, 0, 0); 19891e0ad43cSotto if (ui == ULLONG_MAX - 1) { 199024a2c1a4Smillert fputs("Command aborted\n", stderr); 199124a2c1a4Smillert return(1); 19921e0ad43cSotto } else if (ui == ULLONG_MAX) 199324a2c1a4Smillert fputs("Invalid entry\n", stderr); 199424a2c1a4Smillert else 199524a2c1a4Smillert break; 199624a2c1a4Smillert } 199724a2c1a4Smillert if (ui == 0) 199824a2c1a4Smillert puts("Zero fragment size implies zero block size"); 1999ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag); 200024a2c1a4Smillert return(0); 200124a2c1a4Smillert } 200224a2c1a4Smillert 200324a2c1a4Smillert int 20048809fabbSderaadt get_bsize(struct disklabel *lp, int partno) 200524a2c1a4Smillert { 2006a49bdda8Skrw u_int64_t adj, ui, bsize, frag, fsize; 200724a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 200824a2c1a4Smillert 2009a49bdda8Skrw if (pp->p_fstype != FS_BSDFFS) 2010a4c87e64Skrw return (0); 2011a4c87e64Skrw 201224a2c1a4Smillert /* Avoid dividing by zero... */ 2013ddfcbf38Sotto if (pp->p_fragblock == 0) 201424a2c1a4Smillert return(1); 2015ddfcbf38Sotto 2016a49bdda8Skrw if (!expert) 2017a49bdda8Skrw goto align; 2018a49bdda8Skrw 2019ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 2020ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 202124a2c1a4Smillert 202224a2c1a4Smillert for (;;) { 2023dea75673Skrw ui = getuint(lp, "block size", 20243c92d7f2Stedu "Size of filesystem blocks. Usually 16384 or 4096.", 2025ddfcbf38Sotto fsize * frag, fsize * frag, 202624a2c1a4Smillert 0, 0); 202724a2c1a4Smillert 202824a2c1a4Smillert /* sanity checks */ 20291e0ad43cSotto if (ui == ULLONG_MAX - 1) { 203024a2c1a4Smillert fputs("Command aborted\n", stderr); 203124a2c1a4Smillert return(1); 20321e0ad43cSotto } else if (ui == ULLONG_MAX) 203324a2c1a4Smillert fputs("Invalid entry\n", stderr); 203424a2c1a4Smillert else if (ui < getpagesize()) 203524a2c1a4Smillert fprintf(stderr, 203624a2c1a4Smillert "Error: block size must be at least as big " 203724a2c1a4Smillert "as page size (%d).\n", getpagesize()); 2038ddfcbf38Sotto else if (ui % fsize != 0) 203924a2c1a4Smillert fputs("Error: block size must be a multiple of the " 204024a2c1a4Smillert "fragment size.\n", stderr); 2041ddfcbf38Sotto else if (ui / fsize < 1) 204224a2c1a4Smillert fputs("Error: block size must be at least as big as " 204324a2c1a4Smillert "fragment size.\n", stderr); 204424a2c1a4Smillert else 204524a2c1a4Smillert break; 204624a2c1a4Smillert } 2047ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui / frag, frag); 2048a49bdda8Skrw 2049a49bdda8Skrw align: 2050a49bdda8Skrw #ifndef SUN_CYLCHECK 2051a49bdda8Skrw bsize = (DISKLABELV1_FFS_FRAG(pp->p_fragblock) * 2052a49bdda8Skrw DISKLABELV1_FFS_FSIZE(pp->p_fragblock)) / lp->d_secsize; 2053a49bdda8Skrw if (DL_GETPOFFSET(pp) != starting_sector) { 2054a49bdda8Skrw /* Can't change offset of first partition. */ 2055a49bdda8Skrw adj = bsize - (DL_GETPOFFSET(pp) % bsize); 2056a49bdda8Skrw if (adj != 0 && adj != bsize) { 2057a49bdda8Skrw DL_SETPOFFSET(pp, DL_GETPOFFSET(pp) + adj); 2058a49bdda8Skrw DL_SETPSIZE(pp, DL_GETPSIZE(pp) - adj); 2059a49bdda8Skrw } 2060a49bdda8Skrw } 2061a49bdda8Skrw /* Always align end. */ 2062a49bdda8Skrw adj = (DL_GETPOFFSET(pp) + DL_GETPSIZE(pp)) % bsize; 2063a49bdda8Skrw if (adj > 0) 2064a49bdda8Skrw DL_SETPSIZE(pp, DL_GETPSIZE(pp) - adj); 2065a49bdda8Skrw #endif 206624a2c1a4Smillert return(0); 206724a2c1a4Smillert } 206824a2c1a4Smillert 206924a2c1a4Smillert int 20708809fabbSderaadt get_fstype(struct disklabel *lp, int partno) 207124a2c1a4Smillert { 207224a2c1a4Smillert char *p; 20731e0ad43cSotto u_int64_t ui; 207424a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 207524a2c1a4Smillert 207624a2c1a4Smillert if (pp->p_fstype < FSMAXTYPES) { 2077c33fcabaSmillert p = getstring("FS type", 207824a2c1a4Smillert "Filesystem type (usually 4.2BSD or swap)", 207924a2c1a4Smillert fstypenames[pp->p_fstype]); 208024a2c1a4Smillert if (p == NULL) { 208124a2c1a4Smillert fputs("Command aborted\n", stderr); 208224a2c1a4Smillert return(1); 208324a2c1a4Smillert } 208424a2c1a4Smillert for (ui = 0; ui < FSMAXTYPES; ui++) { 208524a2c1a4Smillert if (!strcasecmp(p, fstypenames[ui])) { 208624a2c1a4Smillert pp->p_fstype = ui; 208724a2c1a4Smillert break; 208824a2c1a4Smillert } 208924a2c1a4Smillert } 209024a2c1a4Smillert if (ui >= FSMAXTYPES) { 209124a2c1a4Smillert printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p); 209224a2c1a4Smillert pp->p_fstype = FS_OTHER; 209324a2c1a4Smillert } 209424a2c1a4Smillert } else { 209524a2c1a4Smillert for (;;) { 2096dea75673Skrw ui = getuint(lp, "FS type (decimal)", 209724a2c1a4Smillert "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", 209824a2c1a4Smillert pp->p_fstype, pp->p_fstype, 0, 0); 20991e0ad43cSotto if (ui == ULLONG_MAX - 1) { 210024a2c1a4Smillert fputs("Command aborted\n", stderr); 210124a2c1a4Smillert return(1); 21021e0ad43cSotto } if (ui == ULLONG_MAX) 210324a2c1a4Smillert fputs("Invalid entry\n", stderr); 210424a2c1a4Smillert else 210524a2c1a4Smillert break; 210624a2c1a4Smillert } 210724a2c1a4Smillert pp->p_fstype = ui; 210824a2c1a4Smillert } 210924a2c1a4Smillert return(0); 211024a2c1a4Smillert } 211124a2c1a4Smillert 211224a2c1a4Smillert int 211334ae4198Skrw get_mp(struct disklabel *lp, int partno) 211424a2c1a4Smillert { 211524a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 2116ec9fde5fSkrw char *p; 2117ec9fde5fSkrw int i; 211824a2c1a4Smillert 211934ae4198Skrw if (fstabfile && pp->p_fstype != FS_UNUSED && 212024a2c1a4Smillert pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT && 212124a2c1a4Smillert pp->p_fstype != FS_OTHER) { 2122ddaff619Smillert for (;;) { 2123c33fcabaSmillert p = getstring("mount point", 212424a2c1a4Smillert "Where to mount this filesystem (ie: / /var /usr)", 212534ae4198Skrw mountpoints[partno] ? mountpoints[partno] : "none"); 212624a2c1a4Smillert if (p == NULL) { 212724a2c1a4Smillert fputs("Command aborted\n", stderr); 212824a2c1a4Smillert return(1); 212924a2c1a4Smillert } 2130ddaff619Smillert if (strcasecmp(p, "none") == 0) { 213134ae4198Skrw free(mountpoints[partno]); 213234ae4198Skrw mountpoints[partno] = NULL; 2133ddaff619Smillert break; 2134ddaff619Smillert } 2135ec9fde5fSkrw for (i = 0; i < MAXPARTITIONS; i++) 213693160b9bSkrw if (mountpoints[i] != NULL && i != partno && 2137ec9fde5fSkrw strcmp(p, mountpoints[i]) == 0) 2138ec9fde5fSkrw break; 2139ec9fde5fSkrw if (i < MAXPARTITIONS) { 214093160b9bSkrw fprintf(stderr, "'%c' already being mounted at " 214193160b9bSkrw "'%s'\n", 'a'+i, p); 2142ec9fde5fSkrw break; 2143ec9fde5fSkrw } 2144ddaff619Smillert if (*p == '/') { 2145ddaff619Smillert /* XXX - might as well realloc */ 214634ae4198Skrw free(mountpoints[partno]); 214734ae4198Skrw if ((mountpoints[partno] = strdup(p)) == NULL) 214824a2c1a4Smillert errx(4, "out of memory"); 2149ddaff619Smillert break; 2150ddaff619Smillert } 2151ddaff619Smillert fputs("Mount points must start with '/'\n", stderr); 215224a2c1a4Smillert } 215324a2c1a4Smillert } 215424a2c1a4Smillert return(0); 215524a2c1a4Smillert } 21563f843443Smillert 21573f843443Smillert int 21588809fabbSderaadt micmp(const void *a1, const void *a2) 21593f843443Smillert { 21603f843443Smillert struct mountinfo *mi1 = (struct mountinfo *)a1; 21613f843443Smillert struct mountinfo *mi2 = (struct mountinfo *)a2; 21623f843443Smillert 21633f843443Smillert /* We want all the NULLs at the end... */ 21643f843443Smillert if (mi1->mountpoint == NULL && mi2->mountpoint == NULL) 21653f843443Smillert return(0); 21663f843443Smillert else if (mi1->mountpoint == NULL) 21673f843443Smillert return(1); 21683f843443Smillert else if (mi2->mountpoint == NULL) 21693f843443Smillert return(-1); 21703f843443Smillert else 21713f843443Smillert return(strcmp(mi1->mountpoint, mi2->mountpoint)); 21723f843443Smillert } 2173c33fcabaSmillert 2174c33fcabaSmillert void 217587023ed9Skrw get_geometry(int f, struct disklabel **dgpp) 2176c33fcabaSmillert { 2177c33fcabaSmillert struct stat st; 2178c33fcabaSmillert struct disklabel *disk_geop; 217987023ed9Skrw 2180c33fcabaSmillert if (fstat(f, &st) == -1) 2181c33fcabaSmillert err(4, "Can't stat device"); 2182c33fcabaSmillert 2183c33fcabaSmillert /* Get disk geometry */ 2184c33fcabaSmillert if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL) 2185c33fcabaSmillert errx(4, "out of memory"); 21869a379a6cSkrw if (ioctl(f, DIOCGPDINFO, disk_geop) < 0) 21879a379a6cSkrw err(4, "ioctl DIOCGPDINFO"); 2188c33fcabaSmillert *dgpp = disk_geop; 2189c33fcabaSmillert } 2190c33fcabaSmillert 2191c33fcabaSmillert void 21928809fabbSderaadt set_geometry(struct disklabel *lp, struct disklabel *dgp, 219387023ed9Skrw struct disklabel *ugp, char *p) 2194c33fcabaSmillert { 2195c33fcabaSmillert if (p == NULL) { 21969a36aa41Ssthen p = getstring("[d]isk or [u]ser geometry", 2197c33fcabaSmillert "Enter 'd' to use the geometry based on what the disk " 21989a36aa41Ssthen "itself thinks it is, or 'u' to use the geometry that " 21999a36aa41Ssthen "was found in the label.", 2200c33fcabaSmillert "d"); 2201c33fcabaSmillert } 2202c33fcabaSmillert if (p == NULL) { 2203c33fcabaSmillert fputs("Command aborted\n", stderr); 2204c33fcabaSmillert return; 2205c33fcabaSmillert } 2206c33fcabaSmillert switch (*p) { 2207c33fcabaSmillert case 'd': 2208c33fcabaSmillert case 'D': 2209c33fcabaSmillert if (dgp == NULL) 2210c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2211c33fcabaSmillert else { 2212c33fcabaSmillert lp->d_secsize = dgp->d_secsize; 2213c33fcabaSmillert lp->d_nsectors = dgp->d_nsectors; 2214c33fcabaSmillert lp->d_ntracks = dgp->d_ntracks; 2215c33fcabaSmillert lp->d_ncylinders = dgp->d_ncylinders; 2216c33fcabaSmillert lp->d_secpercyl = dgp->d_secpercyl; 221734af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(dgp)); 2218c33fcabaSmillert } 2219c33fcabaSmillert break; 2220c33fcabaSmillert case 'u': 2221c33fcabaSmillert case 'U': 2222c33fcabaSmillert if (ugp == NULL) 2223c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2224c33fcabaSmillert else { 2225c33fcabaSmillert lp->d_secsize = ugp->d_secsize; 2226c33fcabaSmillert lp->d_nsectors = ugp->d_nsectors; 2227c33fcabaSmillert lp->d_ntracks = ugp->d_ntracks; 2228c33fcabaSmillert lp->d_ncylinders = ugp->d_ncylinders; 2229c33fcabaSmillert lp->d_secpercyl = ugp->d_secpercyl; 223034af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(ugp)); 2231c33fcabaSmillert if (dgp != NULL && ugp->d_secsize == dgp->d_secsize && 2232c33fcabaSmillert ugp->d_nsectors == dgp->d_nsectors && 2233c33fcabaSmillert ugp->d_ntracks == dgp->d_ntracks && 2234c33fcabaSmillert ugp->d_ncylinders == dgp->d_ncylinders && 2235c33fcabaSmillert ugp->d_secpercyl == dgp->d_secpercyl && 223634af67a3Sotto DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp)) 2237c33fcabaSmillert fputs("Note: user geometry is the same as disk " 2238c33fcabaSmillert "geometry.\n", stderr); 2239c33fcabaSmillert } 2240c33fcabaSmillert break; 2241c33fcabaSmillert default: 22429a36aa41Ssthen fputs("You must enter either 'd' or 'u'.\n", stderr); 2243c33fcabaSmillert break; 2244c33fcabaSmillert } 2245c33fcabaSmillert } 22469afbe9eeSmillert 22479afbe9eeSmillert void 22489fdcb4d6Skrw zero_partitions(struct disklabel *lp) 22499afbe9eeSmillert { 22509afbe9eeSmillert int i; 22519afbe9eeSmillert 2252b4ed6301Skrw for (i = 0; i < MAXPARTITIONS; i++) { 22539afbe9eeSmillert memset(&lp->d_partitions[i], 0, sizeof(struct partition)); 2254b4ed6301Skrw free(mountpoints[i]); 2255b4ed6301Skrw mountpoints[i] = NULL; 2256b4ed6301Skrw } 2257b4ed6301Skrw 225834af67a3Sotto DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); 22599afbe9eeSmillert } 226014192793Skrw 226114192793Skrw u_int64_t 226214192793Skrw max_partition_size(struct disklabel *lp, int partno) 226314192793Skrw { 226414192793Skrw struct partition *pp = &lp->d_partitions[partno]; 226514192793Skrw struct diskchunk *chunks; 226644ffe03bSotto u_int64_t maxsize = 0, offset; 226714192793Skrw int fstype, i; 226814192793Skrw 226914192793Skrw fstype = pp->p_fstype; 227014192793Skrw pp->p_fstype = FS_UNUSED; 227114192793Skrw chunks = free_chunks(lp); 227214192793Skrw pp->p_fstype = fstype; 227314192793Skrw 227414192793Skrw offset = DL_GETPOFFSET(pp); 227514192793Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 227614192793Skrw if (offset < chunks[i].start || offset >= chunks[i].stop) 227714192793Skrw continue; 227814192793Skrw maxsize = chunks[i].stop - offset; 227914192793Skrw break; 228014192793Skrw } 228114192793Skrw return (maxsize); 228214192793Skrw } 2283aff3f969Sotto 2284aff3f969Sotto void 2285aff3f969Sotto psize(daddr64_t sz, char unit, struct disklabel *lp) 2286aff3f969Sotto { 2287aff3f969Sotto double d = scale(sz, unit, lp); 2288aff3f969Sotto if (d < 0) 2289aff3f969Sotto printf("%llu", sz); 2290aff3f969Sotto else 2291aff3f969Sotto printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit); 2292aff3f969Sotto } 2293aff3f969Sotto 2294aff3f969Sotto void 229534ae4198Skrw display_edit(struct disklabel *lp, char unit, u_int64_t fr) 2296aff3f969Sotto { 2297aff3f969Sotto int i; 2298aff3f969Sotto 2299352d199bSkrw unit = canonical_unit(lp, unit); 2300aff3f969Sotto 2301aff3f969Sotto printf("OpenBSD area: "); 230259882f1dSkrw psize(starting_sector, 0, lp); 2303aff3f969Sotto printf("-"); 230459882f1dSkrw psize(ending_sector, 0, lp); 2305aff3f969Sotto printf("; size: "); 2306aff3f969Sotto psize(ending_sector - starting_sector, unit, lp); 2307aff3f969Sotto printf("; free: "); 2308aff3f969Sotto psize(fr, unit, lp); 2309aff3f969Sotto 2310aff3f969Sotto printf("\n# %16.16s %16.16s fstype [fsize bsize cpg]\n", 2311aff3f969Sotto "size", "offset"); 2312aff3f969Sotto for (i = 0; i < lp->d_npartitions; i++) 231334ae4198Skrw display_partition(stdout, lp, i, unit); 2314aff3f969Sotto } 2315aff3f969Sotto 2316