1*5f012d92Snaddy /* $OpenBSD: editor.c,v 1.366 2021/02/03 14:41:40 naddy Exp $ */ 26fe57b42Smillert 36fe57b42Smillert /* 4bf198cc6Smillert * Copyright (c) 1997-2000 Todd C. Miller <millert@openbsd.org> 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 1978eb0b7eSderaadt #include <sys/param.h> /* MAXBSIZE DEV_BSIZE */ 206fe57b42Smillert #include <sys/types.h> 21b9fc9a72Sderaadt #include <sys/signal.h> 22c33fcabaSmillert #include <sys/stat.h> 23c33fcabaSmillert #include <sys/ioctl.h> 2491f4f7d8Sdlg #include <sys/dkio.h> 258dde8bb6Sotto #include <sys/sysctl.h> 266fe57b42Smillert #define DKTYPENAMES 276fe57b42Smillert #include <sys/disklabel.h> 286fe57b42Smillert 296fe57b42Smillert #include <ufs/ffs/fs.h> 306fe57b42Smillert 316fe57b42Smillert #include <ctype.h> 326fe57b42Smillert #include <err.h> 336fe57b42Smillert #include <errno.h> 346fe57b42Smillert #include <string.h> 35803ff7d5Smillert #include <libgen.h> 36f1bc1b27Skrw #include <stdint.h> 376fe57b42Smillert #include <stdio.h> 386fe57b42Smillert #include <stdlib.h> 396fe57b42Smillert #include <unistd.h> 40b9fc9a72Sderaadt #include <limits.h> 416fe57b42Smillert 42f21a098bSotto #include "extern.h" 434793b14cSmillert #include "pathnames.h" 444793b14cSmillert 45b9fc9a72Sderaadt #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) 46b9fc9a72Sderaadt 47117239d3Skrw /* flags for getuint64() */ 486fe57b42Smillert #define DO_CONVERSIONS 0x00000001 496fe57b42Smillert #define DO_ROUNDING 0x00000002 506fe57b42Smillert 5140b226e8Skrw /* flags for alignpartition() */ 5240b226e8Skrw #define ROUND_OFFSET_UP 0x00000001 5340b226e8Skrw #define ROUND_OFFSET_DOWN 0x00000002 5440b226e8Skrw #define ROUND_SIZE_UP 0x00000004 5540b226e8Skrw #define ROUND_SIZE_DOWN 0x00000008 56922b28b8Skrw #define ROUND_SIZE_OVERLAP 0x00000010 5740b226e8Skrw 580db7769aSkrw /* Special return values for getnumber and getuint64() */ 59aa3970cdSkrw #define CMD_ABORTED (ULLONG_MAX - 1) 60aa3970cdSkrw #define CMD_BADVALUE (ULLONG_MAX) 61aa3970cdSkrw 6296a888c6Smillert /* structure to describe a portion of a disk */ 6396a888c6Smillert struct diskchunk { 641e0ad43cSotto u_int64_t start; 651e0ad43cSotto u_int64_t stop; 6696a888c6Smillert }; 6796a888c6Smillert 683f843443Smillert /* used when sorting mountpoints in mpsave() */ 693f843443Smillert struct mountinfo { 703f843443Smillert char *mountpoint; 713f843443Smillert int partno; 723f843443Smillert }; 733f843443Smillert 74557f712bSkrw /* used when allocating all space according to recommendations */ 75557f712bSkrw 76557f712bSkrw struct space_allocation { 77eafadddfSkrw u_int64_t minsz; /* starts as blocks, xlated to sectors. */ 78eafadddfSkrw u_int64_t maxsz; /* starts as blocks, xlated to sectors. */ 79557f712bSkrw int rate; /* % of extra space to use */ 80557f712bSkrw char *mp; 81557f712bSkrw }; 82557f712bSkrw 83e485502dSkrw /* 84e485502dSkrw * NOTE! Changing partition sizes in the space_allocation tables 85e485502dSkrw * requires corresponding updates to the *.ok files in 86e485502dSkrw * /usr/src/regress/sbin/disklabel. 87e485502dSkrw */ 88e485502dSkrw 898dde8bb6Sotto /* entries for swap and var are changed by editor_allocspace() */ 90a2c1f847Shenning struct space_allocation alloc_big[] = { 91d190517aSotto { MEG(150), GIG(1), 5, "/" }, 92559340afSotto { MEG(80), MEG(256), 10, "swap" }, 934ab111d2Sderaadt { MEG(120), GIG(4), 8, "/tmp" }, 9492adb55fSderaadt { MEG(80), GIG(4), 13, "/var" }, 9526e633f4Sotto { MEG(1500), GIG(6), 10, "/usr" }, 96ecf06799Sajacoutot { MEG(384), GIG(1), 3, "/usr/X11R6" }, 9797f090a4Ssolene { GIG(1), GIG(20), 15, "/usr/local" }, 98aa4db624Sbenno { MEG(1300), GIG(2), 2, "/usr/src" }, 99d6b9791fSbluhm { GIG(5), GIG(6), 4, "/usr/obj" }, 10026e633f4Sotto { GIG(1), GIG(300), 30, "/home" } 1014ab111d2Sderaadt /* Anything beyond this leave for the user to decide */ 1028dde8bb6Sotto }; 1038dde8bb6Sotto 104a2c1f847Shenning struct space_allocation alloc_medium[] = { 105905e8239Sderaadt { MEG(800), GIG(2), 5, "/" }, 1068dde8bb6Sotto { MEG(80), MEG(256), 10, "swap" }, 107ad1fb99dSphessler { MEG(1300), GIG(3), 78, "/usr" }, 108905e8239Sderaadt { MEG(256), GIG(2), 7, "/home" } 1098dde8bb6Sotto }; 1108dde8bb6Sotto 111a2c1f847Shenning struct space_allocation alloc_small[] = { 11292adb55fSderaadt { MEG(700), GIG(4), 95, "/" }, 1138dde8bb6Sotto { MEG(1), MEG(256), 5, "swap" } 1148dde8bb6Sotto }; 1158dde8bb6Sotto 116a2c1f847Shenning struct space_allocation alloc_stupid[] = { 1178dde8bb6Sotto { MEG(1), MEG(2048), 100, "/" } 1188dde8bb6Sotto }; 1198dde8bb6Sotto 120b2813ff1Sderaadt #ifndef nitems 121b2813ff1Sderaadt #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 122b2813ff1Sderaadt #endif 123b2813ff1Sderaadt 124a2c1f847Shenning struct alloc_table { 125a2c1f847Shenning struct space_allocation *table; 1268a862940Sderaadt int sz; 127a2c1f847Shenning }; 128a2c1f847Shenning 129a2c1f847Shenning struct alloc_table alloc_table_default[] = { 1308dde8bb6Sotto { alloc_big, nitems(alloc_big) }, 1318dde8bb6Sotto { alloc_medium, nitems(alloc_medium) }, 1328dde8bb6Sotto { alloc_small, nitems(alloc_small) }, 1338dde8bb6Sotto { alloc_stupid, nitems(alloc_stupid) } 134557f712bSkrw }; 135a2c1f847Shenning struct alloc_table *alloc_table = alloc_table_default; 136f55524eaSsthen int alloc_table_nitems = 4; 137557f712bSkrw 1389fdcb4d6Skrw void edit_parms(struct disklabel *); 1396aaa4aabSotto void editor_resize(struct disklabel *, char *); 14034ae4198Skrw void editor_add(struct disklabel *, char *); 1419fdcb4d6Skrw void editor_change(struct disklabel *, char *); 1429fdcb4d6Skrw u_int64_t editor_countfree(struct disklabel *); 14334ae4198Skrw void editor_delete(struct disklabel *, char *); 1444d812bb6Slum void editor_help(void); 14534ae4198Skrw void editor_modify(struct disklabel *, char *); 14634ae4198Skrw void editor_name(struct disklabel *, char *); 147b228e876Smiod char *getstring(const char *, const char *, const char *); 14840b226e8Skrw u_int64_t getuint64(struct disklabel *, char *, char *, u_int64_t, 14940b226e8Skrw u_int64_t, int *); 1500db7769aSkrw u_int64_t getnumber(char *, char *, u_int32_t, u_int32_t); 1511f0f871dSkrw int has_overlap(struct disklabel *); 152c72b5b24Smillert int partition_cmp(const void *, const void *); 1530fbd3c97Skrw struct partition **sort_partitions(struct disklabel *); 154c72b5b24Smillert void getdisktype(struct disklabel *, char *, char *); 15587023ed9Skrw void find_bounds(struct disklabel *); 1569fdcb4d6Skrw void set_bounds(struct disklabel *); 15769a6ffbcSjsing void set_duid(struct disklabel *); 158c72b5b24Smillert struct diskchunk *free_chunks(struct disklabel *); 159c72b5b24Smillert int micmp(const void *, const void *); 160c72b5b24Smillert int mpequal(char **, char **); 161c72b5b24Smillert int get_bsize(struct disklabel *, int); 162c72b5b24Smillert int get_fsize(struct disklabel *, int); 163a95dd767Sotto int get_cpg(struct disklabel *, int); 164c72b5b24Smillert int get_fstype(struct disklabel *, int); 16534ae4198Skrw int get_mp(struct disklabel *, int); 166604d3bdeSkrw int get_offset(struct disklabel *, int); 1679fdcb4d6Skrw int get_size(struct disklabel *, int); 16887023ed9Skrw void get_geometry(int, struct disklabel **); 16987023ed9Skrw void set_geometry(struct disklabel *, struct disklabel *, struct disklabel *, 17087023ed9Skrw char *); 1719fdcb4d6Skrw void zero_partitions(struct disklabel *); 17214192793Skrw u_int64_t max_partition_size(struct disklabel *, int); 1737ad973c1Skrw void display_edit(struct disklabel *, char); 174e07939ebSderaadt void psize(u_int64_t sz, char unit, struct disklabel *lp); 17558c7d7acSnaddy char *get_token(char **); 176a2c1f847Shenning int apply_unit(double, u_char, u_int64_t *); 177a2c1f847Shenning int parse_sizespec(const char *, double *, char **); 178a2c1f847Shenning int parse_sizerange(char *, u_int64_t *, u_int64_t *); 179a2c1f847Shenning int parse_pct(char *, int *); 18040b226e8Skrw int alignpartition(struct disklabel *, int, u_int64_t, u_int64_t, int); 18196a888c6Smillert 1821e0ad43cSotto static u_int64_t starting_sector; 1831e0ad43cSotto static u_int64_t ending_sector; 1842d8451b0Smillert static int expert; 185fc6e9c48Sotto static int overlap; 1866fe57b42Smillert 1876fe57b42Smillert /* 1884d4a335eSkrw * Simple partition editor. 1896fe57b42Smillert */ 1906fe57b42Smillert int 191d6d80bb0Skrw editor(int f) 1926fe57b42Smillert { 193d6d80bb0Skrw struct disklabel origlabel, lastlabel, tmplabel, newlab = lab; 1947e28fb0fSderaadt struct disklabel *disk_geop = NULL; 19596a888c6Smillert struct partition *pp; 1966fe57b42Smillert FILE *fp; 1976fe57b42Smillert char buf[BUFSIZ], *cmd, *arg; 19834ae4198Skrw char **omountpoints = NULL; 1994f3bbbf0Skrw char **origmountpoints = NULL, **tmpmountpoints = NULL; 2007e28fb0fSderaadt int i, error = 0; 201bd6726faSmillert 202bd6726faSmillert /* Alloc and init mount point info */ 20334ae4198Skrw if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 2044f3bbbf0Skrw !(origmountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 205bd6726faSmillert !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *)))) 206bd6726faSmillert errx(4, "out of memory"); 2076fe57b42Smillert 20896a888c6Smillert /* Don't allow disk type of "unknown" */ 209430e1380Skrw getdisktype(&newlab, "You need to specify a type for this disk.", 210430e1380Skrw specname); 2116fe57b42Smillert 21287023ed9Skrw /* Get the on-disk geometries if possible */ 21387023ed9Skrw get_geometry(f, &disk_geop); 214c33fcabaSmillert 215d09f3941Smillert /* How big is the OpenBSD portion of the disk? */ 216d6d80bb0Skrw find_bounds(&newlab); 217d09f3941Smillert 21896a888c6Smillert /* Make sure there is no partition overlap. */ 219d6d80bb0Skrw if (has_overlap(&newlab)) 2206fe57b42Smillert errx(1, "can't run when there is partition overlap."); 2216fe57b42Smillert 22296a888c6Smillert /* If we don't have a 'c' partition, create one. */ 223d6d80bb0Skrw pp = &newlab.d_partitions[RAW_PART]; 224d6d80bb0Skrw if (newlab.d_npartitions < 3 || DL_GETPSIZE(pp) == 0) { 22596a888c6Smillert puts("No 'c' partition found, adding one that spans the disk."); 226d6d80bb0Skrw if (newlab.d_npartitions < 3) 227d6d80bb0Skrw newlab.d_npartitions = 3; 22834af67a3Sotto DL_SETPOFFSET(pp, 0); 229d6d80bb0Skrw DL_SETPSIZE(pp, DL_GETDSIZE(&newlab)); 23096a888c6Smillert pp->p_fstype = FS_UNUSED; 231ddfcbf38Sotto pp->p_fragblock = pp->p_cpg = 0; 23296a888c6Smillert } 2330f820bbbSmillert 234fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 2354bf1fc9dSotto if ((newlab.d_flags & D_VENDOR) && !quiet) { 236fc1a4cc6Sderaadt puts("This platform requires that partition offsets/sizes " 237fc1a4cc6Sderaadt "be on cylinder boundaries.\n" 238fc1a4cc6Sderaadt "Partition offsets/sizes will be rounded to the " 239fc1a4cc6Sderaadt "nearest cylinder automatically."); 240fc1a4cc6Sderaadt } 2416fe57b42Smillert #endif 2426fe57b42Smillert 243bd6726faSmillert /* Set d_bbsize and d_sbsize as necessary */ 244d6d80bb0Skrw if (newlab.d_bbsize == 0) 245d6d80bb0Skrw newlab.d_bbsize = BBSIZE; 246d6d80bb0Skrw if (newlab.d_sbsize == 0) 247d6d80bb0Skrw newlab.d_sbsize = SBSIZE; 248f98aebd4Smillert 24993160b9bSkrw /* Save the (U|u)ndo labels and mountpoints. */ 25093160b9bSkrw mpcopy(origmountpoints, mountpoints); 251d6d80bb0Skrw origlabel = newlab; 252d6d80bb0Skrw lastlabel = newlab; 25334ae4198Skrw 25434ae4198Skrw puts("Label editor (enter '?' for help at any prompt)"); 2556fe57b42Smillert for (;;) { 256cbfc0aa2Skrw fprintf(stdout, "%s%s%c ", dkname, 257cbfc0aa2Skrw (memcmp(&lab, &newlab, sizeof(newlab)) == 0) ? "" : "*", 258cbfc0aa2Skrw (expert == 0) ? '>' : '#'); 2596e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 2606e0becc5Smillert putchar('\n'); 2616e0becc5Smillert buf[0] = 'q'; 2626e0becc5Smillert buf[1] = '\0'; 2636e0becc5Smillert } 264260513deSmillert if ((cmd = strtok(buf, " \t\r\n")) == NULL) 265260513deSmillert continue; 266260513deSmillert arg = strtok(NULL, " \t\r\n"); 2676fe57b42Smillert 2684f3bbbf0Skrw if ((*cmd != 'u') && (*cmd != 'U')) { 2694f3bbbf0Skrw /* 2704f3bbbf0Skrw * Save undo info in case the command tries to make 2714f3bbbf0Skrw * changes but decides not to. 2724f3bbbf0Skrw */ 2734f3bbbf0Skrw tmplabel = lastlabel; 274d6d80bb0Skrw lastlabel = newlab; 2754f3bbbf0Skrw mpcopy(tmpmountpoints, omountpoints); 2764f3bbbf0Skrw mpcopy(omountpoints, mountpoints); 2774f3bbbf0Skrw } 2786fe57b42Smillert 2794f3bbbf0Skrw switch (*cmd) { 2806fe57b42Smillert case '?': 281ea37abd3Sderaadt case 'h': 2824d812bb6Slum editor_help(); 2836fe57b42Smillert break; 2846fe57b42Smillert 285557f712bSkrw case 'A': 28690b0764fSkrw if (ioctl(f, DIOCGPDINFO, &newlab) == -1) { 28790b0764fSkrw warn("DIOCGPDINFO"); 28890b0764fSkrw newlab = lastlabel; 28990b0764fSkrw } else { 29040b226e8Skrw int oquiet = quiet, oexpert = expert; 2914bf1fc9dSotto aflag = 1; 29240b226e8Skrw quiet = expert = 0; 293d6d80bb0Skrw editor_allocspace(&newlab); 29440b226e8Skrw quiet = oquiet; 29540b226e8Skrw expert = oexpert; 29690b0764fSkrw } 297557f712bSkrw break; 2986fe57b42Smillert case 'a': 299d6d80bb0Skrw editor_add(&newlab, arg); 30096a888c6Smillert break; 30196a888c6Smillert 30296a888c6Smillert case 'b': 303d6d80bb0Skrw set_bounds(&newlab); 3046fe57b42Smillert break; 3056fe57b42Smillert 3066fe57b42Smillert case 'c': 307d6d80bb0Skrw editor_change(&newlab, arg); 3086fe57b42Smillert break; 3096fe57b42Smillert 3109afbe9eeSmillert case 'D': 31190b0764fSkrw if (ioctl(f, DIOCGPDINFO, &newlab) == -1) 31290b0764fSkrw warn("DIOCGPDINFO"); 31390b0764fSkrw else { 31471bba4ecSkrw dflag = 1; 31593160b9bSkrw for (i = 0; i < MAXPARTITIONS; i++) { 31693160b9bSkrw free(mountpoints[i]); 31793160b9bSkrw mountpoints[i] = NULL; 31893160b9bSkrw } 31990b0764fSkrw } 3209afbe9eeSmillert break; 3219afbe9eeSmillert 3226fe57b42Smillert case 'd': 323d6d80bb0Skrw editor_delete(&newlab, arg); 3246fe57b42Smillert break; 3256fe57b42Smillert 3269afbe9eeSmillert case 'e': 327d6d80bb0Skrw edit_parms(&newlab); 3289afbe9eeSmillert break; 3299afbe9eeSmillert 330c33fcabaSmillert case 'g': 331d6d80bb0Skrw set_geometry(&newlab, disk_geop, &lab, arg); 332c33fcabaSmillert break; 333c33fcabaSmillert 3340d63cfbaSjsing case 'i': 335d6d80bb0Skrw set_duid(&newlab); 3360d63cfbaSjsing break; 3370d63cfbaSjsing 3386fe57b42Smillert case 'm': 339d6d80bb0Skrw editor_modify(&newlab, arg); 340bd6726faSmillert break; 341bd6726faSmillert 342bd6726faSmillert case 'n': 3435c79e1cfSkrw if (!fstabfile) { 344bd6726faSmillert fputs("This option is not valid when run " 3456b27d9e0Sjmc "without the -F or -f flags.\n", stderr); 346bd6726faSmillert break; 347bd6726faSmillert } 348d6d80bb0Skrw editor_name(&newlab, arg); 3496fe57b42Smillert break; 3506fe57b42Smillert 3516fe57b42Smillert case 'p': 3527ad973c1Skrw display_edit(&newlab, arg ? *arg : 0); 3536fe57b42Smillert break; 3546fe57b42Smillert 355aff3f969Sotto case 'l': 356d6d80bb0Skrw display(stdout, &newlab, arg ? *arg : 0, 0); 357aff3f969Sotto break; 358aff3f969Sotto 359508086e9Smillert case 'M': { 360508086e9Smillert sig_t opipe = signal(SIGPIPE, SIG_IGN); 36145decb36Sderaadt char *pager, *comm = NULL; 362e7936562Sderaadt extern const u_char manpage[]; 36308f8e31fSotto extern const int manpage_sz; 3645d12b01bSderaadt 365489bd112Spjanzen if ((pager = getenv("PAGER")) == NULL || *pager == '\0') 366508086e9Smillert pager = _PATH_LESS; 36708f8e31fSotto 36845decb36Sderaadt if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 && 36945decb36Sderaadt (fp = popen(comm, "w")) != NULL) { 37008f8e31fSotto (void) fwrite(manpage, manpage_sz, 1, fp); 3715d12b01bSderaadt pclose(fp); 372508086e9Smillert } else 373508086e9Smillert warn("unable to execute %s", pager); 374508086e9Smillert 37545decb36Sderaadt free(comm); 376508086e9Smillert (void)signal(SIGPIPE, opipe); 3775d12b01bSderaadt break; 378508086e9Smillert } 3795d12b01bSderaadt 3806fe57b42Smillert case 'q': 38169220492Smillert if (donothing) { 38269220492Smillert puts("In no change mode, not writing label."); 3837e28fb0fSderaadt goto done; 38469220492Smillert } 38593160b9bSkrw 38671bba4ecSkrw /* 38793160b9bSkrw * If we haven't changed the original label, and it 38893160b9bSkrw * wasn't a default label or an auto-allocated label, 38993160b9bSkrw * there is no need to do anything before exiting. Note 39093160b9bSkrw * that 'w' will reset dflag and aflag to allow 'q' to 39193160b9bSkrw * exit without further questions. 39271bba4ecSkrw */ 393ab20a3eaSkrw if (!dflag && !aflag && 394d6d80bb0Skrw memcmp(&lab, &newlab, sizeof(newlab)) == 0) { 395bd6726faSmillert puts("No label changes."); 396d6d80bb0Skrw /* Save mountpoint info. */ 397d6d80bb0Skrw mpsave(&newlab); 3987e28fb0fSderaadt goto done; 3996fe57b42Smillert } 4006fe57b42Smillert do { 401d0e67762Smillert arg = getstring("Write new label?", 402d0e67762Smillert "Write the modified label to disk?", 403d0e67762Smillert "y"); 404025f5691Sderaadt } while (arg && tolower((unsigned char)*arg) != 'y' && 405025f5691Sderaadt tolower((unsigned char)*arg) != 'n'); 406025f5691Sderaadt if (arg && tolower((unsigned char)*arg) == 'y') { 40740bba581Skrw if (writelabel(f, &newlab) == 0) { 408d6d80bb0Skrw newlab = lab; /* lab now has UID info */ 4097e28fb0fSderaadt goto done; 4106fe57b42Smillert } 411d0e67762Smillert warnx("unable to write label"); 412d0e67762Smillert } 4137e28fb0fSderaadt error = 1; 4147e28fb0fSderaadt goto done; 4156fe57b42Smillert /* NOTREACHED */ 4166fe57b42Smillert break; 4176fe57b42Smillert 4186aaa4aabSotto case 'R': 419fc6e9c48Sotto if (aflag && !overlap) 420d6d80bb0Skrw editor_resize(&newlab, arg); 4216aaa4aabSotto else 4226aaa4aabSotto fputs("Resize only implemented for auto " 423fc6e9c48Sotto "allocated labels\n", stderr); 4246aaa4aabSotto break; 4256aaa4aabSotto 42625f9c360Skrw case 'r': { 42725f9c360Skrw struct diskchunk *chunks; 42825f9c360Skrw int i; 4299fdcb4d6Skrw /* Display free space. */ 430d6d80bb0Skrw chunks = free_chunks(&newlab); 43125f9c360Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; 43225f9c360Skrw i++) 43325f9c360Skrw fprintf(stderr, "Free sectors: %16llu - %16llu " 43425f9c360Skrw "(%16llu)\n", 43525f9c360Skrw chunks[i].start, chunks[i].stop - 1, 43625f9c360Skrw chunks[i].stop - chunks[i].start); 43725f9c360Skrw fprintf(stderr, "Total free sectors: %llu.\n", 438d6d80bb0Skrw editor_countfree(&newlab)); 439c0bdc608Smillert break; 44025f9c360Skrw } 441c0bdc608Smillert 4426fe57b42Smillert case 's': 4436fe57b42Smillert if (arg == NULL) { 444c33fcabaSmillert arg = getstring("Filename", 4456fe57b42Smillert "Name of the file to save label into.", 4466fe57b42Smillert NULL); 447e97229a3Scnst if (arg == NULL || *arg == '\0') 4486fe57b42Smillert break; 4496fe57b42Smillert } 4506fe57b42Smillert if ((fp = fopen(arg, "w")) == NULL) { 4516fe57b42Smillert warn("cannot open %s", arg); 4526fe57b42Smillert } else { 453d6d80bb0Skrw display(fp, &newlab, 0, 1); 4546fe57b42Smillert (void)fclose(fp); 4556fe57b42Smillert } 4566fe57b42Smillert break; 4576fe57b42Smillert 4584f3bbbf0Skrw case 'U': 45993160b9bSkrw /* 460430e1380Skrw * If we allow 'U' repeatedly, information would be 461430e1380Skrw * lost. This way multiple 'U's followed by 'u' will 462430e1380Skrw * undo the 'U's. 46393160b9bSkrw */ 464d6d80bb0Skrw if (memcmp(&newlab, &origlabel, sizeof(newlab)) || 46593160b9bSkrw !mpequal(mountpoints, origmountpoints)) { 466d6d80bb0Skrw tmplabel = newlab; 467d6d80bb0Skrw newlab = origlabel; 4684f3bbbf0Skrw lastlabel = tmplabel; 4694f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 4704f3bbbf0Skrw mpcopy(mountpoints, origmountpoints); 4714f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4724f3bbbf0Skrw } 47393160b9bSkrw puts("Original label and mount points restored."); 4744f3bbbf0Skrw break; 4754f3bbbf0Skrw 4766fe57b42Smillert case 'u': 477d6d80bb0Skrw tmplabel = newlab; 478d6d80bb0Skrw newlab = lastlabel; 4796fe57b42Smillert lastlabel = tmplabel; 4804f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 481bd6726faSmillert mpcopy(mountpoints, omountpoints); 4824f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4836fe57b42Smillert puts("Last change undone."); 4846fe57b42Smillert break; 4856fe57b42Smillert 486040947cfSmillert case 'w': 487bd6726faSmillert if (donothing) { 488040947cfSmillert puts("In no change mode, not writing label."); 489bd6726faSmillert break; 490bd6726faSmillert } 49193160b9bSkrw 49241f684b9Skrw /* Write label to disk. */ 49340bba581Skrw if (writelabel(f, &newlab) != 0) 494040947cfSmillert warnx("unable to write label"); 49571bba4ecSkrw else { 496ab20a3eaSkrw dflag = aflag = 0; 497d6d80bb0Skrw newlab = lab; /* lab now has UID info */ 49871bba4ecSkrw } 499040947cfSmillert break; 500040947cfSmillert 5012d8451b0Smillert case 'X': 5022d8451b0Smillert expert = !expert; 5032d8451b0Smillert printf("%s expert mode\n", expert ? "Entering" : 5042d8451b0Smillert "Exiting"); 5052d8451b0Smillert break; 5062d8451b0Smillert 5076fe57b42Smillert case 'x': 5087e28fb0fSderaadt goto done; 5096fe57b42Smillert break; 5106fe57b42Smillert 5119afbe9eeSmillert case 'z': 512d6d80bb0Skrw zero_partitions(&newlab); 5136fe57b42Smillert break; 5146fe57b42Smillert 5159afbe9eeSmillert case '\n': 5166fe57b42Smillert break; 5176fe57b42Smillert 5186fe57b42Smillert default: 5196fe57b42Smillert printf("Unknown option: %c ('?' for help)\n", *cmd); 5206fe57b42Smillert break; 5216fe57b42Smillert } 5224f3bbbf0Skrw 5234f3bbbf0Skrw /* 5244f3bbbf0Skrw * If no changes were made to label or mountpoints, then 5254f3bbbf0Skrw * restore undo info. 5264f3bbbf0Skrw */ 527d6d80bb0Skrw if (memcmp(&newlab, &lastlabel, sizeof(newlab)) == 0 && 52893160b9bSkrw (mpequal(mountpoints, omountpoints))) { 5294f3bbbf0Skrw lastlabel = tmplabel; 5304f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 5314f3bbbf0Skrw } 5326fe57b42Smillert } 5337e28fb0fSderaadt done: 534408ab9bcSkrw mpfree(omountpoints); 535408ab9bcSkrw mpfree(origmountpoints); 536408ab9bcSkrw mpfree(tmpmountpoints); 5377e28fb0fSderaadt free(disk_geop); 5387e28fb0fSderaadt return (error); 5396fe57b42Smillert } 5406fe57b42Smillert 5416fe57b42Smillert /* 542557f712bSkrw * Allocate all disk space according to standard recommendations for a 543557f712bSkrw * root disk. 544557f712bSkrw */ 545185664b4Sotto int 5468dde8bb6Sotto editor_allocspace(struct disklabel *lp_org) 547557f712bSkrw { 5488dde8bb6Sotto struct disklabel *lp, label; 5498dde8bb6Sotto struct space_allocation *alloc; 55034ae4198Skrw struct space_allocation *ap; 551557f712bSkrw struct partition *pp; 55234ae4198Skrw struct diskchunk *chunks; 553859c13c7Skrw u_int64_t chunkstart, chunkstop, chunksize; 55459c4e6f1Skrw u_int64_t cylsecs, secs, xtrasecs; 55534ae4198Skrw char **partmp; 5563c723e85Skrw int i, j, lastalloc, index, partno, freeparts; 557e384f6efSderaadt extern int64_t physmem; 5588dde8bb6Sotto 55934ae4198Skrw /* How big is the OpenBSD portion of the disk? */ 5608dde8bb6Sotto find_bounds(lp_org); 561557f712bSkrw 562fc6e9c48Sotto overlap = 0; 5633c723e85Skrw freeparts = 0; 564fc6e9c48Sotto for (i = 0; i < MAXPARTITIONS; i++) { 565eafadddfSkrw u_int64_t psz, pstart, pend; 566fc6e9c48Sotto 567fc6e9c48Sotto pp = &lp_org->d_partitions[i]; 568fc6e9c48Sotto psz = DL_GETPSIZE(pp); 5693c723e85Skrw if (psz == 0) 5703c723e85Skrw freeparts++; 571fc6e9c48Sotto pstart = DL_GETPOFFSET(pp); 572fc6e9c48Sotto pend = pstart + psz; 573fc6e9c48Sotto if (i != RAW_PART && psz != 0 && 574fc6e9c48Sotto ((pstart >= starting_sector && pstart <= ending_sector) || 575fc6e9c48Sotto (pend > starting_sector && pend < ending_sector))) { 576fc6e9c48Sotto overlap = 1; 577fc6e9c48Sotto break; 578fc6e9c48Sotto } 579fc6e9c48Sotto } 580fc6e9c48Sotto 5818dde8bb6Sotto cylsecs = lp_org->d_secpercyl; 582598ec681Skrw alloc = NULL; 583598ec681Skrw index = -1; 5848dde8bb6Sotto again: 585598ec681Skrw free(alloc); 586a9e37dfeSkrw alloc = NULL; 587598ec681Skrw index++; 588598ec681Skrw if (index >= alloc_table_nitems) 589598ec681Skrw return 1; 5908dde8bb6Sotto lp = &label; 5913d98fc8cSkrw for (i=0; i<MAXPARTITIONS; i++) { 5923d98fc8cSkrw free(mountpoints[i]); 5933d98fc8cSkrw mountpoints[i] = NULL; 5943d98fc8cSkrw } 5958dde8bb6Sotto memcpy(lp, lp_org, sizeof(struct disklabel)); 5960a7398ceSderaadt lp->d_npartitions = MAXPARTITIONS; 5978dde8bb6Sotto lastalloc = alloc_table[index].sz; 5983c723e85Skrw if (lastalloc > freeparts) 5993c723e85Skrw goto again; 600ab30cb2fSdoug alloc = reallocarray(NULL, lastalloc, sizeof(struct space_allocation)); 6018dde8bb6Sotto if (alloc == NULL) 6028dde8bb6Sotto errx(4, "out of memory"); 6038dde8bb6Sotto memcpy(alloc, alloc_table[index].table, 6048dde8bb6Sotto lastalloc * sizeof(struct space_allocation)); 6058dde8bb6Sotto 6068dde8bb6Sotto /* bump max swap based on phys mem, little physmem gets 2x swap */ 607a2c1f847Shenning if (index == 0 && alloc_table == alloc_table_default) { 608e384f6efSderaadt if (physmem / DEV_BSIZE < MEG(256)) 609e0befca8Skrw alloc[1].minsz = alloc[1].maxsz = 2 * (physmem / 610e0befca8Skrw DEV_BSIZE); 6118dde8bb6Sotto else 612e384f6efSderaadt alloc[1].maxsz += (physmem / DEV_BSIZE); 6138dde8bb6Sotto /* bump max /var to make room for 2 crash dumps */ 614e384f6efSderaadt alloc[3].maxsz += 2 * (physmem / DEV_BSIZE); 6158dde8bb6Sotto } 6168dde8bb6Sotto 61759c4e6f1Skrw xtrasecs = editor_countfree(lp); 618557f712bSkrw 61934ae4198Skrw for (i = 0; i < lastalloc; i++) { 6205f3e1104Skrw alloc[i].minsz = DL_BLKTOSEC(lp, alloc[i].minsz); 6215f3e1104Skrw alloc[i].maxsz = DL_BLKTOSEC(lp, alloc[i].maxsz); 6224f05c2ddSkrw if (xtrasecs >= alloc[i].minsz) 62334ae4198Skrw xtrasecs -= alloc[i].minsz; 6244f05c2ddSkrw else { 6254f05c2ddSkrw /* It did not work out, try next strategy */ 6264f05c2ddSkrw goto again; 6274f05c2ddSkrw } 628557f712bSkrw } 629557f712bSkrw 63034ae4198Skrw for (i = 0; i < lastalloc; i++) { 63134ae4198Skrw /* Find next available partition. */ 63234ae4198Skrw for (j = 0; j < MAXPARTITIONS; j++) 63334ae4198Skrw if (DL_GETPSIZE(&lp->d_partitions[j]) == 0) 63434ae4198Skrw break; 635a243d7b5Skrw if (j == MAXPARTITIONS) { 636a243d7b5Skrw /* It did not work out, try next strategy */ 637a243d7b5Skrw goto again; 638a243d7b5Skrw } 639a49bdda8Skrw partno = j; 64034ae4198Skrw pp = &lp->d_partitions[j]; 64134ae4198Skrw partmp = &mountpoints[j]; 64234ae4198Skrw ap = &alloc[i]; 643557f712bSkrw 64434ae4198Skrw /* Find largest chunk of free space. */ 64534ae4198Skrw chunks = free_chunks(lp); 64634ae4198Skrw chunksize = 0; 647859c13c7Skrw for (j = 0; chunks[j].start != 0 || chunks[j].stop != 0; j++) { 64834ae4198Skrw if ((chunks[j].stop - chunks[j].start) > chunksize) { 64934ae4198Skrw chunkstart = chunks[j].start; 650859c13c7Skrw chunkstop = chunks[j].stop; 65134ae4198Skrw #ifdef SUN_CYLCHECK 65234ae4198Skrw if (lp->d_flags & D_VENDOR) { 653859c13c7Skrw /* Align to cylinder boundaries. */ 654859c13c7Skrw chunkstart = ((chunkstart + cylsecs - 1) 655859c13c7Skrw / cylsecs) * cylsecs; 656859c13c7Skrw chunkstop = (chunkstop / cylsecs) * 6576ab0bb66Skrw cylsecs; 65834ae4198Skrw } 65934ae4198Skrw #endif 660859c13c7Skrw chunksize = chunkstop - chunkstart; 661859c13c7Skrw } 662859c13c7Skrw } 663859c13c7Skrw 66459c4e6f1Skrw /* Figure out the size of the partition. */ 66559c4e6f1Skrw if (i == lastalloc - 1) { 66659c4e6f1Skrw if (chunksize > ap->maxsz) 66759c4e6f1Skrw secs = ap->maxsz; 66859c4e6f1Skrw else 66934ae4198Skrw secs = chunksize; 67059c4e6f1Skrw } else { 67159c4e6f1Skrw secs = ap->minsz; 67259c4e6f1Skrw if (xtrasecs > 0) 67359c4e6f1Skrw secs += (xtrasecs / 100) * ap->rate; 67459c4e6f1Skrw if (secs > ap->maxsz) 67559c4e6f1Skrw secs = ap->maxsz; 67634ae4198Skrw } 67759c4e6f1Skrw #ifdef SUN_CYLCHECK 67859c4e6f1Skrw if (lp->d_flags & D_VENDOR) { 67959c4e6f1Skrw secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; 68059c4e6f1Skrw while (secs > chunksize) 68159c4e6f1Skrw secs -= cylsecs; 68259c4e6f1Skrw } 68359c4e6f1Skrw #endif 68459c4e6f1Skrw 68559c4e6f1Skrw /* See if partition can fit into chunk. */ 68659c4e6f1Skrw if (secs > chunksize) 68759c4e6f1Skrw secs = chunksize; 68834ae4198Skrw if (secs < ap->minsz) { 6898dde8bb6Sotto /* It did not work out, try next strategy */ 6908dde8bb6Sotto goto again; 691557f712bSkrw } 69234ae4198Skrw 69334ae4198Skrw /* Everything seems ok so configure the partition. */ 6945f3e1104Skrw DL_SETPSIZE(pp, secs); 69534ae4198Skrw DL_SETPOFFSET(pp, chunkstart); 69634ae4198Skrw if (ap->mp[0] != '/') 69734ae4198Skrw pp->p_fstype = FS_SWAP; 69834ae4198Skrw else { 69934ae4198Skrw pp->p_fstype = FS_BSDFFS; 700d68164a2Skrw pp->p_fragblock = 0; 701d68164a2Skrw if (get_fsize(lp, partno) == 1 || 702d68164a2Skrw get_bsize(lp, partno) == 1 || 703d68164a2Skrw get_cpg(lp, partno) == 1) { 704d68164a2Skrw free(alloc); 705d68164a2Skrw return 1; 706d68164a2Skrw } 70734ae4198Skrw free(*partmp); 70834ae4198Skrw if ((*partmp = strdup(ap->mp)) == NULL) 709557f712bSkrw errx(4, "out of memory"); 710557f712bSkrw } 711557f712bSkrw } 712557f712bSkrw 7138dde8bb6Sotto free(alloc); 7148dde8bb6Sotto memcpy(lp_org, lp, sizeof(struct disklabel)); 715185664b4Sotto return 0; 716557f712bSkrw } 717557f712bSkrw 718557f712bSkrw /* 7196aaa4aabSotto * Resize a partition, moving all subsequent partitions 7206aaa4aabSotto */ 7216aaa4aabSotto void 7226aaa4aabSotto editor_resize(struct disklabel *lp, char *p) 7236aaa4aabSotto { 7246aaa4aabSotto struct disklabel label; 7256aaa4aabSotto struct partition *pp, *prev; 726914b3475Skrw u_int64_t ui, sz, off; 72777370cdaSkrw int partno, i, flags, shrunk; 7286aaa4aabSotto 7296aaa4aabSotto label = *lp; 7306aaa4aabSotto 7316aaa4aabSotto /* Change which partition? */ 732ac30837aSkrw if (p == NULL) 7336aaa4aabSotto p = getstring("partition to resize", 7346aaa4aabSotto "The letter of the partition to name, a - p.", NULL); 735ac30837aSkrw if (p == NULL) 7366aaa4aabSotto return; 7376aaa4aabSotto partno = p[0] - 'a'; 7386aaa4aabSotto if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 7396aaa4aabSotto fprintf(stderr, "Partition must be between 'a' and '%c' " 7406aaa4aabSotto "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 7416aaa4aabSotto return; 7426aaa4aabSotto } 7436aaa4aabSotto 7446aaa4aabSotto pp = &label.d_partitions[partno]; 745fc6e9c48Sotto sz = DL_GETPSIZE(pp); 746fc6e9c48Sotto if (sz == 0) { 747fc6e9c48Sotto fputs("No such partition\n", stderr); 748fc6e9c48Sotto return; 749fc6e9c48Sotto } 750fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) { 751fc6e9c48Sotto fputs("Cannot resize spoofed partition\n", stderr); 752fc6e9c48Sotto return; 753fc6e9c48Sotto } 75440b226e8Skrw flags = DO_CONVERSIONS; 755914b3475Skrw ui = getuint64(lp, "[+|-]new size (with unit)", 756e0befca8Skrw "new size or amount to grow (+) or shrink (-) partition including " 75740b226e8Skrw "unit", sz, sz + editor_countfree(lp), &flags); 7586aaa4aabSotto 759914b3475Skrw if (ui == CMD_ABORTED) 7606aaa4aabSotto return; 761914b3475Skrw else if (ui == CMD_BADVALUE) 7629f0bdc2aSkrw return; 763914b3475Skrw else if (ui == 0) { 7641298f28aSkrw fputs("The size must be > 0 sectors\n", stderr); 7651298f28aSkrw return; 7666aaa4aabSotto } 7676aaa4aabSotto 7686aaa4aabSotto #ifdef SUN_CYLCHECK 7691298f28aSkrw if (lp->d_secpercyl & D_VENDOR) { 7701298f28aSkrw u_int64_t cylsecs; 7716aaa4aabSotto cylsecs = lp->d_secpercyl; 772ce0ca44bSkrw ui = ((ui + cylsecs - 1) / cylsecs) * cylsecs; 7731298f28aSkrw } 7746aaa4aabSotto #endif 775914b3475Skrw if (DL_GETPOFFSET(pp) + ui > ending_sector) { 7766aaa4aabSotto fputs("Amount too big\n", stderr); 7776aaa4aabSotto return; 7786aaa4aabSotto } 7796aaa4aabSotto 780914b3475Skrw DL_SETPSIZE(pp, ui); 781d68164a2Skrw pp->p_fragblock = 0; 782d68164a2Skrw if (get_fsize(&label, partno) == 1 || 783d68164a2Skrw get_bsize(&label, partno) == 1 || 784d68164a2Skrw get_cpg(&label, partno) == 1) 785d68164a2Skrw return; 7866aaa4aabSotto 7876aaa4aabSotto /* 7886aaa4aabSotto * Pack partitions above the resized partition, leaving unused 789c7e00dc5Skrw * partitions alone. 7906aaa4aabSotto */ 79177370cdaSkrw shrunk = -1; 7926aaa4aabSotto prev = pp; 7936aaa4aabSotto for (i = partno + 1; i < MAXPARTITIONS; i++) { 7946aaa4aabSotto if (i == RAW_PART) 7956aaa4aabSotto continue; 796fc6e9c48Sotto pp = &label.d_partitions[i]; 797fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) 798fc6e9c48Sotto continue; 799fc6e9c48Sotto sz = DL_GETPSIZE(pp); 8006aaa4aabSotto if (sz == 0) 8016aaa4aabSotto continue; 8026aaa4aabSotto 8036aaa4aabSotto off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev); 8046aaa4aabSotto 8056aaa4aabSotto if (off < ending_sector) { 8066aaa4aabSotto DL_SETPOFFSET(pp, off); 8076aaa4aabSotto if (off + DL_GETPSIZE(pp) > ending_sector) { 8086aaa4aabSotto DL_SETPSIZE(pp, ending_sector - off); 809ad90a7d1Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(0, 0); 810ad90a7d1Sotto if (get_fsize(&label, i) == 1 || 811ad90a7d1Sotto get_bsize(&label, i) == 1 || 812ad90a7d1Sotto get_cpg(&label, i) == 1) 813d68164a2Skrw return; 81477370cdaSkrw shrunk = i; 8156aaa4aabSotto } 8166aaa4aabSotto } else { 81777370cdaSkrw fputs("Amount too big\n", stderr); 8186aaa4aabSotto return; 8196aaa4aabSotto } 8206aaa4aabSotto prev = pp; 8216aaa4aabSotto } 82277370cdaSkrw 82377370cdaSkrw if (shrunk != -1) 82477370cdaSkrw fprintf(stderr, "Partition %c shrunk to %llu sectors to make " 82577370cdaSkrw "room\n", 'a' + shrunk, 82677370cdaSkrw DL_GETPSIZE(&label.d_partitions[shrunk])); 8276aaa4aabSotto *lp = label; 8286aaa4aabSotto } 8296aaa4aabSotto 8306aaa4aabSotto /* 8316fe57b42Smillert * Add a new partition. 8326fe57b42Smillert */ 8336fe57b42Smillert void 83434ae4198Skrw editor_add(struct disklabel *lp, char *p) 8356fe57b42Smillert { 83696a888c6Smillert struct partition *pp; 83796a888c6Smillert struct diskchunk *chunks; 8385caa08b2Skrw char buf[2]; 839a3ad4147Skrw int i, partno; 840f8ab7229Schl u_int64_t freesectors, new_offset, new_size; 8419fdcb4d6Skrw 8429fdcb4d6Skrw freesectors = editor_countfree(lp); 8436fe57b42Smillert 8446fe57b42Smillert /* XXX - prompt user to steal space from another partition instead */ 845fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 8469fdcb4d6Skrw if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) { 847fc1a4cc6Sderaadt fputs("No space left, you need to shrink a partition " 848fc1a4cc6Sderaadt "(need at least one full cylinder)\n", 849fc1a4cc6Sderaadt stderr); 850fc1a4cc6Sderaadt return; 851fc1a4cc6Sderaadt } 8528390cf28Smillert #endif 8539fdcb4d6Skrw if (freesectors == 0) { 8546fe57b42Smillert fputs("No space left, you need to shrink a partition\n", 8556fe57b42Smillert stderr); 8566fe57b42Smillert return; 8576fe57b42Smillert } 8586fe57b42Smillert 8595caa08b2Skrw if (p == NULL) { 8605caa08b2Skrw /* 8615caa08b2Skrw * Use the first unused partition that is not 'c' as the 8625caa08b2Skrw * default partition in the prompt string. 8635caa08b2Skrw */ 8645caa08b2Skrw pp = &lp->d_partitions[0]; 8655caa08b2Skrw buf[0] = buf[1] = '\0'; 8665caa08b2Skrw for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) { 8675caa08b2Skrw if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) { 8685caa08b2Skrw buf[0] = partno + 'a'; 8695caa08b2Skrw p = &buf[0]; 8706fe57b42Smillert break; 8716fe57b42Smillert } 8725caa08b2Skrw } 873c33fcabaSmillert p = getstring("partition", 8746fe57b42Smillert "The letter of the new partition, a - p.", p); 8756fe57b42Smillert } 876ac30837aSkrw if (p == NULL) 8775caa08b2Skrw return; 8785caa08b2Skrw partno = p[0] - 'a'; 8795caa08b2Skrw if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) { 8805caa08b2Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 8815caa08b2Skrw "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1); 8825caa08b2Skrw return; 8835caa08b2Skrw } 8845caa08b2Skrw pp = &lp->d_partitions[partno]; 8855caa08b2Skrw 8865caa08b2Skrw if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) { 8875caa08b2Skrw fprintf(stderr, "Partition '%c' exists. Delete it first.\n", 8885caa08b2Skrw p[0]); 8895caa08b2Skrw return; 8906fe57b42Smillert } 89196a888c6Smillert 892caf41f96Skrw /* 893caf41f96Skrw * Increase d_npartitions if necessary. Ensure all new partitions are 894855d4e83Ssobrado * zero'ed to avoid inadvertent overlaps. 895caf41f96Skrw */ 896caf41f96Skrw for(; lp->d_npartitions <= partno; lp->d_npartitions++) 897caf41f96Skrw memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp)); 89896a888c6Smillert 89989f4601dSkrw /* Make sure selected partition is zero'd too. */ 90089f4601dSkrw memset(pp, 0, sizeof(*pp)); 90115c15d8aSkrw chunks = free_chunks(lp); 90215c15d8aSkrw 90315c15d8aSkrw /* 90415c15d8aSkrw * Since we know there's free space, there must be at least one 90515c15d8aSkrw * chunk. So find the largest chunk and assume we want to add the 90615c15d8aSkrw * partition in that free space. 90715c15d8aSkrw */ 90815c15d8aSkrw new_size = new_offset = 0; 90915c15d8aSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 91015c15d8aSkrw if (chunks[i].stop - chunks[i].start > new_size) { 91115c15d8aSkrw new_size = chunks[i].stop - chunks[i].start; 91215c15d8aSkrw new_offset = chunks[i].start; 91315c15d8aSkrw } 91415c15d8aSkrw } 9151e0ad43cSotto DL_SETPSIZE(pp, new_size); 9161e0ad43cSotto DL_SETPOFFSET(pp, new_offset); 91796a888c6Smillert pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS; 918c88f83bdSotto 919c88f83bdSotto if (get_offset(lp, partno) == 0 && 920a3ad4147Skrw get_size(lp, partno) == 0 && 921a3ad4147Skrw get_fstype(lp, partno) == 0 && 92234ae4198Skrw get_mp(lp, partno) == 0 && 923a4c87e64Skrw get_fsize(lp, partno) == 0 && 924a6262855Skrw get_bsize(lp, partno) == 0 && 925a6262855Skrw get_cpg(lp, partno) == 0) 92696a888c6Smillert return; 927a3ad4147Skrw 928a4c87e64Skrw /* Bailed out at some point, so effectively delete the partition. */ 929da2bd3f5Skrw memset(pp, 0, sizeof(*pp)); 9306fe57b42Smillert } 9316fe57b42Smillert 9326fe57b42Smillert /* 933bd6726faSmillert * Set the mountpoint of an existing partition ('name'). 934bd6726faSmillert */ 935bd6726faSmillert void 93634ae4198Skrw editor_name(struct disklabel *lp, char *p) 937bd6726faSmillert { 938bd6726faSmillert struct partition *pp; 939bd6726faSmillert int partno; 940bd6726faSmillert 941bd6726faSmillert /* Change which partition? */ 942ac30837aSkrw if (p == NULL) 943c33fcabaSmillert p = getstring("partition to name", 944bd6726faSmillert "The letter of the partition to name, a - p.", NULL); 945ac30837aSkrw if (p == NULL) 946bd6726faSmillert return; 947bd6726faSmillert partno = p[0] - 'a'; 9486c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9496c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9506c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 951bd6726faSmillert return; 95266df1f0cSkrw } 95366df1f0cSkrw pp = &lp->d_partitions[partno]; 95466df1f0cSkrw 95566df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 95666df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 957bd6726faSmillert return; 958bd6726faSmillert } 959bd6726faSmillert 96034ae4198Skrw get_mp(lp, partno); 961bd6726faSmillert } 962bd6726faSmillert 963bd6726faSmillert /* 9646fe57b42Smillert * Change an existing partition. 9656fe57b42Smillert */ 9666fe57b42Smillert void 96734ae4198Skrw editor_modify(struct disklabel *lp, char *p) 9686fe57b42Smillert { 96940b226e8Skrw struct partition opp, *pp; 970f8ab7229Schl int partno; 9716fe57b42Smillert 9726fe57b42Smillert /* Change which partition? */ 973ac30837aSkrw if (p == NULL) 974c33fcabaSmillert p = getstring("partition to modify", 9756fe57b42Smillert "The letter of the partition to modify, a - p.", NULL); 976ac30837aSkrw if (p == NULL) 97796a888c6Smillert return; 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 99140b226e8Skrw opp = *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 && 998a95dd767Sotto get_bsize(lp, partno) == 0 && 999a95dd767Sotto get_cpg(lp, partno) == 0) 100096a888c6Smillert return; 10016fe57b42Smillert 1002a4c87e64Skrw /* Bailed out at some point, so undo any changes. */ 100340b226e8Skrw *pp = opp; 10046fe57b42Smillert } 10056fe57b42Smillert 10066fe57b42Smillert /* 10076fe57b42Smillert * Delete an existing partition. 10086fe57b42Smillert */ 10096fe57b42Smillert void 101034ae4198Skrw editor_delete(struct disklabel *lp, char *p) 10116fe57b42Smillert { 101266df1f0cSkrw struct partition *pp; 1013135c90d1Skrw int partno; 10146fe57b42Smillert 1015ac30837aSkrw if (p == NULL) 1016c33fcabaSmillert p = getstring("partition to delete", 1017945ae268Smillert "The letter of the partition to delete, a - p, or '*'.", 1018945ae268Smillert NULL); 1019ac30837aSkrw if (p == NULL) 102096a888c6Smillert return; 1021945ae268Smillert if (p[0] == '*') { 10229fdcb4d6Skrw zero_partitions(lp); 1023945ae268Smillert return; 1024945ae268Smillert } 1025135c90d1Skrw partno = p[0] - 'a'; 1026135c90d1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 10276c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 10286c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 102933262abfSmiod return; 103066df1f0cSkrw } 1031135c90d1Skrw pp = &lp->d_partitions[partno]; 103266df1f0cSkrw 103366df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 103466df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 103533262abfSmiod return; 103666df1f0cSkrw } 103766df1f0cSkrw 10386fe57b42Smillert /* Really delete it (as opposed to just setting to "unused") */ 1039135c90d1Skrw memset(pp, 0, sizeof(*pp)); 104034ae4198Skrw free(mountpoints[partno]); 104134ae4198Skrw mountpoints[partno] = NULL; 10426fe57b42Smillert } 10436fe57b42Smillert 10446fe57b42Smillert /* 10456fe57b42Smillert * Change the size of an existing partition. 10466fe57b42Smillert */ 10476fe57b42Smillert void 10489fdcb4d6Skrw editor_change(struct disklabel *lp, char *p) 10496fe57b42Smillert { 10504b9a3bdaSmillert struct partition *pp; 105166df1f0cSkrw int partno; 10526fe57b42Smillert 1053ac30837aSkrw if (p == NULL) 1054c33fcabaSmillert p = getstring("partition to change size", 10556fe57b42Smillert "The letter of the partition to change size, a - p.", NULL); 1056ac30837aSkrw if (p == NULL) 105796a888c6Smillert return; 10586fe57b42Smillert partno = p[0] - 'a'; 10596c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 10606c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 10616c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 10626fe57b42Smillert return; 10636fe57b42Smillert } 10644b9a3bdaSmillert pp = &lp->d_partitions[partno]; 10656fe57b42Smillert 106666df1f0cSkrw if (DL_GETPSIZE(pp) == 0) { 106766df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 106866df1f0cSkrw return; 106966df1f0cSkrw } 107066df1f0cSkrw 107114192793Skrw printf("Partition %c is currently %llu sectors in size, and can have " 107214192793Skrw "a maximum\nsize of %llu sectors.\n", 107314192793Skrw p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno)); 10747da73705Skrw 107559ccf790Skrw /* Get new size */ 10769fdcb4d6Skrw get_size(lp, partno); 10776fe57b42Smillert } 10786fe57b42Smillert 10796fe57b42Smillert /* 10806fe57b42Smillert * Sort the partitions based on starting offset. 10816fe57b42Smillert * This assumes there can be no overlap. 10826fe57b42Smillert */ 10836fe57b42Smillert int 10848809fabbSderaadt partition_cmp(const void *e1, const void *e2) 10856fe57b42Smillert { 10866fe57b42Smillert struct partition *p1 = *(struct partition **)e1; 10876fe57b42Smillert struct partition *p2 = *(struct partition **)e2; 10881e0ad43cSotto u_int64_t o1 = DL_GETPOFFSET(p1); 10891e0ad43cSotto u_int64_t o2 = DL_GETPOFFSET(p2); 10906fe57b42Smillert 10911e0ad43cSotto if (o1 < o2) 1092651d5bd9Sotto return -1; 10931e0ad43cSotto else if (o1 > o2) 1094651d5bd9Sotto return 1; 1095651d5bd9Sotto else 1096651d5bd9Sotto return 0; 10976fe57b42Smillert } 10986fe57b42Smillert 10996fe57b42Smillert char * 1100b228e876Smiod getstring(const char *prompt, const char *helpstring, const char *oval) 11016fe57b42Smillert { 11026fe57b42Smillert static char buf[BUFSIZ]; 11036fe57b42Smillert int n; 11046fe57b42Smillert 11056fe57b42Smillert buf[0] = '\0'; 11066fe57b42Smillert do { 11076fe57b42Smillert printf("%s: [%s] ", prompt, oval ? oval : ""); 11086e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1109260513deSmillert buf[0] = '\0'; 111096a888c6Smillert if (feof(stdin)) { 111124c6582eSmillert clearerr(stdin); 111296a888c6Smillert putchar('\n'); 1113ac30837aSkrw fputs("Command aborted\n", stderr); 111496a888c6Smillert return (NULL); 111596a888c6Smillert } 11166e0becc5Smillert } 11176fe57b42Smillert n = strlen(buf); 11186fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 11196fe57b42Smillert buf[--n] = '\0'; 11206fe57b42Smillert if (buf[0] == '?') 11216fe57b42Smillert puts(helpstring); 11224fb6ab7cSmillert else if (oval != NULL && buf[0] == '\0') 11234fb6ab7cSmillert strlcpy(buf, oval, sizeof(buf)); 11246fe57b42Smillert } while (buf[0] == '?'); 11256fe57b42Smillert 11266fe57b42Smillert return (&buf[0]); 11276fe57b42Smillert } 11286fe57b42Smillert 11296fe57b42Smillert /* 1130aa3970cdSkrw * Returns 1131aa3970cdSkrw * 0 .. CMD_ABORTED - 1 ==> valid value 1132aa3970cdSkrw * CMD_BADVALUE ==> invalid value 1133aa3970cdSkrw * CMD_ABORTED ==> ^D on input 11346fe57b42Smillert */ 11351e0ad43cSotto u_int64_t 11360db7769aSkrw getnumber(char *prompt, char *helpstring, u_int32_t oval, u_int32_t maxval) 11370db7769aSkrw { 11380db7769aSkrw char buf[BUFSIZ], *p; 11390db7769aSkrw int rslt; 11400db7769aSkrw long long rval; 11410db7769aSkrw const char *errstr; 11420db7769aSkrw 11430db7769aSkrw rslt = snprintf(buf, sizeof(buf), "%u", oval); 1144515e489cSderaadt if (rslt < 0 || (unsigned int)rslt >= sizeof(buf)) 11450db7769aSkrw return (CMD_BADVALUE); 11460db7769aSkrw 11470db7769aSkrw p = getstring(prompt, helpstring, buf); 11480db7769aSkrw if (p == NULL) 11490db7769aSkrw return (CMD_ABORTED); 11500db7769aSkrw if (strlen(p) == 0) 11510db7769aSkrw return (oval); 11520db7769aSkrw 11530db7769aSkrw rval = strtonum(p, 0, maxval, &errstr); 11540db7769aSkrw if (errstr != NULL) { 11550db7769aSkrw printf("%s must be between 0 and %u\n", prompt, maxval); 11560db7769aSkrw return (CMD_BADVALUE); 11570db7769aSkrw } 11580db7769aSkrw 11590db7769aSkrw return (rval); 11600db7769aSkrw } 11610db7769aSkrw 11620db7769aSkrw /* 11630db7769aSkrw * Returns 11640db7769aSkrw * 0 .. CMD_ABORTED - 1 ==> valid value 11650db7769aSkrw * CMD_BADVALUE ==> invalid value 11660db7769aSkrw * CMD_ABORTED ==> ^D on input 11670db7769aSkrw */ 11680db7769aSkrw u_int64_t 1169117239d3Skrw getuint64(struct disklabel *lp, char *prompt, char *helpstring, 117040b226e8Skrw u_int64_t oval, u_int64_t maxval, int *flags) 11716fe57b42Smillert { 11721fec2892Skrw char buf[21], *p, operator = '\0'; 11731fec2892Skrw char *unit = NULL; 11741e0ad43cSotto u_int64_t rval = oval; 11751fec2892Skrw double d; 11769a4afaafSkrw int rslt; 11776fe57b42Smillert 11789a4afaafSkrw rslt = snprintf(buf, sizeof(buf), "%llu", oval); 1179515e489cSderaadt if (rslt < 0 || (unsigned int)rslt >= sizeof(buf)) 11809a4afaafSkrw goto invalid; 11819a4afaafSkrw 11829a4afaafSkrw p = getstring(prompt, helpstring, buf); 11839a4afaafSkrw if (p == NULL) 1184aa3970cdSkrw return (CMD_ABORTED); 11851fec2892Skrw else if (p[0] == '\0') 11861fec2892Skrw rval = oval; 11871fec2892Skrw else if (p[0] == '*' && p[1] == '\0') 11886fe57b42Smillert rval = maxval; 11891fec2892Skrw else { 11901fec2892Skrw if (*p == '+' || *p == '-') 11911fec2892Skrw operator = *p++; 11921fec2892Skrw if (parse_sizespec(p, &d, &unit) == -1) 11931fec2892Skrw goto invalid; 11941fec2892Skrw if (unit == NULL) 11951fec2892Skrw rval = d; 11961fec2892Skrw else if (flags != NULL && (*flags & DO_CONVERSIONS) == 0) 11971fec2892Skrw goto invalid; 11981fec2892Skrw else { 11991fec2892Skrw switch (tolower((unsigned char)*unit)) { 12006fe57b42Smillert case 'b': 12011fec2892Skrw rval = d / lp->d_secsize; 12026fe57b42Smillert break; 12031fec2892Skrw case 'c': 12041fec2892Skrw rval = d * lp->d_secpercyl; 12051a51a1eeSmillert break; 120614cc915fSmillert case '%': 12071fec2892Skrw rval = DL_GETDSIZE(lp) * (d / 100.0); 120814cc915fSmillert break; 120914cc915fSmillert case '&': 12101fec2892Skrw rval = maxval * (d / 100.0); 12111fec2892Skrw break; 12121fec2892Skrw default: 12131fec2892Skrw if (apply_unit(d, *unit, &rval) == -1) 12141fec2892Skrw goto invalid; 12151fec2892Skrw rval = DL_BLKTOSEC(lp, rval); 121614cc915fSmillert break; 12176fe57b42Smillert } 121896a888c6Smillert } 12196fe57b42Smillert 1220e15dcdb4Skrw /* Range check then apply [+-] operator */ 1221e15dcdb4Skrw if (operator == '+') { 1222aa3970cdSkrw if (CMD_ABORTED - oval > rval) 12236fe57b42Smillert rval += oval; 1224e15dcdb4Skrw else { 1225ac30837aSkrw goto invalid; 1226e15dcdb4Skrw } 1227e15dcdb4Skrw } else if (operator == '-') { 1228e15dcdb4Skrw if (oval >= rval) 12296fe57b42Smillert rval = oval - rval; 1230e15dcdb4Skrw else { 1231ac30837aSkrw goto invalid; 1232e15dcdb4Skrw } 1233e15dcdb4Skrw } 12346fe57b42Smillert } 123540b226e8Skrw 123640b226e8Skrw if (flags != NULL) { 12371fec2892Skrw if (unit != NULL) 123840b226e8Skrw *flags |= DO_ROUNDING; 1239fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 124040b226e8Skrw if (lp->d_flags & D_VENDOR) 124140b226e8Skrw *flags |= DO_ROUNDING; 1242dbffb156Smillert #endif 12436fe57b42Smillert } 12446fe57b42Smillert return (rval); 1245ac30837aSkrw 1246ac30837aSkrw invalid: 1247ac30837aSkrw fputs("Invalid entry\n", stderr); 1248aa3970cdSkrw return (CMD_BADVALUE); 12496fe57b42Smillert } 12506fe57b42Smillert 12516fe57b42Smillert /* 12521f0f871dSkrw * Check for partition overlap in lp and prompt the user to resolve the overlap 12531f0f871dSkrw * if any is found. Returns 1 if unable to resolve, else 0. 12546fe57b42Smillert */ 12556fe57b42Smillert int 12561f0f871dSkrw has_overlap(struct disklabel *lp) 12576fe57b42Smillert { 12586fe57b42Smillert struct partition **spp; 12590f1cd5a2Skrw int i, p1, p2; 12600f1cd5a2Skrw char *line = NULL; 12610f1cd5a2Skrw size_t linesize = 0; 12620f1cd5a2Skrw ssize_t linelen; 12636fe57b42Smillert 12640f1cd5a2Skrw for (;;) { 12650fbd3c97Skrw spp = sort_partitions(lp); 12660f1cd5a2Skrw for (i = 0; spp[i+1] != NULL; i++) { 1267430e1380Skrw if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) > 12680f1cd5a2Skrw DL_GETPOFFSET(spp[i+1])) 12690f1cd5a2Skrw break; 1270616cd1c4Smillert } 12710f1cd5a2Skrw if (spp[i+1] == NULL) { 12720f1cd5a2Skrw free(line); 1273e6aa8bafSmillert return (0); 12746fe57b42Smillert } 12756fe57b42Smillert 12760f1cd5a2Skrw p1 = 'a' + (spp[i] - lp->d_partitions); 12770f1cd5a2Skrw p2 = 'a' + (spp[i+1] - lp->d_partitions); 12780f1cd5a2Skrw printf("\nError, partitions %c and %c overlap:\n", p1, p2); 12790f1cd5a2Skrw printf("# %16.16s %16.16s fstype [fsize bsize cpg]\n", 12800f1cd5a2Skrw "size", "offset"); 12810f1cd5a2Skrw display_partition(stdout, lp, p1 - 'a', 0); 12820f1cd5a2Skrw display_partition(stdout, lp, p2 - 'a', 0); 12830f1cd5a2Skrw 12840f1cd5a2Skrw for (;;) { 12850f1cd5a2Skrw printf("Disable which one? (%c %c) ", p1, p2); 12860f1cd5a2Skrw linelen = getline(&line, &linesize, stdin); 12870f1cd5a2Skrw if (linelen == -1) 12880f1cd5a2Skrw goto done; 12890f1cd5a2Skrw if (linelen == 2 && (line[0] == p1 || line[0] == p2)) 12900f1cd5a2Skrw break; 12910f1cd5a2Skrw } 12920f1cd5a2Skrw lp->d_partitions[line[0] - 'a'].p_fstype = FS_UNUSED; 12930f1cd5a2Skrw } 12940f1cd5a2Skrw 12950f1cd5a2Skrw done: 12960f1cd5a2Skrw putchar('\n'); 12970f1cd5a2Skrw free(line); 12980f1cd5a2Skrw return (1); 12990f1cd5a2Skrw } 13000f1cd5a2Skrw 13016fe57b42Smillert void 13029fdcb4d6Skrw edit_parms(struct disklabel *lp) 13036fe57b42Smillert { 13046fe57b42Smillert char *p; 13059fdcb4d6Skrw u_int64_t freesectors, ui; 130696a888c6Smillert struct disklabel oldlabel = *lp; 13076fe57b42Smillert 1308ea37abd3Sderaadt printf("Changing device parameters for %s:\n", specname); 13096fe57b42Smillert 13100f820bbbSmillert /* disk type */ 13110f820bbbSmillert for (;;) { 1312c33fcabaSmillert p = getstring("disk type", 131341282a2aSmillert "What kind of disk is this? Usually SCSI, ESDI, ST506, or " 131441282a2aSmillert "floppy (use ESDI for IDE).", dktypenames[lp->d_type]); 1315ac30837aSkrw if (p == NULL) 131696a888c6Smillert return; 131741282a2aSmillert if (strcasecmp(p, "IDE") == 0) 131841282a2aSmillert ui = DTYPE_ESDI; 131941282a2aSmillert else 1320c5229dceSkrw for (ui = 1; ui < DKMAXTYPES && strcasecmp(p, 1321c5229dceSkrw dktypenames[ui]); ui++) 13220f820bbbSmillert ; 13230f820bbbSmillert if (ui < DKMAXTYPES) { 13240f820bbbSmillert break; 13250f820bbbSmillert } else { 13260f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", p); 13270f820bbbSmillert fputs("Valid types are: ", stdout); 13280f820bbbSmillert for (ui = 1; ui < DKMAXTYPES; ui++) { 13290f820bbbSmillert printf("\"%s\"", dktypenames[ui]); 13300f820bbbSmillert if (ui < DKMAXTYPES - 1) 13310f820bbbSmillert fputs(", ", stdout); 13320f820bbbSmillert } 13330f820bbbSmillert putchar('\n'); 13340f820bbbSmillert } 13350f820bbbSmillert } 13360f820bbbSmillert lp->d_type = ui; 13370f820bbbSmillert 13386fe57b42Smillert /* pack/label id */ 1339c33fcabaSmillert p = getstring("label name", 13406fe57b42Smillert "15 char string that describes this label, usually the disk name.", 13416fe57b42Smillert lp->d_packname); 134296a888c6Smillert if (p == NULL) { 134396a888c6Smillert *lp = oldlabel; /* undo damage */ 134496a888c6Smillert return; 134596a888c6Smillert } 13464fb6ab7cSmillert strncpy(lp->d_packname, p, sizeof(lp->d_packname)); /* checked */ 13476fe57b42Smillert 13486fe57b42Smillert /* sectors/track */ 13496fe57b42Smillert for (;;) { 13500db7769aSkrw ui = getnumber("sectors/track", 1351cfd24250Skrw "The Number of sectors per track.", lp->d_nsectors, 13520db7769aSkrw UINT32_MAX); 1353aa3970cdSkrw if (ui == CMD_ABORTED) { 135496a888c6Smillert *lp = oldlabel; /* undo damage */ 135596a888c6Smillert return; 1356aa3970cdSkrw } else if (ui == CMD_BADVALUE) 1357ac30837aSkrw ; /* Try again. */ 13586fe57b42Smillert else 13596fe57b42Smillert break; 13606fe57b42Smillert } 13616fe57b42Smillert lp->d_nsectors = ui; 13626fe57b42Smillert 13636fe57b42Smillert /* tracks/cylinder */ 13646fe57b42Smillert for (;;) { 13650db7769aSkrw ui = getnumber("tracks/cylinder", 13666fe57b42Smillert "The number of tracks per cylinder.", lp->d_ntracks, 13670db7769aSkrw UINT32_MAX); 1368aa3970cdSkrw if (ui == CMD_ABORTED) { 136996a888c6Smillert *lp = oldlabel; /* undo damage */ 137096a888c6Smillert return; 1371aa3970cdSkrw } else if (ui == CMD_BADVALUE) 1372ac30837aSkrw ; /* Try again. */ 13736fe57b42Smillert else 13746fe57b42Smillert break; 13756fe57b42Smillert } 13766fe57b42Smillert lp->d_ntracks = ui; 13776fe57b42Smillert 13786fe57b42Smillert /* sectors/cylinder */ 1379148b6188Smillert for (;;) { 13800db7769aSkrw ui = getnumber("sectors/cylinder", 1381148b6188Smillert "The number of sectors per cylinder (Usually sectors/track " 13820db7769aSkrw "* tracks/cylinder).", lp->d_secpercyl, UINT32_MAX); 1383aa3970cdSkrw if (ui == CMD_ABORTED) { 138496a888c6Smillert *lp = oldlabel; /* undo damage */ 138596a888c6Smillert return; 1386aa3970cdSkrw } else if (ui == CMD_BADVALUE) 1387ac30837aSkrw ; /* Try again. */ 1388148b6188Smillert else 1389148b6188Smillert break; 1390148b6188Smillert } 1391148b6188Smillert lp->d_secpercyl = ui; 13926fe57b42Smillert 13936fe57b42Smillert /* number of cylinders */ 13946fe57b42Smillert for (;;) { 13950db7769aSkrw ui = getnumber("number of cylinders", 13966fe57b42Smillert "The total number of cylinders on the disk.", 13970db7769aSkrw lp->d_ncylinders, UINT32_MAX); 1398aa3970cdSkrw if (ui == CMD_ABORTED) { 139996a888c6Smillert *lp = oldlabel; /* undo damage */ 140096a888c6Smillert return; 1401aa3970cdSkrw } else if (ui == CMD_BADVALUE) 1402ac30837aSkrw ; /* Try again. */ 14036fe57b42Smillert else 14046fe57b42Smillert break; 14056fe57b42Smillert } 14066fe57b42Smillert lp->d_ncylinders = ui; 14076fe57b42Smillert 14086fe57b42Smillert /* total sectors */ 14096fe57b42Smillert for (;;) { 1410b9fc9a72Sderaadt u_int64_t nsec = MAXIMUM(DL_GETDSIZE(lp), 141134af67a3Sotto (u_int64_t)lp->d_ncylinders * lp->d_secpercyl); 1412117239d3Skrw ui = getuint64(lp, "total sectors", 14136fe57b42Smillert "The total number of sectors on the disk.", 141440b226e8Skrw nsec, nsec, NULL); 1415aa3970cdSkrw if (ui == CMD_ABORTED) { 141696a888c6Smillert *lp = oldlabel; /* undo damage */ 141796a888c6Smillert return; 1418aa3970cdSkrw } else if (ui == CMD_BADVALUE) 1419ac30837aSkrw ; /* Try again. */ 14201e0ad43cSotto else if (ui > DL_GETDSIZE(lp) && 14211e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 1422f98aebd4Smillert puts("You may want to increase the size of the 'c' " 1423f98aebd4Smillert "partition."); 14246fe57b42Smillert break; 14251e0ad43cSotto } else if (ui < DL_GETDSIZE(lp) && 14261e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 14276fe57b42Smillert /* shrink free count */ 14289fdcb4d6Skrw freesectors = editor_countfree(lp); 14299fdcb4d6Skrw if (DL_GETDSIZE(lp) - ui > freesectors) 14306fe57b42Smillert fprintf(stderr, 14311e0ad43cSotto "Not enough free space to shrink by %llu " 14321e0ad43cSotto "sectors (only %llu sectors left)\n", 14339fdcb4d6Skrw DL_GETDSIZE(lp) - ui, freesectors); 1434c4f83f03Skrw else 14356fe57b42Smillert break; 14366fe57b42Smillert } else 14376fe57b42Smillert break; 14386fe57b42Smillert } 143941ed49b7Smillert /* Adjust ending_sector if necessary. */ 144078f0fb17Skrw if (ending_sector > ui) { 144196a888c6Smillert ending_sector = ui; 144278f0fb17Skrw DL_SETBEND(lp, ending_sector); 144378f0fb17Skrw } 14441e0ad43cSotto DL_SETDSIZE(lp, ui); 14456fe57b42Smillert } 1446a7e61405Smillert 1447a7e61405Smillert struct partition ** 14480fbd3c97Skrw sort_partitions(struct disklabel *lp) 1449a7e61405Smillert { 1450d18c2a43Skrw static struct partition *spp[MAXPARTITIONS+2]; 14510fbd3c97Skrw int i, npartitions; 1452a7e61405Smillert 1453d18c2a43Skrw memset(spp, 0, sizeof(spp)); 1454d18c2a43Skrw 1455a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1456a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 14571e0ad43cSotto DL_GETPSIZE(&lp->d_partitions[i]) != 0) 1458a7e61405Smillert spp[npartitions++] = &lp->d_partitions[i]; 1459a7e61405Smillert } 1460a7e61405Smillert 1461a7e61405Smillert /* 1462a7e61405Smillert * Sort the partitions based on starting offset. 1463a7e61405Smillert * This is safe because we guarantee no overlap. 1464a7e61405Smillert */ 1465a7e61405Smillert if (npartitions > 1) 14660f1cd5a2Skrw if (mergesort((void *)spp, npartitions, sizeof(spp[0]), 1467a7e61405Smillert partition_cmp)) 1468a7e61405Smillert err(4, "failed to sort partition table"); 1469a7e61405Smillert 1470a7e61405Smillert return (spp); 1471a7e61405Smillert } 14720f820bbbSmillert 14730f820bbbSmillert /* 14740f820bbbSmillert * Get a valid disk type if necessary. 14750f820bbbSmillert */ 14760f820bbbSmillert void 14778809fabbSderaadt getdisktype(struct disklabel *lp, char *banner, char *dev) 14780f820bbbSmillert { 14790f820bbbSmillert int i; 1480b228e876Smiod char *s; 1481b228e876Smiod const char *def = "SCSI"; 1482b228e876Smiod const struct dtypes { 1483b228e876Smiod const char *dev; 1484b228e876Smiod const char *type; 1485803ff7d5Smillert } dtypes[] = { 1486c33fcabaSmillert { "sd", "SCSI" }, 1487c33fcabaSmillert { "wd", "IDE" }, 1488c33fcabaSmillert { "fd", "FLOPPY" }, 1489c33fcabaSmillert { "xd", "SMD" }, 1490c33fcabaSmillert { "xy", "SMD" }, 1491c33fcabaSmillert { "hd", "HP-IB" }, 1492c33fcabaSmillert { "vnd", "VND" }, 1493c33fcabaSmillert { "svnd", "VND" }, 1494c33fcabaSmillert { NULL, NULL } 1495803ff7d5Smillert }; 1496803ff7d5Smillert 1497803ff7d5Smillert if ((s = basename(dev)) != NULL) { 1498803ff7d5Smillert if (*s == 'r') 1499803ff7d5Smillert s++; 1500803ff7d5Smillert i = strcspn(s, "0123456789"); 1501803ff7d5Smillert s[i] = '\0'; 1502803ff7d5Smillert dev = s; 1503803ff7d5Smillert for (i = 0; dtypes[i].dev != NULL; i++) { 1504803ff7d5Smillert if (strcmp(dev, dtypes[i].dev) == 0) { 1505803ff7d5Smillert def = dtypes[i].type; 1506803ff7d5Smillert break; 1507803ff7d5Smillert } 1508803ff7d5Smillert } 1509803ff7d5Smillert } 15100f820bbbSmillert 15110f820bbbSmillert if (lp->d_type > DKMAXTYPES || lp->d_type == 0) { 15120f820bbbSmillert puts(banner); 15130f820bbbSmillert puts("Possible values are:"); 1514eb5dd924Sderaadt printf("\"IDE\", "); 15150f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15160f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15170f820bbbSmillert if (i < DKMAXTYPES - 1) 15180f820bbbSmillert fputs(", ", stdout); 15190f820bbbSmillert } 15200f820bbbSmillert putchar('\n'); 15210f820bbbSmillert 15220f820bbbSmillert for (;;) { 1523c33fcabaSmillert s = getstring("Disk type", 1524803ff7d5Smillert "What kind of disk is this? Usually SCSI, IDE, " 1525d7878011Sderaadt "ESDI, ST506, or floppy.", def); 152696a888c6Smillert if (s == NULL) 152796a888c6Smillert continue; 15285b412421Smillert if (strcasecmp(s, "IDE") == 0) { 15295b412421Smillert lp->d_type = DTYPE_ESDI; 15305b412421Smillert return; 15315b412421Smillert } 15320f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) 15330f820bbbSmillert if (strcasecmp(s, dktypenames[i]) == 0) { 15340f820bbbSmillert lp->d_type = i; 15350f820bbbSmillert return; 15360f820bbbSmillert } 15370f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", s); 15380f820bbbSmillert fputs("Valid types are: ", stdout); 15390f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15400f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15410f820bbbSmillert if (i < DKMAXTYPES - 1) 15420f820bbbSmillert fputs(", ", stdout); 15430f820bbbSmillert } 15440f820bbbSmillert putchar('\n'); 15450f820bbbSmillert } 15460f820bbbSmillert } 15470f820bbbSmillert } 154896a888c6Smillert 154996a888c6Smillert /* 155096a888c6Smillert * Get beginning and ending sectors of the OpenBSD portion of the disk 155196a888c6Smillert * from the user. 155296a888c6Smillert */ 155396a888c6Smillert void 15549fdcb4d6Skrw set_bounds(struct disklabel *lp) 155596a888c6Smillert { 15561e0ad43cSotto u_int64_t ui, start_temp; 155796a888c6Smillert 155896a888c6Smillert /* Starting sector */ 1559f1bc1b27Skrw for (;;) { 1560117239d3Skrw ui = getuint64(lp, "Starting sector", 156196a888c6Smillert "The start of the OpenBSD portion of the disk.", 156240b226e8Skrw starting_sector, DL_GETDSIZE(lp), NULL); 1563aa3970cdSkrw if (ui == CMD_ABORTED) 156496a888c6Smillert return; 1565aa3970cdSkrw else if (ui == CMD_BADVALUE) 1566f1bc1b27Skrw ; /* Try again. */ 1567f1bc1b27Skrw else if (ui >= DL_GETDSIZE(lp)) 1568f1bc1b27Skrw fprintf(stderr, "starting sector must be < %llu\n", 1569f1bc1b27Skrw DL_GETDSIZE(lp)); 1570f1bc1b27Skrw else 1571f1bc1b27Skrw break; 1572f1bc1b27Skrw } 157396a888c6Smillert start_temp = ui; 157496a888c6Smillert 15754793b14cSmillert /* Size */ 1576f1bc1b27Skrw for (;;) { 1577117239d3Skrw ui = getuint64(lp, "Size ('*' for entire disk)", 1578f98aebd4Smillert "The size of the OpenBSD portion of the disk ('*' for the " 1579f98aebd4Smillert "entire disk).", ending_sector - starting_sector, 158040b226e8Skrw DL_GETDSIZE(lp) - start_temp, NULL); 1581aa3970cdSkrw if (ui == CMD_ABORTED) 158296a888c6Smillert return; 1583aa3970cdSkrw else if (ui == CMD_BADVALUE) 1584f1bc1b27Skrw ; /* Try again. */ 1585f1bc1b27Skrw else if (ui > DL_GETDSIZE(lp) - start_temp) 1586f1bc1b27Skrw fprintf(stderr, "size must be <= %llu\n", 1587f1bc1b27Skrw DL_GETDSIZE(lp) - start_temp); 1588f1bc1b27Skrw else 1589f1bc1b27Skrw break; 1590f1bc1b27Skrw } 15914793b14cSmillert ending_sector = start_temp + ui; 159278f0fb17Skrw DL_SETBEND(lp, ending_sector); 159396a888c6Smillert starting_sector = start_temp; 159478f0fb17Skrw DL_SETBSTART(lp, starting_sector); 159596a888c6Smillert } 159696a888c6Smillert 159796a888c6Smillert /* 15980d63cfbaSjsing * Allow user to interactively change disklabel UID. 15990d63cfbaSjsing */ 16000d63cfbaSjsing void 160169a6ffbcSjsing set_duid(struct disklabel *lp) 16020d63cfbaSjsing { 16030d63cfbaSjsing char *s; 16040d63cfbaSjsing int i; 16050d63cfbaSjsing 1606f6ad9e2dSjsing printf("The disklabel UID is currently: " 1607f6ad9e2dSjsing "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n", 1608f6ad9e2dSjsing lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3], 1609f6ad9e2dSjsing lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]); 16100d63cfbaSjsing 16110d63cfbaSjsing do { 161269a6ffbcSjsing s = getstring("duid", "The disklabel UID, given as a 16 " 16130d63cfbaSjsing "character hexadecimal string.", NULL); 1614ce98d1aeShalex if (s == NULL || strlen(s) == 0) { 16150d63cfbaSjsing fputs("Command aborted\n", stderr); 16160d63cfbaSjsing return; 16170d63cfbaSjsing } 161869a6ffbcSjsing i = duid_parse(lp, s); 16190d63cfbaSjsing if (i != 0) 16200d63cfbaSjsing fputs("Invalid UID entered.\n", stderr); 16210d63cfbaSjsing } while (i != 0); 16220d63cfbaSjsing } 16230d63cfbaSjsing 16240d63cfbaSjsing /* 162596a888c6Smillert * Return a list of the "chunks" of free space available 162696a888c6Smillert */ 162796a888c6Smillert struct diskchunk * 16288809fabbSderaadt free_chunks(struct disklabel *lp) 162996a888c6Smillert { 163096a888c6Smillert struct partition **spp; 163196a888c6Smillert static struct diskchunk chunks[MAXPARTITIONS + 2]; 163299bd27d2Skrw u_int64_t start, stop; 163396a888c6Smillert int i, numchunks; 163496a888c6Smillert 16350fbd3c97Skrw /* Sort the in-use partitions based on offset */ 16360fbd3c97Skrw spp = sort_partitions(lp); 163796a888c6Smillert 163896a888c6Smillert /* If there are no partitions, it's all free. */ 16390fbd3c97Skrw if (spp[0] == NULL) { 16402d8451b0Smillert chunks[0].start = starting_sector; 164196a888c6Smillert chunks[0].stop = ending_sector; 164296a888c6Smillert chunks[1].start = chunks[1].stop = 0; 164396a888c6Smillert return (chunks); 164496a888c6Smillert } 164596a888c6Smillert 164696a888c6Smillert /* Find chunks of free space */ 164796a888c6Smillert numchunks = 0; 16480fbd3c97Skrw if (DL_GETPOFFSET(spp[0]) > starting_sector) { 16492d8451b0Smillert chunks[0].start = starting_sector; 16501e0ad43cSotto chunks[0].stop = DL_GETPOFFSET(spp[0]); 165196a888c6Smillert numchunks++; 165296a888c6Smillert } 16530fbd3c97Skrw for (i = 0; spp[i] != NULL; i++) { 165499bd27d2Skrw start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]); 1655aff3f969Sotto if (start < starting_sector) 1656aff3f969Sotto start = starting_sector; 1657aff3f969Sotto else if (start > ending_sector) 1658aff3f969Sotto start = ending_sector; 165999bd27d2Skrw if (spp[i + 1] != NULL) 166099bd27d2Skrw stop = DL_GETPOFFSET(spp[i+1]); 166199bd27d2Skrw else 166299bd27d2Skrw stop = ending_sector; 1663aff3f969Sotto if (stop < starting_sector) 1664aff3f969Sotto stop = starting_sector; 1665aff3f969Sotto else if (stop > ending_sector) 1666aff3f969Sotto stop = ending_sector; 166799bd27d2Skrw if (start < stop) { 166899bd27d2Skrw chunks[numchunks].start = start; 166999bd27d2Skrw chunks[numchunks].stop = stop; 167096a888c6Smillert numchunks++; 167196a888c6Smillert } 167296a888c6Smillert } 167396a888c6Smillert 167496a888c6Smillert /* Terminate and return */ 167596a888c6Smillert chunks[numchunks].start = chunks[numchunks].stop = 0; 167696a888c6Smillert return (chunks); 167796a888c6Smillert } 16784793b14cSmillert 16794793b14cSmillert void 168087023ed9Skrw find_bounds(struct disklabel *lp) 16814793b14cSmillert { 16826534e983Sderaadt starting_sector = DL_GETBSTART(lp); 16836534e983Sderaadt ending_sector = DL_GETBEND(lp); 1684b2d4a455Smiod 16856534e983Sderaadt if (ending_sector) { 168634ae4198Skrw if (verbose) 168734ae4198Skrw printf("Treating sectors %llu-%llu as the OpenBSD" 168834ae4198Skrw " portion of the disk.\nYou can use the 'b'" 168934ae4198Skrw " command to change this.\n\n", starting_sector, 169034ae4198Skrw ending_sector); 16914793b14cSmillert } 1692b2d4a455Smiod } 1693c0bdc608Smillert 1694c0bdc608Smillert /* 1695c0bdc608Smillert * Calculate free space. 1696c0bdc608Smillert */ 16979fdcb4d6Skrw u_int64_t 16989fdcb4d6Skrw editor_countfree(struct disklabel *lp) 1699c0bdc608Smillert { 1700d93cb2bbSkrw struct diskchunk *chunks; 17019fdcb4d6Skrw u_int64_t freesectors = 0; 1702c0bdc608Smillert int i; 1703c0bdc608Smillert 1704d93cb2bbSkrw chunks = free_chunks(lp); 1705509930fbSotto 1706d93cb2bbSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) 17079fdcb4d6Skrw freesectors += chunks[i].stop - chunks[i].start; 17089fdcb4d6Skrw 17099fdcb4d6Skrw return (freesectors); 1710c0bdc608Smillert } 1711617e6e4aSmillert 1712617e6e4aSmillert void 17134d812bb6Slum editor_help(void) 1714617e6e4aSmillert { 1715617e6e4aSmillert puts("Available commands:"); 1716617e6e4aSmillert puts( 17174d812bb6Slum " ? | h - show help n [part] - set mount point\n" 171849159a67Skrw " A - auto partition all space p [unit] - print partitions\n" 171949159a67Skrw " a [part] - add partition q - quit & save changes\n" 17204659aa0dSotto " b - set OpenBSD boundaries R [part] - resize auto allocated partition\n" 172149159a67Skrw " c [part] - change partition size r - display free space\n" 17226aaa4aabSotto " D - reset label to default s [path] - save label to file\n" 17236aaa4aabSotto " d [part] - delete partition U - undo all changes\n" 17246aaa4aabSotto " e - edit drive parameters u - undo last change\n" 17256aaa4aabSotto " g [d|u] - [d]isk or [u]ser geometry w - write label to disk\n" 17260d63cfbaSjsing " i - modify disklabel UID X - toggle expert mode\n" 17270d63cfbaSjsing " l [unit] - print disk label header x - exit & lose changes\n" 17280d63cfbaSjsing " M - disklabel(8) man page z - delete all partitions\n" 17290d63cfbaSjsing " m [part] - modify partition\n" 1730c4884206Skrw "\n" 1731c4884206Skrw "Suffixes can be used to indicate units other than sectors:\n" 1732e5f81948Sotto " 'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes) 't' (terabytes)\n" 1733e5f81948Sotto " 'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n" 1734c4884206Skrw "Values in non-sector units are truncated to the nearest cylinder boundary."); 17354d812bb6Slum 1736617e6e4aSmillert } 1737bd6726faSmillert 17384f3bbbf0Skrw void 17398809fabbSderaadt mpcopy(char **to, char **from) 1740bd6726faSmillert { 1741bd6726faSmillert int i; 1742bd6726faSmillert 1743bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1744bd6726faSmillert free(to[i]); 1745bd6726faSmillert to[i] = NULL; 1746408ab9bcSkrw if (from[i] != NULL) { 1747408ab9bcSkrw to[i] = strdup(from[i]); 1748408ab9bcSkrw if (to[i] == NULL) 1749408ab9bcSkrw errx(4, "out of memory"); 1750bd6726faSmillert } 1751bd6726faSmillert } 1752bd6726faSmillert } 1753bd6726faSmillert 1754bd6726faSmillert int 17558809fabbSderaadt mpequal(char **mp1, char **mp2) 1756bd6726faSmillert { 1757bd6726faSmillert int i; 1758bd6726faSmillert 1759bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1760bd6726faSmillert if (mp1[i] == NULL && mp2[i] == NULL) 1761bd6726faSmillert continue; 1762bd6726faSmillert 1763bd6726faSmillert if ((mp1[i] != NULL && mp2[i] == NULL) || 1764bd6726faSmillert (mp1[i] == NULL && mp2[i] != NULL) || 1765bd6726faSmillert (strcmp(mp1[i], mp2[i]) != 0)) 1766bd6726faSmillert return (0); 1767bd6726faSmillert } 1768bd6726faSmillert return (1); 1769bd6726faSmillert } 1770bd6726faSmillert 177193160b9bSkrw void 177234ae4198Skrw mpsave(struct disklabel *lp) 1773bd6726faSmillert { 1774d8b446ceSderaadt int i, j; 1775b9fc9a72Sderaadt char bdev[PATH_MAX], *p; 17763f843443Smillert struct mountinfo mi[MAXPARTITIONS]; 1777bd6726faSmillert FILE *fp; 1778fe01da94Skrw u_int8_t fstype; 1779bd6726faSmillert 178093160b9bSkrw if (!fstabfile) 178193160b9bSkrw return; 178293160b9bSkrw 17833f843443Smillert memset(&mi, 0, sizeof(mi)); 17843f843443Smillert 1785d8b446ceSderaadt for (i = 0; i < MAXPARTITIONS; i++) { 1786fe01da94Skrw fstype = lp->d_partitions[i].p_fstype; 1787fe01da94Skrw if (mountpoints[i] != NULL || fstype == FS_SWAP) { 178834ae4198Skrw mi[i].mountpoint = mountpoints[i]; 17893f843443Smillert mi[i].partno = i; 1790bd6726faSmillert } 1791bd6726faSmillert } 1792bd6726faSmillert 179334ae4198Skrw /* Convert specname to bdev */ 1794d6d80bb0Skrw if (uidflag) { 1795d6d80bb0Skrw snprintf(bdev, sizeof(bdev), 1796d6d80bb0Skrw "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 1797d6d80bb0Skrw lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3], 1798d6d80bb0Skrw lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7], 1799d6d80bb0Skrw specname[strlen(specname)-1]); 1800d6d80bb0Skrw } else if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 && 180134ae4198Skrw specname[sizeof(_PATH_DEV) - 1] == 'r') { 1802bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV, 180334ae4198Skrw &specname[sizeof(_PATH_DEV)]); 1804bd6726faSmillert } else { 180534ae4198Skrw if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r') 180693160b9bSkrw return; 1807bd6726faSmillert *p = '\0'; 180834ae4198Skrw snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1); 1809bd6726faSmillert *p = 'r'; 1810bd6726faSmillert } 1811bd6726faSmillert bdev[strlen(bdev) - 1] = '\0'; 1812bd6726faSmillert 18133f843443Smillert /* Sort mountpoints so we don't try to mount /usr/local before /usr */ 18143f843443Smillert qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp); 18153f843443Smillert 1816d71533c9Stedu if ((fp = fopen(fstabfile, "w"))) { 1817fe01da94Skrw for (i = 0; i < MAXPARTITIONS; i++) { 18185fea0b85Smillert j = mi[i].partno; 1819fe01da94Skrw fstype = lp->d_partitions[j].p_fstype; 1820fe01da94Skrw if (fstype == FS_SWAP) { 1821fe01da94Skrw fprintf(fp, "%s%c none swap sw\n", bdev, 'a'+j); 1822fe01da94Skrw } else if (mi[i].mountpoint) { 1823fe01da94Skrw fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 1824fe01da94Skrw 'a' + j, mi[i].mountpoint, 1825fe01da94Skrw fstypesnames[fstype], j == 0 ? 1 : 2); 1826fe01da94Skrw } 1827bd6726faSmillert } 1828bd6726faSmillert fclose(fp); 182993160b9bSkrw } 1830bd6726faSmillert } 183124a2c1a4Smillert 1832408ab9bcSkrw void 1833408ab9bcSkrw mpfree(char **mp) 1834408ab9bcSkrw { 1835408ab9bcSkrw int part; 1836408ab9bcSkrw 1837408ab9bcSkrw if (mp == NULL) 1838408ab9bcSkrw return; 1839408ab9bcSkrw 184075691760Skrw for (part = 0; part < MAXPARTITIONS; part++) 1841408ab9bcSkrw free(mp[part]); 1842408ab9bcSkrw 1843408ab9bcSkrw free(mp); 1844408ab9bcSkrw } 1845408ab9bcSkrw 184624a2c1a4Smillert int 1847604d3bdeSkrw get_offset(struct disklabel *lp, int partno) 184824a2c1a4Smillert { 184940b226e8Skrw struct partition opp, *pp = &lp->d_partitions[partno]; 185040b226e8Skrw u_int64_t ui, offsetalign; 185140b226e8Skrw int flags; 185224a2c1a4Smillert 185340b226e8Skrw flags = DO_CONVERSIONS; 1854117239d3Skrw ui = getuint64(lp, "offset", 18551e0ad43cSotto "Starting sector for this partition.", 18561e0ad43cSotto DL_GETPOFFSET(pp), 185740b226e8Skrw DL_GETPOFFSET(pp), &flags); 1858e9ff19beSkrw 185940b226e8Skrw if (ui == CMD_ABORTED || ui == CMD_BADVALUE) 186040b226e8Skrw return (1); 1861fc1a4cc6Sderaadt #ifdef SUN_AAT0 186240b226e8Skrw if (partno == 0 && ui != 0) { 186349bf537cSderaadt fprintf(stderr, "This architecture requires that " 186440f544cdSderaadt "partition 'a' start at sector 0.\n"); 186540b226e8Skrw return (1); 186624a2c1a4Smillert } 186740b226e8Skrw #endif 186840b226e8Skrw opp = *pp; 186940b226e8Skrw DL_SETPOFFSET(pp, ui); 187040b226e8Skrw offsetalign = 1; 187140b226e8Skrw if ((flags & DO_ROUNDING) != 0 && pp->p_fstype == FS_BSDFFS) 187240b226e8Skrw offsetalign = lp->d_secpercyl; 187340b226e8Skrw 187440b226e8Skrw if (alignpartition(lp, partno, offsetalign, 1, ROUND_OFFSET_UP) == 1) { 187540b226e8Skrw *pp = opp; 187640b226e8Skrw return (1); 187715c15d8aSkrw } 1878e9ff19beSkrw 187940b226e8Skrw if (expert == 1 && quiet == 0 && ui != DL_GETPOFFSET(pp)) 188040b226e8Skrw printf("offset rounded to sector %llu\n", DL_GETPOFFSET(pp)); 188140b226e8Skrw 188240b226e8Skrw return (0); 188315c15d8aSkrw } 188424a2c1a4Smillert 188524a2c1a4Smillert int 18869fdcb4d6Skrw get_size(struct disklabel *lp, int partno) 188724a2c1a4Smillert { 188840b226e8Skrw struct partition opp, *pp = &lp->d_partitions[partno]; 188940b226e8Skrw u_int64_t maxsize, ui, sizealign; 189040b226e8Skrw int flags; 189114192793Skrw 189214192793Skrw maxsize = max_partition_size(lp, partno); 189340b226e8Skrw flags = DO_CONVERSIONS; 1894117239d3Skrw ui = getuint64(lp, "size", "Size of the partition. " 18957da73705Skrw "You may also say +/- amount for a relative change.", 189640b226e8Skrw DL_GETPSIZE(pp), maxsize, &flags); 1897e9ff19beSkrw 189840b226e8Skrw if (ui == CMD_ABORTED || ui == CMD_BADVALUE) 189940b226e8Skrw return (1); 190040b226e8Skrw 190140b226e8Skrw opp = *pp; 190259ccf790Skrw DL_SETPSIZE(pp, ui); 190340b226e8Skrw sizealign = 1; 190440b226e8Skrw if ((flags & DO_ROUNDING) != 0 && (pp->p_fstype == FS_SWAP || 190540b226e8Skrw pp->p_fstype == FS_BSDFFS)) 190640b226e8Skrw sizealign = lp->d_secpercyl; 190740b226e8Skrw 190840b226e8Skrw if (alignpartition(lp, partno, 1, sizealign, ROUND_SIZE_UP) == 1) { 190940b226e8Skrw *pp = opp; 191040b226e8Skrw return (1); 191124a2c1a4Smillert } 1912e9ff19beSkrw 191340b226e8Skrw if (expert == 1 && quiet == 0 && ui != DL_GETPSIZE(pp)) 191440b226e8Skrw printf("size rounded to %llu sectors\n", DL_GETPSIZE(pp)); 191540b226e8Skrw 191640b226e8Skrw return (0); 1917e9ff19beSkrw } 191824a2c1a4Smillert 191924a2c1a4Smillert int 1920a95dd767Sotto get_cpg(struct disklabel *lp, int partno) 1921a95dd767Sotto { 1922a95dd767Sotto u_int64_t ui; 1923a95dd767Sotto struct partition *pp = &lp->d_partitions[partno]; 1924a95dd767Sotto 19254aa85578Skrw if (pp->p_fstype != FS_BSDFFS) 19264aa85578Skrw return (0); 19274aa85578Skrw 19284aa85578Skrw if (pp->p_cpg == 0) 19294aa85578Skrw pp->p_cpg = 1; 19304aa85578Skrw 193140b226e8Skrw if (expert == 0) 1932a95dd767Sotto return (0); 1933a95dd767Sotto 1934a95dd767Sotto for (;;) { 19350db7769aSkrw ui = getnumber("cpg", "Size of partition in fs blocks.", 19360db7769aSkrw pp->p_cpg, USHRT_MAX); 1937aa3970cdSkrw if (ui == CMD_ABORTED) 1938a95dd767Sotto return (1); 1939aa3970cdSkrw else if (ui == CMD_BADVALUE) 1940ac30837aSkrw ; /* Try again. */ 1941ac30837aSkrw else 1942a95dd767Sotto break; 1943a95dd767Sotto } 1944a95dd767Sotto pp->p_cpg = ui; 1945a95dd767Sotto return (0); 1946a95dd767Sotto } 1947a95dd767Sotto 1948a95dd767Sotto int 19498809fabbSderaadt get_fsize(struct disklabel *lp, int partno) 195024a2c1a4Smillert { 195124a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 1952a3ad4147Skrw u_int64_t ui, bytes; 1953a3ad4147Skrw u_int32_t frag, fsize; 195424a2c1a4Smillert 1955a3ad4147Skrw if (pp->p_fstype != FS_BSDFFS) 1956a4c87e64Skrw return (0); 1957a4c87e64Skrw 1958ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 1959ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 1960a3ad4147Skrw if (fsize == 0) { 1961a3ad4147Skrw fsize = 2048; 1962ddfcbf38Sotto frag = 8; 1963a3ad4147Skrw bytes = DL_GETPSIZE(pp) * lp->d_secsize; 1964a3ad4147Skrw if (bytes > 128ULL * 1024 * 1024 * 1024) 1965a3ad4147Skrw fsize *= 2; 1966a3ad4147Skrw if (bytes > 512ULL * 1024 * 1024 * 1024) 1967a3ad4147Skrw fsize *= 2; 1968a3ad4147Skrw if (fsize < lp->d_secsize) 1969a3ad4147Skrw fsize = lp->d_secsize; 1970a3ad4147Skrw if (fsize > MAXBSIZE / frag) 1971a3ad4147Skrw fsize = MAXBSIZE / frag; 1972a3ad4147Skrw pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, frag); 1973a3ad4147Skrw } 1974a3ad4147Skrw 1975a3ad4147Skrw if (expert == 0) 1976a3ad4147Skrw return (0); 1977ddfcbf38Sotto 197824a2c1a4Smillert for (;;) { 19790db7769aSkrw ui = getnumber("fragment size", 1980c782b064Skrw "Size of ffs block fragments. A multiple of the disk " 19810db7769aSkrw "sector-size.", fsize, UINT32_MAX); 1982aa3970cdSkrw if (ui == CMD_ABORTED) 198324a2c1a4Smillert return (1); 1984aa3970cdSkrw else if (ui == CMD_BADVALUE) 1985ac30837aSkrw ; /* Try again. */ 1986ac30837aSkrw else if (ui < lp->d_secsize || (ui % lp->d_secsize) != 0) 1987c782b064Skrw fprintf(stderr, "Error: fragment size must be a " 1988c782b064Skrw "multiple of the disk sector size (%d)\n", 1989c782b064Skrw lp->d_secsize); 1990ac30837aSkrw else 199124a2c1a4Smillert break; 199224a2c1a4Smillert } 199324a2c1a4Smillert if (ui == 0) 199424a2c1a4Smillert puts("Zero fragment size implies zero block size"); 1995ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag); 199624a2c1a4Smillert return (0); 199724a2c1a4Smillert } 199824a2c1a4Smillert 199924a2c1a4Smillert int 20008809fabbSderaadt get_bsize(struct disklabel *lp, int partno) 200124a2c1a4Smillert { 20027a687b60Skrw u_int64_t ui, frag, fsize; 200340b226e8Skrw struct partition opp, *pp = &lp->d_partitions[partno]; 200440b226e8Skrw u_int64_t offsetalign, sizealign; 20056be94867Skrw char *p; 200624a2c1a4Smillert 2007a49bdda8Skrw if (pp->p_fstype != FS_BSDFFS) 2008a4c87e64Skrw return (0); 2009a4c87e64Skrw 201024a2c1a4Smillert /* Avoid dividing by zero... */ 2011ddfcbf38Sotto if (pp->p_fragblock == 0) 201224a2c1a4Smillert return (1); 2013ddfcbf38Sotto 201440b226e8Skrw opp = *pp; 201540b226e8Skrw if (expert == 0) 2016a49bdda8Skrw goto align; 2017a49bdda8Skrw 2018ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 2019ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 202024a2c1a4Smillert 202124a2c1a4Smillert for (;;) { 20220db7769aSkrw ui = getnumber("block size", 20230cf7e76dSotto "Size of ffs blocks. 1, 2, 4 or 8 times ffs fragment size.", 20240db7769aSkrw fsize * frag, UINT32_MAX); 202524a2c1a4Smillert 202624a2c1a4Smillert /* sanity checks */ 2027aa3970cdSkrw if (ui == CMD_ABORTED) 202824a2c1a4Smillert return (1); 2029aa3970cdSkrw else if (ui == CMD_BADVALUE) 2030ac30837aSkrw ; /* Try again. */ 203124a2c1a4Smillert else if (ui < getpagesize()) 203224a2c1a4Smillert fprintf(stderr, 203324a2c1a4Smillert "Error: block size must be at least as big " 203424a2c1a4Smillert "as page size (%d).\n", getpagesize()); 20350cf7e76dSotto else if (ui < fsize || (fsize != ui && fsize * 2 != ui && 20360cf7e76dSotto fsize * 4 != ui && fsize * 8 != ui)) 20370cf7e76dSotto fprintf(stderr, "Error: block size must be 1, 2, 4 or " 20380cf7e76dSotto "8 times fragment size (%llu).\n", 20392777acfaSchl (unsigned long long) fsize); 204024a2c1a4Smillert else 204124a2c1a4Smillert break; 204224a2c1a4Smillert } 20430cf7e76dSotto frag = ui / fsize; 20440cf7e76dSotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, frag); 2045a49bdda8Skrw 204640b226e8Skrw #ifdef SUN_CYLCHECK 20476be94867Skrw return (0); 20486be94867Skrw #endif 204940b226e8Skrw p = getstring("Align partition to block size", 205040b226e8Skrw "Round the partition offset and size to multiples of bsize?", "y"); 205140b226e8Skrw if (*p == 'n' || *p == 'N') 205240b226e8Skrw return (0); 20536be94867Skrw 20546be94867Skrw align: 205540b226e8Skrw #ifdef SUN_CYLCHECK 205640b226e8Skrw return (0); 2057a49bdda8Skrw #endif 205840b226e8Skrw sizealign = (DISKLABELV1_FFS_FRAG(pp->p_fragblock) * 205940b226e8Skrw DISKLABELV1_FFS_FSIZE(pp->p_fragblock)) / lp->d_secsize; 206040b226e8Skrw offsetalign = 1; 206140b226e8Skrw if (DL_GETPOFFSET(pp) != starting_sector) 206240b226e8Skrw offsetalign = sizealign; 206340b226e8Skrw 2064922b28b8Skrw if (alignpartition(lp, partno, offsetalign, sizealign, ROUND_OFFSET_UP | 2065922b28b8Skrw ROUND_SIZE_DOWN | ROUND_SIZE_OVERLAP) == 1) { 206640b226e8Skrw *pp = opp; 206740b226e8Skrw return (1); 206840b226e8Skrw } 206940b226e8Skrw 207040b226e8Skrw if (expert == 1 && quiet == 0 && 207140b226e8Skrw DL_GETPOFFSET(&opp) != DL_GETPOFFSET(pp)) 207240b226e8Skrw printf("offset rounded to sector %llu\n", DL_GETPOFFSET(pp)); 207340b226e8Skrw if (expert == 1 && quiet == 0 && DL_GETPSIZE(&opp) != DL_GETPSIZE(pp)) 207440b226e8Skrw printf("size rounded to %llu sectors\n", DL_GETPSIZE(pp)); 207540b226e8Skrw 207624a2c1a4Smillert return (0); 207724a2c1a4Smillert } 207824a2c1a4Smillert 207924a2c1a4Smillert int 20808809fabbSderaadt get_fstype(struct disklabel *lp, int partno) 208124a2c1a4Smillert { 208224a2c1a4Smillert char *p; 20831e0ad43cSotto u_int64_t ui; 208424a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 208524a2c1a4Smillert 208624a2c1a4Smillert if (pp->p_fstype < FSMAXTYPES) { 2087c33fcabaSmillert p = getstring("FS type", 208824a2c1a4Smillert "Filesystem type (usually 4.2BSD or swap)", 208924a2c1a4Smillert fstypenames[pp->p_fstype]); 209024a2c1a4Smillert if (p == NULL) { 209124a2c1a4Smillert return (1); 209224a2c1a4Smillert } 209324a2c1a4Smillert for (ui = 0; ui < FSMAXTYPES; ui++) { 209424a2c1a4Smillert if (!strcasecmp(p, fstypenames[ui])) { 209524a2c1a4Smillert pp->p_fstype = ui; 209624a2c1a4Smillert break; 209724a2c1a4Smillert } 209824a2c1a4Smillert } 209924a2c1a4Smillert if (ui >= FSMAXTYPES) { 2100430e1380Skrw printf("Unrecognized filesystem type '%s', treating " 2101430e1380Skrw "as 'unknown'\n", p); 210224a2c1a4Smillert pp->p_fstype = FS_OTHER; 210324a2c1a4Smillert } 210424a2c1a4Smillert } else { 210524a2c1a4Smillert for (;;) { 21060db7769aSkrw ui = getnumber("FS type (decimal)", 2107430e1380Skrw "Filesystem type as a decimal number; usually 7 " 2108430e1380Skrw "(4.2BSD) or 1 (swap).", 21090db7769aSkrw pp->p_fstype, UINT8_MAX); 2110aa3970cdSkrw if (ui == CMD_ABORTED) 211124a2c1a4Smillert return (1); 2112aa3970cdSkrw else if (ui == CMD_BADVALUE) 2113ac30837aSkrw ; /* Try again. */ 211424a2c1a4Smillert else 211524a2c1a4Smillert break; 211624a2c1a4Smillert } 211724a2c1a4Smillert pp->p_fstype = ui; 211824a2c1a4Smillert } 211924a2c1a4Smillert return (0); 212024a2c1a4Smillert } 212124a2c1a4Smillert 212224a2c1a4Smillert int 212334ae4198Skrw get_mp(struct disklabel *lp, int partno) 212424a2c1a4Smillert { 212524a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 2126ec9fde5fSkrw char *p; 2127ec9fde5fSkrw int i; 212824a2c1a4Smillert 2129b308f3d4Skrw if (fstabfile == NULL || 2130b308f3d4Skrw pp->p_fstype == FS_UNUSED || 2131b308f3d4Skrw pp->p_fstype == FS_SWAP || 2132b308f3d4Skrw pp->p_fstype == FS_BOOT || 2133b308f3d4Skrw pp->p_fstype == FS_OTHER || 2134b308f3d4Skrw pp->p_fstype == FS_RAID) { 2135b308f3d4Skrw /* No fstabfile, no names. Not all fstypes can be named */ 2136b308f3d4Skrw return 0; 2137b308f3d4Skrw } 2138b308f3d4Skrw 2139ddaff619Smillert for (;;) { 2140c33fcabaSmillert p = getstring("mount point", 214124a2c1a4Smillert "Where to mount this filesystem (ie: / /var /usr)", 214234ae4198Skrw mountpoints[partno] ? mountpoints[partno] : "none"); 2143ac30837aSkrw if (p == NULL) 214424a2c1a4Smillert return (1); 2145ddaff619Smillert if (strcasecmp(p, "none") == 0) { 214634ae4198Skrw free(mountpoints[partno]); 214734ae4198Skrw mountpoints[partno] = NULL; 2148ddaff619Smillert break; 2149ddaff619Smillert } 2150ec9fde5fSkrw for (i = 0; i < MAXPARTITIONS; i++) 215193160b9bSkrw if (mountpoints[i] != NULL && i != partno && 2152ec9fde5fSkrw strcmp(p, mountpoints[i]) == 0) 2153ec9fde5fSkrw break; 2154ec9fde5fSkrw if (i < MAXPARTITIONS) { 215593160b9bSkrw fprintf(stderr, "'%c' already being mounted at " 215693160b9bSkrw "'%s'\n", 'a'+i, p); 2157ec9fde5fSkrw break; 2158ec9fde5fSkrw } 2159ddaff619Smillert if (*p == '/') { 2160ddaff619Smillert /* XXX - might as well realloc */ 216134ae4198Skrw free(mountpoints[partno]); 216234ae4198Skrw if ((mountpoints[partno] = strdup(p)) == NULL) 216324a2c1a4Smillert errx(4, "out of memory"); 2164ddaff619Smillert break; 2165ddaff619Smillert } 2166ddaff619Smillert fputs("Mount points must start with '/'\n", stderr); 216724a2c1a4Smillert } 2168b308f3d4Skrw 216924a2c1a4Smillert return (0); 217024a2c1a4Smillert } 21713f843443Smillert 21723f843443Smillert int 21738809fabbSderaadt micmp(const void *a1, const void *a2) 21743f843443Smillert { 21753f843443Smillert struct mountinfo *mi1 = (struct mountinfo *)a1; 21763f843443Smillert struct mountinfo *mi2 = (struct mountinfo *)a2; 21773f843443Smillert 21783f843443Smillert /* We want all the NULLs at the end... */ 21793f843443Smillert if (mi1->mountpoint == NULL && mi2->mountpoint == NULL) 21803f843443Smillert return (0); 21813f843443Smillert else if (mi1->mountpoint == NULL) 21823f843443Smillert return (1); 21833f843443Smillert else if (mi2->mountpoint == NULL) 21843f843443Smillert return (-1); 21853f843443Smillert else 21863f843443Smillert return (strcmp(mi1->mountpoint, mi2->mountpoint)); 21873f843443Smillert } 2188c33fcabaSmillert 2189c33fcabaSmillert void 219087023ed9Skrw get_geometry(int f, struct disklabel **dgpp) 2191c33fcabaSmillert { 2192c33fcabaSmillert struct stat st; 2193c33fcabaSmillert struct disklabel *disk_geop; 219487023ed9Skrw 2195c33fcabaSmillert if (fstat(f, &st) == -1) 2196c33fcabaSmillert err(4, "Can't stat device"); 2197c33fcabaSmillert 2198c33fcabaSmillert /* Get disk geometry */ 2199c33fcabaSmillert if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL) 2200c33fcabaSmillert errx(4, "out of memory"); 220190b0764fSkrw if (ioctl(f, DIOCGPDINFO, disk_geop) == -1) 220290b0764fSkrw err(4, "DIOCGPDINFO"); 2203c33fcabaSmillert *dgpp = disk_geop; 2204c33fcabaSmillert } 2205c33fcabaSmillert 2206c33fcabaSmillert void 22078809fabbSderaadt set_geometry(struct disklabel *lp, struct disklabel *dgp, 220887023ed9Skrw struct disklabel *ugp, char *p) 2209c33fcabaSmillert { 2210ac30837aSkrw if (p == NULL) 22119a36aa41Ssthen p = getstring("[d]isk or [u]ser geometry", 2212c33fcabaSmillert "Enter 'd' to use the geometry based on what the disk " 22139a36aa41Ssthen "itself thinks it is, or 'u' to use the geometry that " 22149a36aa41Ssthen "was found in the label.", 2215c33fcabaSmillert "d"); 2216ac30837aSkrw if (p == NULL) 2217c33fcabaSmillert return; 2218c33fcabaSmillert switch (*p) { 2219c33fcabaSmillert case 'd': 2220c33fcabaSmillert case 'D': 2221c33fcabaSmillert if (dgp == NULL) 2222c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2223c33fcabaSmillert else { 2224c33fcabaSmillert lp->d_secsize = dgp->d_secsize; 2225c33fcabaSmillert lp->d_nsectors = dgp->d_nsectors; 2226c33fcabaSmillert lp->d_ntracks = dgp->d_ntracks; 2227c33fcabaSmillert lp->d_ncylinders = dgp->d_ncylinders; 2228c33fcabaSmillert lp->d_secpercyl = dgp->d_secpercyl; 222934af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(dgp)); 2230c33fcabaSmillert } 2231c33fcabaSmillert break; 2232c33fcabaSmillert case 'u': 2233c33fcabaSmillert case 'U': 2234c33fcabaSmillert if (ugp == NULL) 2235c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2236c33fcabaSmillert else { 2237c33fcabaSmillert lp->d_secsize = ugp->d_secsize; 2238c33fcabaSmillert lp->d_nsectors = ugp->d_nsectors; 2239c33fcabaSmillert lp->d_ntracks = ugp->d_ntracks; 2240c33fcabaSmillert lp->d_ncylinders = ugp->d_ncylinders; 2241c33fcabaSmillert lp->d_secpercyl = ugp->d_secpercyl; 224234af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(ugp)); 2243c33fcabaSmillert if (dgp != NULL && ugp->d_secsize == dgp->d_secsize && 2244c33fcabaSmillert ugp->d_nsectors == dgp->d_nsectors && 2245c33fcabaSmillert ugp->d_ntracks == dgp->d_ntracks && 2246c33fcabaSmillert ugp->d_ncylinders == dgp->d_ncylinders && 2247c33fcabaSmillert ugp->d_secpercyl == dgp->d_secpercyl && 224834af67a3Sotto DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp)) 2249c33fcabaSmillert fputs("Note: user geometry is the same as disk " 2250c33fcabaSmillert "geometry.\n", stderr); 2251c33fcabaSmillert } 2252c33fcabaSmillert break; 2253c33fcabaSmillert default: 22549a36aa41Ssthen fputs("You must enter either 'd' or 'u'.\n", stderr); 2255c33fcabaSmillert break; 2256c33fcabaSmillert } 2257c33fcabaSmillert } 22589afbe9eeSmillert 22599afbe9eeSmillert void 22609fdcb4d6Skrw zero_partitions(struct disklabel *lp) 22619afbe9eeSmillert { 22629afbe9eeSmillert int i; 22639afbe9eeSmillert 2264b4ed6301Skrw for (i = 0; i < MAXPARTITIONS; i++) { 22659afbe9eeSmillert memset(&lp->d_partitions[i], 0, sizeof(struct partition)); 2266b4ed6301Skrw free(mountpoints[i]); 2267b4ed6301Skrw mountpoints[i] = NULL; 2268b4ed6301Skrw } 2269b4ed6301Skrw 227034af67a3Sotto DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); 22719afbe9eeSmillert } 227214192793Skrw 227314192793Skrw u_int64_t 227414192793Skrw max_partition_size(struct disklabel *lp, int partno) 227514192793Skrw { 227614192793Skrw struct partition *pp = &lp->d_partitions[partno]; 227714192793Skrw struct diskchunk *chunks; 227844ffe03bSotto u_int64_t maxsize = 0, offset; 227914192793Skrw int fstype, i; 228014192793Skrw 228114192793Skrw fstype = pp->p_fstype; 228214192793Skrw pp->p_fstype = FS_UNUSED; 228314192793Skrw chunks = free_chunks(lp); 228414192793Skrw pp->p_fstype = fstype; 228514192793Skrw 228614192793Skrw offset = DL_GETPOFFSET(pp); 228714192793Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 228814192793Skrw if (offset < chunks[i].start || offset >= chunks[i].stop) 228914192793Skrw continue; 229014192793Skrw maxsize = chunks[i].stop - offset; 229114192793Skrw break; 229214192793Skrw } 229314192793Skrw return (maxsize); 229414192793Skrw } 2295aff3f969Sotto 2296aff3f969Sotto void 2297eafadddfSkrw psize(u_int64_t sz, char unit, struct disklabel *lp) 2298aff3f969Sotto { 2299aff3f969Sotto double d = scale(sz, unit, lp); 2300aff3f969Sotto if (d < 0) 2301aff3f969Sotto printf("%llu", sz); 2302aff3f969Sotto else 2303aff3f969Sotto printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit); 2304aff3f969Sotto } 2305aff3f969Sotto 2306aff3f969Sotto void 23077ad973c1Skrw display_edit(struct disklabel *lp, char unit) 2308aff3f969Sotto { 23097ad973c1Skrw u_int64_t fr; 2310aff3f969Sotto int i; 2311aff3f969Sotto 23127ad973c1Skrw fr = editor_countfree(lp); 2313352d199bSkrw unit = canonical_unit(lp, unit); 2314aff3f969Sotto 2315aff3f969Sotto printf("OpenBSD area: "); 231659882f1dSkrw psize(starting_sector, 0, lp); 2317aff3f969Sotto printf("-"); 231859882f1dSkrw psize(ending_sector, 0, lp); 2319aff3f969Sotto printf("; size: "); 2320aff3f969Sotto psize(ending_sector - starting_sector, unit, lp); 2321aff3f969Sotto printf("; free: "); 2322aff3f969Sotto psize(fr, unit, lp); 2323aff3f969Sotto 2324aff3f969Sotto printf("\n# %16.16s %16.16s fstype [fsize bsize cpg]\n", 2325aff3f969Sotto "size", "offset"); 2326aff3f969Sotto for (i = 0; i < lp->d_npartitions; i++) 232734ae4198Skrw display_partition(stdout, lp, i, unit); 2328aff3f969Sotto } 2329a2c1f847Shenning 2330a2c1f847Shenning void 2331a2c1f847Shenning parse_autotable(char *filename) 2332a2c1f847Shenning { 2333a2c1f847Shenning FILE *cfile; 2334*5f012d92Snaddy size_t linesize = 0; 2335*5f012d92Snaddy char *line = NULL, *buf, *t; 2336a2c1f847Shenning uint idx = 0, pctsum = 0; 2337a2c1f847Shenning struct space_allocation *sa; 2338a2c1f847Shenning 2339a2c1f847Shenning if ((cfile = fopen(filename, "r")) == NULL) 2340a2c1f847Shenning err(1, "%s", filename); 2341a2c1f847Shenning if ((alloc_table = calloc(1, sizeof(struct alloc_table))) == NULL) 2342a2c1f847Shenning err(1, NULL); 2343f55524eaSsthen alloc_table_nitems = 1; 2344a2c1f847Shenning 2345*5f012d92Snaddy while (getline(&line, &linesize, cfile) != -1) { 2346a2c1f847Shenning if ((alloc_table[0].table = reallocarray(alloc_table[0].table, 2347a2c1f847Shenning idx + 1, sizeof(*sa))) == NULL) 2348a2c1f847Shenning err(1, NULL); 2349a2c1f847Shenning sa = &(alloc_table[0].table[idx]); 2350ee18520dSotto memset(sa, 0, sizeof(*sa)); 2351a2c1f847Shenning idx++; 2352a2c1f847Shenning 2353*5f012d92Snaddy buf = line; 235458c7d7acSnaddy if ((sa->mp = get_token(&buf)) == NULL || 2355a2c1f847Shenning (sa->mp[0] != '/' && strcmp(sa->mp, "swap"))) 2356a2c1f847Shenning errx(1, "%s: parse error on line %u", filename, idx); 235758c7d7acSnaddy if ((t = get_token(&buf)) == NULL || 2358a2c1f847Shenning parse_sizerange(t, &sa->minsz, &sa->maxsz) == -1) 2359a2c1f847Shenning errx(1, "%s: parse error on line %u", filename, idx); 236058c7d7acSnaddy if ((t = get_token(&buf)) != NULL && 2361a2c1f847Shenning parse_pct(t, &sa->rate) == -1) 2362a2c1f847Shenning errx(1, "%s: parse error on line %u", filename, idx); 2363a2c1f847Shenning if (sa->minsz > sa->maxsz) 2364a2c1f847Shenning errx(1, "%s: min size > max size on line %u", filename, 2365a2c1f847Shenning idx); 2366a2c1f847Shenning pctsum += sa->rate; 2367a2c1f847Shenning } 2368a2c1f847Shenning if (pctsum > 100) 2369a2c1f847Shenning errx(1, "%s: sum of extra space allocation > 100%%", filename); 2370a2c1f847Shenning alloc_table[0].sz = idx; 2371*5f012d92Snaddy free(line); 2372a2c1f847Shenning fclose(cfile); 2373a2c1f847Shenning } 2374a2c1f847Shenning 2375a2c1f847Shenning char * 237658c7d7acSnaddy get_token(char **s) 2377a2c1f847Shenning { 2378a2c1f847Shenning char *p, *r; 2379a2c1f847Shenning size_t tlen = 0; 2380a2c1f847Shenning 2381a2c1f847Shenning p = *s; 238258c7d7acSnaddy while (**s != '\0' && !isspace((u_char)**s)) { 2383a2c1f847Shenning (*s)++; 2384a2c1f847Shenning tlen++; 2385a2c1f847Shenning } 2386a2c1f847Shenning if (tlen == 0) 2387a2c1f847Shenning return (NULL); 2388a2c1f847Shenning 2389a2c1f847Shenning /* eat whitespace */ 239058c7d7acSnaddy while (isspace((u_char)**s)) 2391a2c1f847Shenning (*s)++; 2392a2c1f847Shenning 2393104c1c3cSmillert if ((r = strndup(p, tlen)) == NULL) 2394a2c1f847Shenning err(1, NULL); 2395a2c1f847Shenning return (r); 2396a2c1f847Shenning } 2397a2c1f847Shenning 2398a2c1f847Shenning int 2399a2c1f847Shenning apply_unit(double val, u_char unit, u_int64_t *n) 2400a2c1f847Shenning { 2401a2c1f847Shenning u_int64_t factor = 1; 2402a2c1f847Shenning 2403a2c1f847Shenning switch (tolower(unit)) { 2404a2c1f847Shenning case 't': 2405a2c1f847Shenning factor *= 1024; 2406a2c1f847Shenning /* FALLTHROUGH */ 2407a2c1f847Shenning case 'g': 2408a2c1f847Shenning factor *= 1024; 2409a2c1f847Shenning /* FALLTHROUGH */ 2410a2c1f847Shenning case 'm': 2411a2c1f847Shenning factor *= 1024; 2412a2c1f847Shenning /* FALLTHROUGH */ 2413a2c1f847Shenning case 'k': 2414a2c1f847Shenning factor *= 1024; 2415a2c1f847Shenning break; 2416a2c1f847Shenning default: 2417a2c1f847Shenning return (-1); 2418a2c1f847Shenning } 2419a2c1f847Shenning 2420a2c1f847Shenning val *= factor / DEV_BSIZE; 2421a2c1f847Shenning if (val > ULLONG_MAX) 2422a2c1f847Shenning return (-1); 2423a2c1f847Shenning *n = val; 2424a2c1f847Shenning return (0); 2425a2c1f847Shenning } 2426a2c1f847Shenning 2427a2c1f847Shenning int 2428a2c1f847Shenning parse_sizespec(const char *buf, double *val, char **unit) 2429a2c1f847Shenning { 24305f6cf98aSkrw errno = 0; 2431a2c1f847Shenning *val = strtod(buf, unit); 24325f6cf98aSkrw if (errno == ERANGE || *val < 0 || *val > ULLONG_MAX) 24335f6cf98aSkrw return (-1); /* too big/small */ 24345f6cf98aSkrw if (*val == 0 && *unit == buf) 24355f6cf98aSkrw return (-1); /* No conversion performed. */ 2436a2c1f847Shenning if (*unit != NULL && *unit[0] == '\0') 2437a2c1f847Shenning *unit = NULL; 2438a2c1f847Shenning return (0); 2439a2c1f847Shenning } 2440a2c1f847Shenning 2441a2c1f847Shenning int 2442a2c1f847Shenning parse_sizerange(char *buf, u_int64_t *min, u_int64_t *max) 2443a2c1f847Shenning { 2444a2c1f847Shenning char *p, *unit1 = NULL, *unit2 = NULL; 2445a2c1f847Shenning double val1 = 0, val2 = 0; 2446a2c1f847Shenning 2447a2c1f847Shenning if ((p = strchr(buf, '-')) != NULL) { 2448a2c1f847Shenning p[0] = '\0'; 2449a2c1f847Shenning p++; 2450a2c1f847Shenning } 2451a2c1f847Shenning *max = 0; 2452a2c1f847Shenning if (parse_sizespec(buf, &val1, &unit1) == -1) 2453a2c1f847Shenning return (-1); 2454a2c1f847Shenning if (p != NULL && p[0] != '\0') { 2455a2c1f847Shenning if (p[0] == '*') 2456a2c1f847Shenning *max = -1; 2457a2c1f847Shenning else 2458a2c1f847Shenning if (parse_sizespec(p, &val2, &unit2) == -1) 2459a2c1f847Shenning return (-1); 2460a2c1f847Shenning } 2461a2c1f847Shenning if (unit1 == NULL && (unit1 = unit2) == NULL) 2462a2c1f847Shenning return (-1); 2463a2c1f847Shenning if (apply_unit(val1, unit1[0], min) == -1) 2464a2c1f847Shenning return (-1); 2465a2c1f847Shenning if (val2 > 0) { 2466a2c1f847Shenning if (apply_unit(val2, unit2[0], max) == -1) 2467a2c1f847Shenning return (-1); 2468a2c1f847Shenning } else 2469a2c1f847Shenning if (*max == 0) 2470a2c1f847Shenning *max = *min; 2471a2c1f847Shenning free(buf); 2472a2c1f847Shenning return (0); 2473a2c1f847Shenning } 2474a2c1f847Shenning 2475a2c1f847Shenning int 2476a2c1f847Shenning parse_pct(char *buf, int *n) 2477a2c1f847Shenning { 2478a2c1f847Shenning const char *errstr; 2479a2c1f847Shenning 2480a2c1f847Shenning if (buf[strlen(buf) - 1] == '%') 2481a2c1f847Shenning buf[strlen(buf) - 1] = '\0'; 2482a2c1f847Shenning *n = strtonum(buf, 0, 100, &errstr); 2483a2c1f847Shenning if (errstr) { 2484a2c1f847Shenning warnx("parse percent %s: %s", buf, errstr); 2485a2c1f847Shenning return (-1); 2486a2c1f847Shenning } 2487a2c1f847Shenning free(buf); 2488a2c1f847Shenning return (0); 2489a2c1f847Shenning } 249040b226e8Skrw 249140b226e8Skrw int 249240b226e8Skrw alignpartition(struct disklabel *lp, int partno, u_int64_t startalign, 249340b226e8Skrw u_int64_t stopalign, int flags) 249440b226e8Skrw { 249540b226e8Skrw struct partition *pp = &lp->d_partitions[partno]; 249640b226e8Skrw struct diskchunk *chunks; 249740b226e8Skrw u_int64_t start, stop, maxstop; 249840b226e8Skrw unsigned int i; 249940b226e8Skrw u_int8_t fstype; 250040b226e8Skrw 250140b226e8Skrw start = DL_GETPOFFSET(pp); 250240b226e8Skrw if ((flags & ROUND_OFFSET_UP) == ROUND_OFFSET_UP) 250340b226e8Skrw start = ((start + startalign - 1) / startalign) * startalign; 250440b226e8Skrw else if ((flags & ROUND_OFFSET_DOWN) == ROUND_OFFSET_DOWN) 250540b226e8Skrw start = (start / startalign) * startalign; 250640b226e8Skrw 250740b226e8Skrw /* Find the chunk that contains 'start'. */ 250840b226e8Skrw fstype = pp->p_fstype; 250940b226e8Skrw pp->p_fstype = FS_UNUSED; 251040b226e8Skrw chunks = free_chunks(lp); 251140b226e8Skrw pp->p_fstype = fstype; 251240b226e8Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 251340b226e8Skrw if (start >= chunks[i].start && start < chunks[i].stop) 251440b226e8Skrw break; 251540b226e8Skrw } 251640b226e8Skrw if (chunks[i].stop == 0) { 2517aef735d2Skrw fprintf(stderr, "'%c' aligned offset %llu lies outside " 2518aef735d2Skrw "the OpenBSD bounds or inside another partition\n", 2519aef735d2Skrw 'a' + partno, start); 252040b226e8Skrw return (1); 252140b226e8Skrw } 252240b226e8Skrw 252340b226e8Skrw /* Calculate the new 'stop' sector, the sector after the partition. */ 2524aef735d2Skrw if ((flags & ROUND_SIZE_OVERLAP) == 0) 2525aef735d2Skrw maxstop = (chunks[i].stop / stopalign) * stopalign; 2526aef735d2Skrw else 2527aef735d2Skrw maxstop = (ending_sector / stopalign) * stopalign; 2528aef735d2Skrw 252940b226e8Skrw stop = DL_GETPOFFSET(pp) + DL_GETPSIZE(pp); 253040b226e8Skrw if ((flags & ROUND_SIZE_UP) == ROUND_SIZE_UP) 253140b226e8Skrw stop = ((stop + stopalign - 1) / stopalign) * stopalign; 253240b226e8Skrw else if ((flags & ROUND_SIZE_DOWN) == ROUND_SIZE_DOWN) 253340b226e8Skrw stop = (stop / stopalign) * stopalign; 2534aef735d2Skrw if (stop > maxstop) 253540b226e8Skrw stop = maxstop; 253640b226e8Skrw 2537aef735d2Skrw if (stop <= start) { 2538aef735d2Skrw fprintf(stderr, "'%c' aligned size <= 0\n", 'a' + partno); 2539aef735d2Skrw return (1); 2540aef735d2Skrw } 2541aef735d2Skrw 254240b226e8Skrw if (start != DL_GETPOFFSET(pp)) 254340b226e8Skrw DL_SETPOFFSET(pp, start); 2544aef735d2Skrw if (stop != DL_GETPOFFSET(pp) + DL_GETPSIZE(pp)) 254540b226e8Skrw DL_SETPSIZE(pp, stop - start); 254640b226e8Skrw 254740b226e8Skrw return (0); 254840b226e8Skrw } 2549