1*97f090a4Ssolene /* $OpenBSD: editor.c,v 1.351 2018/09/21 14:07:34 solene Exp $ */ 26fe57b42Smillert 36fe57b42Smillert /* 42d8451b0Smillert * Copyright (c) 1997-2000 Todd C. Miller <Todd.Miller@courtesan.com> 56fe57b42Smillert * 606f01696Smillert * Permission to use, copy, modify, and distribute this software for any 706f01696Smillert * purpose with or without fee is hereby granted, provided that the above 806f01696Smillert * copyright notice and this permission notice appear in all copies. 96fe57b42Smillert * 10328f1f07Smillert * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11328f1f07Smillert * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12328f1f07Smillert * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13328f1f07Smillert * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14328f1f07Smillert * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15328f1f07Smillert * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16328f1f07Smillert * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 176fe57b42Smillert */ 186fe57b42Smillert 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 838dde8bb6Sotto /* entries for swap and var are changed by editor_allocspace() */ 84a2c1f847Shenning struct space_allocation alloc_big[] = { 85d190517aSotto { MEG(150), GIG(1), 5, "/" }, 86559340afSotto { MEG(80), MEG(256), 10, "swap" }, 874ab111d2Sderaadt { MEG(120), GIG(4), 8, "/tmp" }, 8892adb55fSderaadt { MEG(80), GIG(4), 13, "/var" }, 8921a0d117Sderaadt { MEG(900), GIG(2), 5, "/usr" }, 90ecf06799Sajacoutot { MEG(384), GIG(1), 3, "/usr/X11R6" }, 91*97f090a4Ssolene { GIG(1), GIG(20), 15, "/usr/local" }, 92aa4db624Sbenno { MEG(1300), GIG(2), 2, "/usr/src" }, 93d6b9791fSbluhm { GIG(5), GIG(6), 4, "/usr/obj" }, 94d190517aSotto { GIG(1), GIG(300), 35, "/home" } 954ab111d2Sderaadt /* Anything beyond this leave for the user to decide */ 968dde8bb6Sotto }; 978dde8bb6Sotto 98a2c1f847Shenning struct space_allocation alloc_medium[] = { 99905e8239Sderaadt { MEG(800), GIG(2), 5, "/" }, 1008dde8bb6Sotto { MEG(80), MEG(256), 10, "swap" }, 101905e8239Sderaadt { MEG(900), GIG(3), 78, "/usr" }, 102905e8239Sderaadt { MEG(256), GIG(2), 7, "/home" } 1038dde8bb6Sotto }; 1048dde8bb6Sotto 105a2c1f847Shenning struct space_allocation alloc_small[] = { 10692adb55fSderaadt { MEG(700), GIG(4), 95, "/" }, 1078dde8bb6Sotto { MEG(1), MEG(256), 5, "swap" } 1088dde8bb6Sotto }; 1098dde8bb6Sotto 110a2c1f847Shenning struct space_allocation alloc_stupid[] = { 1118dde8bb6Sotto { MEG(1), MEG(2048), 100, "/" } 1128dde8bb6Sotto }; 1138dde8bb6Sotto 114b2813ff1Sderaadt #ifndef nitems 115b2813ff1Sderaadt #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 116b2813ff1Sderaadt #endif 117b2813ff1Sderaadt 118a2c1f847Shenning struct alloc_table { 119a2c1f847Shenning struct space_allocation *table; 1208a862940Sderaadt int sz; 121a2c1f847Shenning }; 122a2c1f847Shenning 123a2c1f847Shenning struct alloc_table alloc_table_default[] = { 1248dde8bb6Sotto { alloc_big, nitems(alloc_big) }, 1258dde8bb6Sotto { alloc_medium, nitems(alloc_medium) }, 1268dde8bb6Sotto { alloc_small, nitems(alloc_small) }, 1278dde8bb6Sotto { alloc_stupid, nitems(alloc_stupid) } 128557f712bSkrw }; 129a2c1f847Shenning struct alloc_table *alloc_table = alloc_table_default; 130f55524eaSsthen int alloc_table_nitems = 4; 131557f712bSkrw 1329fdcb4d6Skrw void edit_parms(struct disklabel *); 1336aaa4aabSotto void editor_resize(struct disklabel *, char *); 13434ae4198Skrw void editor_add(struct disklabel *, char *); 1359fdcb4d6Skrw void editor_change(struct disklabel *, char *); 1369fdcb4d6Skrw u_int64_t editor_countfree(struct disklabel *); 13734ae4198Skrw void editor_delete(struct disklabel *, char *); 1384d812bb6Slum void editor_help(void); 13934ae4198Skrw void editor_modify(struct disklabel *, char *); 14034ae4198Skrw void editor_name(struct disklabel *, char *); 141b228e876Smiod char *getstring(const char *, const char *, const char *); 14240b226e8Skrw u_int64_t getuint64(struct disklabel *, char *, char *, u_int64_t, 14340b226e8Skrw u_int64_t, int *); 1440db7769aSkrw u_int64_t getnumber(char *, char *, u_int32_t, u_int32_t); 1451f0f871dSkrw int has_overlap(struct disklabel *); 146c72b5b24Smillert int partition_cmp(const void *, const void *); 1470fbd3c97Skrw struct partition **sort_partitions(struct disklabel *); 148c72b5b24Smillert void getdisktype(struct disklabel *, char *, char *); 14987023ed9Skrw void find_bounds(struct disklabel *); 1509fdcb4d6Skrw void set_bounds(struct disklabel *); 15169a6ffbcSjsing void set_duid(struct disklabel *); 152c72b5b24Smillert struct diskchunk *free_chunks(struct disklabel *); 153c72b5b24Smillert int micmp(const void *, const void *); 154c72b5b24Smillert int mpequal(char **, char **); 155c72b5b24Smillert int get_bsize(struct disklabel *, int); 156c72b5b24Smillert int get_fsize(struct disklabel *, int); 157a95dd767Sotto int get_cpg(struct disklabel *, int); 158c72b5b24Smillert int get_fstype(struct disklabel *, int); 15934ae4198Skrw int get_mp(struct disklabel *, int); 160604d3bdeSkrw int get_offset(struct disklabel *, int); 1619fdcb4d6Skrw int get_size(struct disklabel *, int); 16287023ed9Skrw void get_geometry(int, struct disklabel **); 16387023ed9Skrw void set_geometry(struct disklabel *, struct disklabel *, struct disklabel *, 16487023ed9Skrw char *); 1659fdcb4d6Skrw void zero_partitions(struct disklabel *); 16614192793Skrw u_int64_t max_partition_size(struct disklabel *, int); 1677ad973c1Skrw void display_edit(struct disklabel *, char); 168e07939ebSderaadt void psize(u_int64_t sz, char unit, struct disklabel *lp); 169a2c1f847Shenning char *get_token(char **, size_t *); 170a2c1f847Shenning int apply_unit(double, u_char, u_int64_t *); 171a2c1f847Shenning int parse_sizespec(const char *, double *, char **); 172a2c1f847Shenning int parse_sizerange(char *, u_int64_t *, u_int64_t *); 173a2c1f847Shenning int parse_pct(char *, int *); 17440b226e8Skrw int alignpartition(struct disklabel *, int, u_int64_t, u_int64_t, int); 17596a888c6Smillert 1761e0ad43cSotto static u_int64_t starting_sector; 1771e0ad43cSotto static u_int64_t ending_sector; 1782d8451b0Smillert static int expert; 179fc6e9c48Sotto static int overlap; 1806fe57b42Smillert 1816fe57b42Smillert /* 1824d4a335eSkrw * Simple partition editor. 1836fe57b42Smillert */ 1846fe57b42Smillert int 185d6d80bb0Skrw editor(int f) 1866fe57b42Smillert { 187d6d80bb0Skrw struct disklabel origlabel, lastlabel, tmplabel, newlab = lab; 1887e28fb0fSderaadt struct disklabel *disk_geop = NULL; 18996a888c6Smillert struct partition *pp; 1906fe57b42Smillert FILE *fp; 1916fe57b42Smillert char buf[BUFSIZ], *cmd, *arg; 19234ae4198Skrw char **omountpoints = NULL; 1934f3bbbf0Skrw char **origmountpoints = NULL, **tmpmountpoints = NULL; 1947e28fb0fSderaadt int i, error = 0; 195bd6726faSmillert 196bd6726faSmillert /* Alloc and init mount point info */ 19734ae4198Skrw if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 1984f3bbbf0Skrw !(origmountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 199bd6726faSmillert !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *)))) 200bd6726faSmillert errx(4, "out of memory"); 2016fe57b42Smillert 20296a888c6Smillert /* Don't allow disk type of "unknown" */ 203430e1380Skrw getdisktype(&newlab, "You need to specify a type for this disk.", 204430e1380Skrw specname); 2056fe57b42Smillert 20687023ed9Skrw /* Get the on-disk geometries if possible */ 20787023ed9Skrw get_geometry(f, &disk_geop); 208c33fcabaSmillert 209d09f3941Smillert /* How big is the OpenBSD portion of the disk? */ 210d6d80bb0Skrw find_bounds(&newlab); 211d09f3941Smillert 21296a888c6Smillert /* Make sure there is no partition overlap. */ 213d6d80bb0Skrw if (has_overlap(&newlab)) 2146fe57b42Smillert errx(1, "can't run when there is partition overlap."); 2156fe57b42Smillert 21696a888c6Smillert /* If we don't have a 'c' partition, create one. */ 217d6d80bb0Skrw pp = &newlab.d_partitions[RAW_PART]; 218d6d80bb0Skrw if (newlab.d_npartitions < 3 || DL_GETPSIZE(pp) == 0) { 21996a888c6Smillert puts("No 'c' partition found, adding one that spans the disk."); 220d6d80bb0Skrw if (newlab.d_npartitions < 3) 221d6d80bb0Skrw newlab.d_npartitions = 3; 22234af67a3Sotto DL_SETPOFFSET(pp, 0); 223d6d80bb0Skrw DL_SETPSIZE(pp, DL_GETDSIZE(&newlab)); 22496a888c6Smillert pp->p_fstype = FS_UNUSED; 225ddfcbf38Sotto pp->p_fragblock = pp->p_cpg = 0; 22696a888c6Smillert } 2270f820bbbSmillert 228fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 2294bf1fc9dSotto if ((newlab.d_flags & D_VENDOR) && !quiet) { 230fc1a4cc6Sderaadt puts("This platform requires that partition offsets/sizes " 231fc1a4cc6Sderaadt "be on cylinder boundaries.\n" 232fc1a4cc6Sderaadt "Partition offsets/sizes will be rounded to the " 233fc1a4cc6Sderaadt "nearest cylinder automatically."); 234fc1a4cc6Sderaadt } 2356fe57b42Smillert #endif 2366fe57b42Smillert 237bd6726faSmillert /* Set d_bbsize and d_sbsize as necessary */ 238d6d80bb0Skrw if (newlab.d_bbsize == 0) 239d6d80bb0Skrw newlab.d_bbsize = BBSIZE; 240d6d80bb0Skrw if (newlab.d_sbsize == 0) 241d6d80bb0Skrw newlab.d_sbsize = SBSIZE; 242f98aebd4Smillert 24393160b9bSkrw /* Save the (U|u)ndo labels and mountpoints. */ 24493160b9bSkrw mpcopy(origmountpoints, mountpoints); 245d6d80bb0Skrw origlabel = newlab; 246d6d80bb0Skrw lastlabel = newlab; 24734ae4198Skrw 24834ae4198Skrw puts("Label editor (enter '?' for help at any prompt)"); 2496fe57b42Smillert for (;;) { 2506fe57b42Smillert fputs("> ", stdout); 2516e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 2526e0becc5Smillert putchar('\n'); 2536e0becc5Smillert buf[0] = 'q'; 2546e0becc5Smillert buf[1] = '\0'; 2556e0becc5Smillert } 256260513deSmillert if ((cmd = strtok(buf, " \t\r\n")) == NULL) 257260513deSmillert continue; 258260513deSmillert arg = strtok(NULL, " \t\r\n"); 2596fe57b42Smillert 2604f3bbbf0Skrw if ((*cmd != 'u') && (*cmd != 'U')) { 2614f3bbbf0Skrw /* 2624f3bbbf0Skrw * Save undo info in case the command tries to make 2634f3bbbf0Skrw * changes but decides not to. 2644f3bbbf0Skrw */ 2654f3bbbf0Skrw tmplabel = lastlabel; 266d6d80bb0Skrw lastlabel = newlab; 2674f3bbbf0Skrw mpcopy(tmpmountpoints, omountpoints); 2684f3bbbf0Skrw mpcopy(omountpoints, mountpoints); 2694f3bbbf0Skrw } 2706fe57b42Smillert 2714f3bbbf0Skrw switch (*cmd) { 2726fe57b42Smillert case '?': 273ea37abd3Sderaadt case 'h': 2744d812bb6Slum editor_help(); 2756fe57b42Smillert break; 2766fe57b42Smillert 277557f712bSkrw case 'A': 278d6d80bb0Skrw if (ioctl(f, DIOCGPDINFO, &newlab) == 0) { 27940b226e8Skrw int oquiet = quiet, oexpert = expert; 2804bf1fc9dSotto aflag = 1; 28140b226e8Skrw quiet = expert = 0; 282d6d80bb0Skrw editor_allocspace(&newlab); 28340b226e8Skrw quiet = oquiet; 28440b226e8Skrw expert = oexpert; 285ab20a3eaSkrw } else 286d6d80bb0Skrw newlab = lastlabel; 287557f712bSkrw break; 2886fe57b42Smillert case 'a': 289d6d80bb0Skrw editor_add(&newlab, arg); 29096a888c6Smillert break; 29196a888c6Smillert 29296a888c6Smillert case 'b': 293d6d80bb0Skrw set_bounds(&newlab); 2946fe57b42Smillert break; 2956fe57b42Smillert 2966fe57b42Smillert case 'c': 297d6d80bb0Skrw editor_change(&newlab, arg); 2986fe57b42Smillert break; 2996fe57b42Smillert 3009afbe9eeSmillert case 'D': 301d6d80bb0Skrw if (ioctl(f, DIOCGPDINFO, &newlab) == 0) { 30271bba4ecSkrw dflag = 1; 30393160b9bSkrw for (i=0; i<MAXPARTITIONS; i++) { 30493160b9bSkrw free(mountpoints[i]); 30593160b9bSkrw mountpoints[i] = NULL; 30693160b9bSkrw } 30793160b9bSkrw } else 308cdd7eb76Smillert warn("unable to get default partition table"); 3099afbe9eeSmillert break; 3109afbe9eeSmillert 3116fe57b42Smillert case 'd': 312d6d80bb0Skrw editor_delete(&newlab, arg); 3136fe57b42Smillert break; 3146fe57b42Smillert 3159afbe9eeSmillert case 'e': 316d6d80bb0Skrw edit_parms(&newlab); 3179afbe9eeSmillert break; 3189afbe9eeSmillert 319c33fcabaSmillert case 'g': 320d6d80bb0Skrw set_geometry(&newlab, disk_geop, &lab, arg); 321c33fcabaSmillert break; 322c33fcabaSmillert 3230d63cfbaSjsing case 'i': 324d6d80bb0Skrw set_duid(&newlab); 3250d63cfbaSjsing break; 3260d63cfbaSjsing 3276fe57b42Smillert case 'm': 328d6d80bb0Skrw editor_modify(&newlab, arg); 329bd6726faSmillert break; 330bd6726faSmillert 331bd6726faSmillert case 'n': 3325c79e1cfSkrw if (!fstabfile) { 333bd6726faSmillert fputs("This option is not valid when run " 33484d0bb16Sderaadt "without the -f flag.\n", stderr); 335bd6726faSmillert break; 336bd6726faSmillert } 337d6d80bb0Skrw editor_name(&newlab, arg); 3386fe57b42Smillert break; 3396fe57b42Smillert 3406fe57b42Smillert case 'p': 3417ad973c1Skrw display_edit(&newlab, arg ? *arg : 0); 3426fe57b42Smillert break; 3436fe57b42Smillert 344aff3f969Sotto case 'l': 345d6d80bb0Skrw display(stdout, &newlab, arg ? *arg : 0, 0); 346aff3f969Sotto break; 347aff3f969Sotto 348508086e9Smillert case 'M': { 349508086e9Smillert sig_t opipe = signal(SIGPIPE, SIG_IGN); 35045decb36Sderaadt char *pager, *comm = NULL; 351e7936562Sderaadt extern const u_char manpage[]; 35208f8e31fSotto extern const int manpage_sz; 3535d12b01bSderaadt 354489bd112Spjanzen if ((pager = getenv("PAGER")) == NULL || *pager == '\0') 355508086e9Smillert pager = _PATH_LESS; 35608f8e31fSotto 35745decb36Sderaadt if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 && 35845decb36Sderaadt (fp = popen(comm, "w")) != NULL) { 35908f8e31fSotto (void) fwrite(manpage, manpage_sz, 1, fp); 3605d12b01bSderaadt pclose(fp); 361508086e9Smillert } else 362508086e9Smillert warn("unable to execute %s", pager); 363508086e9Smillert 36445decb36Sderaadt free(comm); 365508086e9Smillert (void)signal(SIGPIPE, opipe); 3665d12b01bSderaadt break; 367508086e9Smillert } 3685d12b01bSderaadt 3696fe57b42Smillert case 'q': 37069220492Smillert if (donothing) { 37169220492Smillert puts("In no change mode, not writing label."); 3727e28fb0fSderaadt goto done; 37369220492Smillert } 37493160b9bSkrw 37571bba4ecSkrw /* 37693160b9bSkrw * If we haven't changed the original label, and it 37793160b9bSkrw * wasn't a default label or an auto-allocated label, 37893160b9bSkrw * there is no need to do anything before exiting. Note 37993160b9bSkrw * that 'w' will reset dflag and aflag to allow 'q' to 38093160b9bSkrw * exit without further questions. 38171bba4ecSkrw */ 382ab20a3eaSkrw if (!dflag && !aflag && 383d6d80bb0Skrw memcmp(&lab, &newlab, sizeof(newlab)) == 0) { 384bd6726faSmillert puts("No label changes."); 385d6d80bb0Skrw /* Save mountpoint info. */ 386d6d80bb0Skrw mpsave(&newlab); 3877e28fb0fSderaadt goto done; 3886fe57b42Smillert } 3896fe57b42Smillert do { 390d0e67762Smillert arg = getstring("Write new label?", 391d0e67762Smillert "Write the modified label to disk?", 392d0e67762Smillert "y"); 393025f5691Sderaadt } while (arg && tolower((unsigned char)*arg) != 'y' && 394025f5691Sderaadt tolower((unsigned char)*arg) != 'n'); 395025f5691Sderaadt if (arg && tolower((unsigned char)*arg) == 'y') { 39640bba581Skrw if (writelabel(f, &newlab) == 0) { 397d6d80bb0Skrw newlab = lab; /* lab now has UID info */ 3987e28fb0fSderaadt goto done; 3996fe57b42Smillert } 400d0e67762Smillert warnx("unable to write label"); 401d0e67762Smillert } 4027e28fb0fSderaadt error = 1; 4037e28fb0fSderaadt goto done; 4046fe57b42Smillert /* NOTREACHED */ 4056fe57b42Smillert break; 4066fe57b42Smillert 4076aaa4aabSotto case 'R': 408fc6e9c48Sotto if (aflag && !overlap) 409d6d80bb0Skrw editor_resize(&newlab, arg); 4106aaa4aabSotto else 4116aaa4aabSotto fputs("Resize only implemented for auto " 412fc6e9c48Sotto "allocated labels\n", stderr); 4136aaa4aabSotto break; 4146aaa4aabSotto 41525f9c360Skrw case 'r': { 41625f9c360Skrw struct diskchunk *chunks; 41725f9c360Skrw int i; 4189fdcb4d6Skrw /* Display free space. */ 419d6d80bb0Skrw chunks = free_chunks(&newlab); 42025f9c360Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; 42125f9c360Skrw i++) 42225f9c360Skrw fprintf(stderr, "Free sectors: %16llu - %16llu " 42325f9c360Skrw "(%16llu)\n", 42425f9c360Skrw chunks[i].start, chunks[i].stop - 1, 42525f9c360Skrw chunks[i].stop - chunks[i].start); 42625f9c360Skrw fprintf(stderr, "Total free sectors: %llu.\n", 427d6d80bb0Skrw editor_countfree(&newlab)); 428c0bdc608Smillert break; 42925f9c360Skrw } 430c0bdc608Smillert 4316fe57b42Smillert case 's': 4326fe57b42Smillert if (arg == NULL) { 433c33fcabaSmillert arg = getstring("Filename", 4346fe57b42Smillert "Name of the file to save label into.", 4356fe57b42Smillert NULL); 436e97229a3Scnst if (arg == NULL || *arg == '\0') 4376fe57b42Smillert break; 4386fe57b42Smillert } 4396fe57b42Smillert if ((fp = fopen(arg, "w")) == NULL) { 4406fe57b42Smillert warn("cannot open %s", arg); 4416fe57b42Smillert } else { 442d6d80bb0Skrw display(fp, &newlab, 0, 1); 4436fe57b42Smillert (void)fclose(fp); 4446fe57b42Smillert } 4456fe57b42Smillert break; 4466fe57b42Smillert 4474f3bbbf0Skrw case 'U': 44893160b9bSkrw /* 449430e1380Skrw * If we allow 'U' repeatedly, information would be 450430e1380Skrw * lost. This way multiple 'U's followed by 'u' will 451430e1380Skrw * undo the 'U's. 45293160b9bSkrw */ 453d6d80bb0Skrw if (memcmp(&newlab, &origlabel, sizeof(newlab)) || 45493160b9bSkrw !mpequal(mountpoints, origmountpoints)) { 455d6d80bb0Skrw tmplabel = newlab; 456d6d80bb0Skrw newlab = origlabel; 4574f3bbbf0Skrw lastlabel = tmplabel; 4584f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 4594f3bbbf0Skrw mpcopy(mountpoints, origmountpoints); 4604f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4614f3bbbf0Skrw } 46293160b9bSkrw puts("Original label and mount points restored."); 4634f3bbbf0Skrw break; 4644f3bbbf0Skrw 4656fe57b42Smillert case 'u': 466d6d80bb0Skrw tmplabel = newlab; 467d6d80bb0Skrw newlab = lastlabel; 4686fe57b42Smillert lastlabel = tmplabel; 4694f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 470bd6726faSmillert mpcopy(mountpoints, omountpoints); 4714f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4726fe57b42Smillert puts("Last change undone."); 4736fe57b42Smillert break; 4746fe57b42Smillert 475040947cfSmillert case 'w': 476bd6726faSmillert if (donothing) { 477040947cfSmillert puts("In no change mode, not writing label."); 478bd6726faSmillert break; 479bd6726faSmillert } 48093160b9bSkrw 48141f684b9Skrw /* Write label to disk. */ 48240bba581Skrw if (writelabel(f, &newlab) != 0) 483040947cfSmillert warnx("unable to write label"); 48471bba4ecSkrw else { 485ab20a3eaSkrw dflag = aflag = 0; 486d6d80bb0Skrw newlab = lab; /* lab now has UID info */ 48771bba4ecSkrw } 488040947cfSmillert break; 489040947cfSmillert 4902d8451b0Smillert case 'X': 4912d8451b0Smillert expert = !expert; 4922d8451b0Smillert printf("%s expert mode\n", expert ? "Entering" : 4932d8451b0Smillert "Exiting"); 4942d8451b0Smillert break; 4952d8451b0Smillert 4966fe57b42Smillert case 'x': 4977e28fb0fSderaadt goto done; 4986fe57b42Smillert break; 4996fe57b42Smillert 5009afbe9eeSmillert case 'z': 501d6d80bb0Skrw zero_partitions(&newlab); 5026fe57b42Smillert break; 5036fe57b42Smillert 5049afbe9eeSmillert case '\n': 5056fe57b42Smillert break; 5066fe57b42Smillert 5076fe57b42Smillert default: 5086fe57b42Smillert printf("Unknown option: %c ('?' for help)\n", *cmd); 5096fe57b42Smillert break; 5106fe57b42Smillert } 5114f3bbbf0Skrw 5124f3bbbf0Skrw /* 5134f3bbbf0Skrw * If no changes were made to label or mountpoints, then 5144f3bbbf0Skrw * restore undo info. 5154f3bbbf0Skrw */ 516d6d80bb0Skrw if (memcmp(&newlab, &lastlabel, sizeof(newlab)) == 0 && 51793160b9bSkrw (mpequal(mountpoints, omountpoints))) { 5184f3bbbf0Skrw lastlabel = tmplabel; 5194f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 5204f3bbbf0Skrw } 5216fe57b42Smillert } 5227e28fb0fSderaadt done: 523408ab9bcSkrw mpfree(omountpoints); 524408ab9bcSkrw mpfree(origmountpoints); 525408ab9bcSkrw mpfree(tmpmountpoints); 5267e28fb0fSderaadt free(disk_geop); 5277e28fb0fSderaadt return (error); 5286fe57b42Smillert } 5296fe57b42Smillert 5306fe57b42Smillert /* 531557f712bSkrw * Allocate all disk space according to standard recommendations for a 532557f712bSkrw * root disk. 533557f712bSkrw */ 534185664b4Sotto int 5358dde8bb6Sotto editor_allocspace(struct disklabel *lp_org) 536557f712bSkrw { 5378dde8bb6Sotto struct disklabel *lp, label; 5388dde8bb6Sotto struct space_allocation *alloc; 53934ae4198Skrw struct space_allocation *ap; 540557f712bSkrw struct partition *pp; 54134ae4198Skrw struct diskchunk *chunks; 542859c13c7Skrw u_int64_t chunkstart, chunkstop, chunksize; 54359c4e6f1Skrw u_int64_t cylsecs, secs, xtrasecs; 54434ae4198Skrw char **partmp; 5453c723e85Skrw int i, j, lastalloc, index, partno, freeparts; 546e384f6efSderaadt extern int64_t physmem; 5478dde8bb6Sotto 54834ae4198Skrw /* How big is the OpenBSD portion of the disk? */ 5498dde8bb6Sotto find_bounds(lp_org); 550557f712bSkrw 551fc6e9c48Sotto overlap = 0; 5523c723e85Skrw freeparts = 0; 553fc6e9c48Sotto for (i = 0; i < MAXPARTITIONS; i++) { 554eafadddfSkrw u_int64_t psz, pstart, pend; 555fc6e9c48Sotto 556fc6e9c48Sotto pp = &lp_org->d_partitions[i]; 557fc6e9c48Sotto psz = DL_GETPSIZE(pp); 5583c723e85Skrw if (psz == 0) 5593c723e85Skrw freeparts++; 560fc6e9c48Sotto pstart = DL_GETPOFFSET(pp); 561fc6e9c48Sotto pend = pstart + psz; 562fc6e9c48Sotto if (i != RAW_PART && psz != 0 && 563fc6e9c48Sotto ((pstart >= starting_sector && pstart <= ending_sector) || 564fc6e9c48Sotto (pend > starting_sector && pend < ending_sector))) { 565fc6e9c48Sotto overlap = 1; 566fc6e9c48Sotto break; 567fc6e9c48Sotto } 568fc6e9c48Sotto } 569fc6e9c48Sotto 5708dde8bb6Sotto cylsecs = lp_org->d_secpercyl; 571598ec681Skrw alloc = NULL; 572598ec681Skrw index = -1; 5738dde8bb6Sotto again: 574598ec681Skrw free(alloc); 575a9e37dfeSkrw alloc = NULL; 576598ec681Skrw index++; 577598ec681Skrw if (index >= alloc_table_nitems) 578598ec681Skrw return 1; 5798dde8bb6Sotto lp = &label; 5803d98fc8cSkrw for (i=0; i<MAXPARTITIONS; i++) { 5813d98fc8cSkrw free(mountpoints[i]); 5823d98fc8cSkrw mountpoints[i] = NULL; 5833d98fc8cSkrw } 5848dde8bb6Sotto memcpy(lp, lp_org, sizeof(struct disklabel)); 5850a7398ceSderaadt lp->d_npartitions = MAXPARTITIONS; 5868dde8bb6Sotto lastalloc = alloc_table[index].sz; 5873c723e85Skrw if (lastalloc > freeparts) 5883c723e85Skrw goto again; 589ab30cb2fSdoug alloc = reallocarray(NULL, lastalloc, sizeof(struct space_allocation)); 5908dde8bb6Sotto if (alloc == NULL) 5918dde8bb6Sotto errx(4, "out of memory"); 5928dde8bb6Sotto memcpy(alloc, alloc_table[index].table, 5938dde8bb6Sotto lastalloc * sizeof(struct space_allocation)); 5948dde8bb6Sotto 5958dde8bb6Sotto /* bump max swap based on phys mem, little physmem gets 2x swap */ 596a2c1f847Shenning if (index == 0 && alloc_table == alloc_table_default) { 597e384f6efSderaadt if (physmem / DEV_BSIZE < MEG(256)) 598e0befca8Skrw alloc[1].minsz = alloc[1].maxsz = 2 * (physmem / 599e0befca8Skrw DEV_BSIZE); 6008dde8bb6Sotto else 601e384f6efSderaadt alloc[1].maxsz += (physmem / DEV_BSIZE); 6028dde8bb6Sotto /* bump max /var to make room for 2 crash dumps */ 603e384f6efSderaadt alloc[3].maxsz += 2 * (physmem / DEV_BSIZE); 6048dde8bb6Sotto } 6058dde8bb6Sotto 60659c4e6f1Skrw xtrasecs = editor_countfree(lp); 607557f712bSkrw 60834ae4198Skrw for (i = 0; i < lastalloc; i++) { 6095f3e1104Skrw alloc[i].minsz = DL_BLKTOSEC(lp, alloc[i].minsz); 6105f3e1104Skrw alloc[i].maxsz = DL_BLKTOSEC(lp, alloc[i].maxsz); 6114f05c2ddSkrw if (xtrasecs >= alloc[i].minsz) 61234ae4198Skrw xtrasecs -= alloc[i].minsz; 6134f05c2ddSkrw else { 6144f05c2ddSkrw /* It did not work out, try next strategy */ 6154f05c2ddSkrw goto again; 6164f05c2ddSkrw } 617557f712bSkrw } 618557f712bSkrw 61934ae4198Skrw for (i = 0; i < lastalloc; i++) { 62034ae4198Skrw /* Find next available partition. */ 62134ae4198Skrw for (j = 0; j < MAXPARTITIONS; j++) 62234ae4198Skrw if (DL_GETPSIZE(&lp->d_partitions[j]) == 0) 62334ae4198Skrw break; 624a243d7b5Skrw if (j == MAXPARTITIONS) { 625a243d7b5Skrw /* It did not work out, try next strategy */ 626a243d7b5Skrw goto again; 627a243d7b5Skrw } 628a49bdda8Skrw partno = j; 62934ae4198Skrw pp = &lp->d_partitions[j]; 63034ae4198Skrw partmp = &mountpoints[j]; 63134ae4198Skrw ap = &alloc[i]; 632557f712bSkrw 63334ae4198Skrw /* Find largest chunk of free space. */ 63434ae4198Skrw chunks = free_chunks(lp); 63534ae4198Skrw chunksize = 0; 636859c13c7Skrw for (j = 0; chunks[j].start != 0 || chunks[j].stop != 0; j++) { 63734ae4198Skrw if ((chunks[j].stop - chunks[j].start) > chunksize) { 63834ae4198Skrw chunkstart = chunks[j].start; 639859c13c7Skrw chunkstop = chunks[j].stop; 64034ae4198Skrw #ifdef SUN_CYLCHECK 64134ae4198Skrw if (lp->d_flags & D_VENDOR) { 642859c13c7Skrw /* Align to cylinder boundaries. */ 643859c13c7Skrw chunkstart = ((chunkstart + cylsecs - 1) 644859c13c7Skrw / cylsecs) * cylsecs; 645859c13c7Skrw chunkstop = (chunkstop / cylsecs) * 6466ab0bb66Skrw cylsecs; 64734ae4198Skrw } 64834ae4198Skrw #endif 649859c13c7Skrw chunksize = chunkstop - chunkstart; 650859c13c7Skrw } 651859c13c7Skrw } 652859c13c7Skrw 65359c4e6f1Skrw /* Figure out the size of the partition. */ 65459c4e6f1Skrw if (i == lastalloc - 1) { 65559c4e6f1Skrw if (chunksize > ap->maxsz) 65659c4e6f1Skrw secs = ap->maxsz; 65759c4e6f1Skrw else 65834ae4198Skrw secs = chunksize; 65959c4e6f1Skrw } else { 66059c4e6f1Skrw secs = ap->minsz; 66159c4e6f1Skrw if (xtrasecs > 0) 66259c4e6f1Skrw secs += (xtrasecs / 100) * ap->rate; 66359c4e6f1Skrw if (secs > ap->maxsz) 66459c4e6f1Skrw secs = ap->maxsz; 66534ae4198Skrw } 66659c4e6f1Skrw #ifdef SUN_CYLCHECK 66759c4e6f1Skrw if (lp->d_flags & D_VENDOR) { 66859c4e6f1Skrw secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; 66959c4e6f1Skrw while (secs > chunksize) 67059c4e6f1Skrw secs -= cylsecs; 67159c4e6f1Skrw } 67259c4e6f1Skrw #endif 67359c4e6f1Skrw 67459c4e6f1Skrw /* See if partition can fit into chunk. */ 67559c4e6f1Skrw if (secs > chunksize) 67659c4e6f1Skrw secs = chunksize; 67734ae4198Skrw if (secs < ap->minsz) { 6788dde8bb6Sotto /* It did not work out, try next strategy */ 6798dde8bb6Sotto goto again; 680557f712bSkrw } 68134ae4198Skrw 68234ae4198Skrw /* Everything seems ok so configure the partition. */ 6835f3e1104Skrw DL_SETPSIZE(pp, secs); 68434ae4198Skrw DL_SETPOFFSET(pp, chunkstart); 68534ae4198Skrw if (ap->mp[0] != '/') 68634ae4198Skrw pp->p_fstype = FS_SWAP; 68734ae4198Skrw else { 68834ae4198Skrw pp->p_fstype = FS_BSDFFS; 689d68164a2Skrw pp->p_fragblock = 0; 690d68164a2Skrw if (get_fsize(lp, partno) == 1 || 691d68164a2Skrw get_bsize(lp, partno) == 1 || 692d68164a2Skrw get_cpg(lp, partno) == 1) { 693d68164a2Skrw free(alloc); 694d68164a2Skrw return 1; 695d68164a2Skrw } 69634ae4198Skrw free(*partmp); 69734ae4198Skrw if ((*partmp = strdup(ap->mp)) == NULL) 698557f712bSkrw errx(4, "out of memory"); 699557f712bSkrw } 700557f712bSkrw } 701557f712bSkrw 7028dde8bb6Sotto free(alloc); 7038dde8bb6Sotto memcpy(lp_org, lp, sizeof(struct disklabel)); 704185664b4Sotto return 0; 705557f712bSkrw } 706557f712bSkrw 707557f712bSkrw /* 7086aaa4aabSotto * Resize a partition, moving all subsequent partitions 7096aaa4aabSotto */ 7106aaa4aabSotto void 7116aaa4aabSotto editor_resize(struct disklabel *lp, char *p) 7126aaa4aabSotto { 7136aaa4aabSotto struct disklabel label; 7146aaa4aabSotto struct partition *pp, *prev; 715914b3475Skrw u_int64_t ui, sz, off; 71677370cdaSkrw int partno, i, flags, shrunk; 7176aaa4aabSotto 7186aaa4aabSotto label = *lp; 7196aaa4aabSotto 7206aaa4aabSotto /* Change which partition? */ 721ac30837aSkrw if (p == NULL) 7226aaa4aabSotto p = getstring("partition to resize", 7236aaa4aabSotto "The letter of the partition to name, a - p.", NULL); 724ac30837aSkrw if (p == NULL) 7256aaa4aabSotto return; 7266aaa4aabSotto partno = p[0] - 'a'; 7276aaa4aabSotto if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 7286aaa4aabSotto fprintf(stderr, "Partition must be between 'a' and '%c' " 7296aaa4aabSotto "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 7306aaa4aabSotto return; 7316aaa4aabSotto } 7326aaa4aabSotto 7336aaa4aabSotto pp = &label.d_partitions[partno]; 734fc6e9c48Sotto sz = DL_GETPSIZE(pp); 735fc6e9c48Sotto if (sz == 0) { 736fc6e9c48Sotto fputs("No such partition\n", stderr); 737fc6e9c48Sotto return; 738fc6e9c48Sotto } 739fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) { 740fc6e9c48Sotto fputs("Cannot resize spoofed partition\n", stderr); 741fc6e9c48Sotto return; 742fc6e9c48Sotto } 74340b226e8Skrw flags = DO_CONVERSIONS; 744914b3475Skrw ui = getuint64(lp, "[+|-]new size (with unit)", 745e0befca8Skrw "new size or amount to grow (+) or shrink (-) partition including " 74640b226e8Skrw "unit", sz, sz + editor_countfree(lp), &flags); 7476aaa4aabSotto 748914b3475Skrw if (ui == CMD_ABORTED) 7496aaa4aabSotto return; 750914b3475Skrw else if (ui == CMD_BADVALUE) 7519f0bdc2aSkrw return; 752914b3475Skrw else if (ui == 0) { 7531298f28aSkrw fputs("The size must be > 0 sectors\n", stderr); 7541298f28aSkrw return; 7556aaa4aabSotto } 7566aaa4aabSotto 7576aaa4aabSotto #ifdef SUN_CYLCHECK 7581298f28aSkrw if (lp->d_secpercyl & D_VENDOR) { 7591298f28aSkrw u_int64_t cylsecs; 7606aaa4aabSotto cylsecs = lp->d_secpercyl; 761ce0ca44bSkrw ui = ((ui + cylsecs - 1) / cylsecs) * cylsecs; 7621298f28aSkrw } 7636aaa4aabSotto #endif 764914b3475Skrw if (DL_GETPOFFSET(pp) + ui > ending_sector) { 7656aaa4aabSotto fputs("Amount too big\n", stderr); 7666aaa4aabSotto return; 7676aaa4aabSotto } 7686aaa4aabSotto 769914b3475Skrw DL_SETPSIZE(pp, ui); 770d68164a2Skrw pp->p_fragblock = 0; 771d68164a2Skrw if (get_fsize(&label, partno) == 1 || 772d68164a2Skrw get_bsize(&label, partno) == 1 || 773d68164a2Skrw get_cpg(&label, partno) == 1) 774d68164a2Skrw return; 7756aaa4aabSotto 7766aaa4aabSotto /* 7776aaa4aabSotto * Pack partitions above the resized partition, leaving unused 778c7e00dc5Skrw * partitions alone. 7796aaa4aabSotto */ 78077370cdaSkrw shrunk = -1; 7816aaa4aabSotto prev = pp; 7826aaa4aabSotto for (i = partno + 1; i < MAXPARTITIONS; i++) { 7836aaa4aabSotto if (i == RAW_PART) 7846aaa4aabSotto continue; 785fc6e9c48Sotto pp = &label.d_partitions[i]; 786fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) 787fc6e9c48Sotto continue; 788fc6e9c48Sotto sz = DL_GETPSIZE(pp); 7896aaa4aabSotto if (sz == 0) 7906aaa4aabSotto continue; 7916aaa4aabSotto 7926aaa4aabSotto off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev); 7936aaa4aabSotto 7946aaa4aabSotto if (off < ending_sector) { 7956aaa4aabSotto DL_SETPOFFSET(pp, off); 7966aaa4aabSotto if (off + DL_GETPSIZE(pp) > ending_sector) { 7976aaa4aabSotto DL_SETPSIZE(pp, ending_sector - off); 798d68164a2Skrw pp->p_fragblock = 0; 799d68164a2Skrw if (get_fsize(&label, partno) == 1 || 800d68164a2Skrw get_bsize(&label, partno) == 1 || 801d68164a2Skrw get_cpg(&label, partno) == 1) 802d68164a2Skrw return; 80377370cdaSkrw shrunk = i; 8046aaa4aabSotto } 8056aaa4aabSotto } else { 80677370cdaSkrw fputs("Amount too big\n", stderr); 8076aaa4aabSotto return; 8086aaa4aabSotto } 8096aaa4aabSotto prev = pp; 8106aaa4aabSotto } 81177370cdaSkrw 81277370cdaSkrw if (shrunk != -1) 81377370cdaSkrw fprintf(stderr, "Partition %c shrunk to %llu sectors to make " 81477370cdaSkrw "room\n", 'a' + shrunk, 81577370cdaSkrw DL_GETPSIZE(&label.d_partitions[shrunk])); 8166aaa4aabSotto *lp = label; 8176aaa4aabSotto } 8186aaa4aabSotto 8196aaa4aabSotto /* 8206fe57b42Smillert * Add a new partition. 8216fe57b42Smillert */ 8226fe57b42Smillert void 82334ae4198Skrw editor_add(struct disklabel *lp, char *p) 8246fe57b42Smillert { 82596a888c6Smillert struct partition *pp; 82696a888c6Smillert struct diskchunk *chunks; 8275caa08b2Skrw char buf[2]; 828a3ad4147Skrw int i, partno; 829f8ab7229Schl u_int64_t freesectors, new_offset, new_size; 8309fdcb4d6Skrw 8319fdcb4d6Skrw freesectors = editor_countfree(lp); 8326fe57b42Smillert 8336fe57b42Smillert /* XXX - prompt user to steal space from another partition instead */ 834fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 8359fdcb4d6Skrw if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) { 836fc1a4cc6Sderaadt fputs("No space left, you need to shrink a partition " 837fc1a4cc6Sderaadt "(need at least one full cylinder)\n", 838fc1a4cc6Sderaadt stderr); 839fc1a4cc6Sderaadt return; 840fc1a4cc6Sderaadt } 8418390cf28Smillert #endif 8429fdcb4d6Skrw if (freesectors == 0) { 8436fe57b42Smillert fputs("No space left, you need to shrink a partition\n", 8446fe57b42Smillert stderr); 8456fe57b42Smillert return; 8466fe57b42Smillert } 8476fe57b42Smillert 8485caa08b2Skrw if (p == NULL) { 8495caa08b2Skrw /* 8505caa08b2Skrw * Use the first unused partition that is not 'c' as the 8515caa08b2Skrw * default partition in the prompt string. 8525caa08b2Skrw */ 8535caa08b2Skrw pp = &lp->d_partitions[0]; 8545caa08b2Skrw buf[0] = buf[1] = '\0'; 8555caa08b2Skrw for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) { 8565caa08b2Skrw if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) { 8575caa08b2Skrw buf[0] = partno + 'a'; 8585caa08b2Skrw p = &buf[0]; 8596fe57b42Smillert break; 8606fe57b42Smillert } 8615caa08b2Skrw } 862c33fcabaSmillert p = getstring("partition", 8636fe57b42Smillert "The letter of the new partition, a - p.", p); 8646fe57b42Smillert } 865ac30837aSkrw if (p == NULL) 8665caa08b2Skrw return; 8675caa08b2Skrw partno = p[0] - 'a'; 8685caa08b2Skrw if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) { 8695caa08b2Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 8705caa08b2Skrw "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1); 8715caa08b2Skrw return; 8725caa08b2Skrw } 8735caa08b2Skrw pp = &lp->d_partitions[partno]; 8745caa08b2Skrw 8755caa08b2Skrw if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) { 8765caa08b2Skrw fprintf(stderr, "Partition '%c' exists. Delete it first.\n", 8775caa08b2Skrw p[0]); 8785caa08b2Skrw return; 8796fe57b42Smillert } 88096a888c6Smillert 881caf41f96Skrw /* 882caf41f96Skrw * Increase d_npartitions if necessary. Ensure all new partitions are 883855d4e83Ssobrado * zero'ed to avoid inadvertent overlaps. 884caf41f96Skrw */ 885caf41f96Skrw for(; lp->d_npartitions <= partno; lp->d_npartitions++) 886caf41f96Skrw memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp)); 88796a888c6Smillert 88889f4601dSkrw /* Make sure selected partition is zero'd too. */ 88989f4601dSkrw memset(pp, 0, sizeof(*pp)); 89015c15d8aSkrw chunks = free_chunks(lp); 89115c15d8aSkrw 89215c15d8aSkrw /* 89315c15d8aSkrw * Since we know there's free space, there must be at least one 89415c15d8aSkrw * chunk. So find the largest chunk and assume we want to add the 89515c15d8aSkrw * partition in that free space. 89615c15d8aSkrw */ 89715c15d8aSkrw new_size = new_offset = 0; 89815c15d8aSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 89915c15d8aSkrw if (chunks[i].stop - chunks[i].start > new_size) { 90015c15d8aSkrw new_size = chunks[i].stop - chunks[i].start; 90115c15d8aSkrw new_offset = chunks[i].start; 90215c15d8aSkrw } 90315c15d8aSkrw } 9041e0ad43cSotto DL_SETPSIZE(pp, new_size); 9051e0ad43cSotto DL_SETPOFFSET(pp, new_offset); 90696a888c6Smillert pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS; 907c88f83bdSotto 908c88f83bdSotto if (get_offset(lp, partno) == 0 && 909a3ad4147Skrw get_size(lp, partno) == 0 && 910a3ad4147Skrw get_fstype(lp, partno) == 0 && 91134ae4198Skrw get_mp(lp, partno) == 0 && 912a4c87e64Skrw get_fsize(lp, partno) == 0 && 913a6262855Skrw get_bsize(lp, partno) == 0 && 914a6262855Skrw get_cpg(lp, partno) == 0) 91596a888c6Smillert return; 916a3ad4147Skrw 917a4c87e64Skrw /* Bailed out at some point, so effectively delete the partition. */ 918da2bd3f5Skrw memset(pp, 0, sizeof(*pp)); 9196fe57b42Smillert } 9206fe57b42Smillert 9216fe57b42Smillert /* 922bd6726faSmillert * Set the mountpoint of an existing partition ('name'). 923bd6726faSmillert */ 924bd6726faSmillert void 92534ae4198Skrw editor_name(struct disklabel *lp, char *p) 926bd6726faSmillert { 927bd6726faSmillert struct partition *pp; 928bd6726faSmillert int partno; 929bd6726faSmillert 930bd6726faSmillert /* Change which partition? */ 931ac30837aSkrw if (p == NULL) 932c33fcabaSmillert p = getstring("partition to name", 933bd6726faSmillert "The letter of the partition to name, a - p.", NULL); 934ac30837aSkrw if (p == NULL) 935bd6726faSmillert return; 936bd6726faSmillert partno = p[0] - 'a'; 9376c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9386c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9396c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 940bd6726faSmillert return; 94166df1f0cSkrw } 94266df1f0cSkrw pp = &lp->d_partitions[partno]; 94366df1f0cSkrw 94466df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 94566df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 946bd6726faSmillert return; 947bd6726faSmillert } 948bd6726faSmillert 94934ae4198Skrw get_mp(lp, partno); 950bd6726faSmillert } 951bd6726faSmillert 952bd6726faSmillert /* 9536fe57b42Smillert * Change an existing partition. 9546fe57b42Smillert */ 9556fe57b42Smillert void 95634ae4198Skrw editor_modify(struct disklabel *lp, char *p) 9576fe57b42Smillert { 95840b226e8Skrw struct partition opp, *pp; 959f8ab7229Schl int partno; 9606fe57b42Smillert 9616fe57b42Smillert /* Change which partition? */ 962ac30837aSkrw if (p == NULL) 963c33fcabaSmillert p = getstring("partition to modify", 9646fe57b42Smillert "The letter of the partition to modify, a - p.", NULL); 965ac30837aSkrw if (p == NULL) 96696a888c6Smillert return; 9676fe57b42Smillert partno = p[0] - 'a'; 9686c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9696c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9706c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 9716fe57b42Smillert return; 97266df1f0cSkrw } 97366df1f0cSkrw pp = &lp->d_partitions[partno]; 97466df1f0cSkrw 97566df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 97666df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 9776fe57b42Smillert return; 9786fe57b42Smillert } 9796fe57b42Smillert 98040b226e8Skrw opp = *pp; 98166df1f0cSkrw 982a4c87e64Skrw if (get_offset(lp, partno) == 0 && 983a4c87e64Skrw get_size(lp, partno) == 0 && 984a4c87e64Skrw get_fstype(lp, partno) == 0 && 98534ae4198Skrw get_mp(lp, partno) == 0 && 986a4c87e64Skrw get_fsize(lp, partno) == 0 && 987a95dd767Sotto get_bsize(lp, partno) == 0 && 988a95dd767Sotto get_cpg(lp, partno) == 0) 98996a888c6Smillert return; 9906fe57b42Smillert 991a4c87e64Skrw /* Bailed out at some point, so undo any changes. */ 99240b226e8Skrw *pp = opp; 9936fe57b42Smillert } 9946fe57b42Smillert 9956fe57b42Smillert /* 9966fe57b42Smillert * Delete an existing partition. 9976fe57b42Smillert */ 9986fe57b42Smillert void 99934ae4198Skrw editor_delete(struct disklabel *lp, char *p) 10006fe57b42Smillert { 100166df1f0cSkrw struct partition *pp; 1002135c90d1Skrw int partno; 10036fe57b42Smillert 1004ac30837aSkrw if (p == NULL) 1005c33fcabaSmillert p = getstring("partition to delete", 1006945ae268Smillert "The letter of the partition to delete, a - p, or '*'.", 1007945ae268Smillert NULL); 1008ac30837aSkrw if (p == NULL) 100996a888c6Smillert return; 1010945ae268Smillert if (p[0] == '*') { 10119fdcb4d6Skrw zero_partitions(lp); 1012945ae268Smillert return; 1013945ae268Smillert } 1014135c90d1Skrw partno = p[0] - 'a'; 1015135c90d1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 10166c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 10176c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 101833262abfSmiod return; 101966df1f0cSkrw } 1020135c90d1Skrw pp = &lp->d_partitions[partno]; 102166df1f0cSkrw 102266df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 102366df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 102433262abfSmiod return; 102566df1f0cSkrw } 102666df1f0cSkrw 10276fe57b42Smillert /* Really delete it (as opposed to just setting to "unused") */ 1028135c90d1Skrw memset(pp, 0, sizeof(*pp)); 102934ae4198Skrw free(mountpoints[partno]); 103034ae4198Skrw mountpoints[partno] = NULL; 10316fe57b42Smillert } 10326fe57b42Smillert 10336fe57b42Smillert /* 10346fe57b42Smillert * Change the size of an existing partition. 10356fe57b42Smillert */ 10366fe57b42Smillert void 10379fdcb4d6Skrw editor_change(struct disklabel *lp, char *p) 10386fe57b42Smillert { 10394b9a3bdaSmillert struct partition *pp; 104066df1f0cSkrw int partno; 10416fe57b42Smillert 1042ac30837aSkrw if (p == NULL) 1043c33fcabaSmillert p = getstring("partition to change size", 10446fe57b42Smillert "The letter of the partition to change size, a - p.", NULL); 1045ac30837aSkrw if (p == NULL) 104696a888c6Smillert return; 10476fe57b42Smillert partno = p[0] - 'a'; 10486c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 10496c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 10506c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 10516fe57b42Smillert return; 10526fe57b42Smillert } 10534b9a3bdaSmillert pp = &lp->d_partitions[partno]; 10546fe57b42Smillert 105566df1f0cSkrw if (DL_GETPSIZE(pp) == 0) { 105666df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 105766df1f0cSkrw return; 105866df1f0cSkrw } 105966df1f0cSkrw 106014192793Skrw printf("Partition %c is currently %llu sectors in size, and can have " 106114192793Skrw "a maximum\nsize of %llu sectors.\n", 106214192793Skrw p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno)); 10637da73705Skrw 106459ccf790Skrw /* Get new size */ 10659fdcb4d6Skrw get_size(lp, partno); 10666fe57b42Smillert } 10676fe57b42Smillert 10686fe57b42Smillert /* 10696fe57b42Smillert * Sort the partitions based on starting offset. 10706fe57b42Smillert * This assumes there can be no overlap. 10716fe57b42Smillert */ 10726fe57b42Smillert int 10738809fabbSderaadt partition_cmp(const void *e1, const void *e2) 10746fe57b42Smillert { 10756fe57b42Smillert struct partition *p1 = *(struct partition **)e1; 10766fe57b42Smillert struct partition *p2 = *(struct partition **)e2; 10771e0ad43cSotto u_int64_t o1 = DL_GETPOFFSET(p1); 10781e0ad43cSotto u_int64_t o2 = DL_GETPOFFSET(p2); 10796fe57b42Smillert 10801e0ad43cSotto if (o1 < o2) 1081651d5bd9Sotto return -1; 10821e0ad43cSotto else if (o1 > o2) 1083651d5bd9Sotto return 1; 1084651d5bd9Sotto else 1085651d5bd9Sotto return 0; 10866fe57b42Smillert } 10876fe57b42Smillert 10886fe57b42Smillert char * 1089b228e876Smiod getstring(const char *prompt, const char *helpstring, const char *oval) 10906fe57b42Smillert { 10916fe57b42Smillert static char buf[BUFSIZ]; 10926fe57b42Smillert int n; 10936fe57b42Smillert 10946fe57b42Smillert buf[0] = '\0'; 10956fe57b42Smillert do { 10966fe57b42Smillert printf("%s: [%s] ", prompt, oval ? oval : ""); 10976e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1098260513deSmillert buf[0] = '\0'; 109996a888c6Smillert if (feof(stdin)) { 110024c6582eSmillert clearerr(stdin); 110196a888c6Smillert putchar('\n'); 1102ac30837aSkrw fputs("Command aborted\n", stderr); 110396a888c6Smillert return (NULL); 110496a888c6Smillert } 11056e0becc5Smillert } 11066fe57b42Smillert n = strlen(buf); 11076fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 11086fe57b42Smillert buf[--n] = '\0'; 11096fe57b42Smillert if (buf[0] == '?') 11106fe57b42Smillert puts(helpstring); 11114fb6ab7cSmillert else if (oval != NULL && buf[0] == '\0') 11124fb6ab7cSmillert strlcpy(buf, oval, sizeof(buf)); 11136fe57b42Smillert } while (buf[0] == '?'); 11146fe57b42Smillert 11156fe57b42Smillert return (&buf[0]); 11166fe57b42Smillert } 11176fe57b42Smillert 11186fe57b42Smillert /* 1119aa3970cdSkrw * Returns 1120aa3970cdSkrw * 0 .. CMD_ABORTED - 1 ==> valid value 1121aa3970cdSkrw * CMD_BADVALUE ==> invalid value 1122aa3970cdSkrw * CMD_ABORTED ==> ^D on input 11236fe57b42Smillert */ 11241e0ad43cSotto u_int64_t 11250db7769aSkrw getnumber(char *prompt, char *helpstring, u_int32_t oval, u_int32_t maxval) 11260db7769aSkrw { 11270db7769aSkrw char buf[BUFSIZ], *p; 11280db7769aSkrw int rslt; 11290db7769aSkrw long long rval; 11300db7769aSkrw const char *errstr; 11310db7769aSkrw 11320db7769aSkrw rslt = snprintf(buf, sizeof(buf), "%u", oval); 11330db7769aSkrw if (rslt == -1 || (unsigned int)rslt >= sizeof(buf)) 11340db7769aSkrw return (CMD_BADVALUE); 11350db7769aSkrw 11360db7769aSkrw p = getstring(prompt, helpstring, buf); 11370db7769aSkrw if (p == NULL) 11380db7769aSkrw return (CMD_ABORTED); 11390db7769aSkrw if (strlen(p) == 0) 11400db7769aSkrw return (oval); 11410db7769aSkrw 11420db7769aSkrw rval = strtonum(p, 0, maxval, &errstr); 11430db7769aSkrw if (errstr != NULL) { 11440db7769aSkrw printf("%s must be between 0 and %u\n", prompt, maxval); 11450db7769aSkrw return (CMD_BADVALUE); 11460db7769aSkrw } 11470db7769aSkrw 11480db7769aSkrw return (rval); 11490db7769aSkrw } 11500db7769aSkrw 11510db7769aSkrw /* 11520db7769aSkrw * Returns 11530db7769aSkrw * 0 .. CMD_ABORTED - 1 ==> valid value 11540db7769aSkrw * CMD_BADVALUE ==> invalid value 11550db7769aSkrw * CMD_ABORTED ==> ^D on input 11560db7769aSkrw */ 11570db7769aSkrw u_int64_t 1158117239d3Skrw getuint64(struct disklabel *lp, char *prompt, char *helpstring, 115940b226e8Skrw u_int64_t oval, u_int64_t maxval, int *flags) 11606fe57b42Smillert { 11611fec2892Skrw char buf[21], *p, operator = '\0'; 11621fec2892Skrw char *unit = NULL; 11631e0ad43cSotto u_int64_t rval = oval; 11641fec2892Skrw double d; 11659a4afaafSkrw int rslt; 11666fe57b42Smillert 11679a4afaafSkrw rslt = snprintf(buf, sizeof(buf), "%llu", oval); 11689a4afaafSkrw if (rslt == -1 || (unsigned int)rslt >= sizeof(buf)) 11699a4afaafSkrw goto invalid; 11709a4afaafSkrw 11719a4afaafSkrw p = getstring(prompt, helpstring, buf); 11729a4afaafSkrw if (p == NULL) 1173aa3970cdSkrw return (CMD_ABORTED); 11741fec2892Skrw else if (p[0] == '\0') 11751fec2892Skrw rval = oval; 11761fec2892Skrw else if (p[0] == '*' && p[1] == '\0') 11776fe57b42Smillert rval = maxval; 11781fec2892Skrw else { 11791fec2892Skrw if (*p == '+' || *p == '-') 11801fec2892Skrw operator = *p++; 11811fec2892Skrw if (parse_sizespec(p, &d, &unit) == -1) 11821fec2892Skrw goto invalid; 11831fec2892Skrw if (unit == NULL) 11841fec2892Skrw rval = d; 11851fec2892Skrw else if (flags != NULL && (*flags & DO_CONVERSIONS) == 0) 11861fec2892Skrw goto invalid; 11871fec2892Skrw else { 11881fec2892Skrw switch (tolower((unsigned char)*unit)) { 11896fe57b42Smillert case 'b': 11901fec2892Skrw rval = d / lp->d_secsize; 11916fe57b42Smillert break; 11921fec2892Skrw case 'c': 11931fec2892Skrw rval = d * lp->d_secpercyl; 11941a51a1eeSmillert break; 119514cc915fSmillert case '%': 11961fec2892Skrw rval = DL_GETDSIZE(lp) * (d / 100.0); 119714cc915fSmillert break; 119814cc915fSmillert case '&': 11991fec2892Skrw rval = maxval * (d / 100.0); 12001fec2892Skrw break; 12011fec2892Skrw default: 12021fec2892Skrw if (apply_unit(d, *unit, &rval) == -1) 12031fec2892Skrw goto invalid; 12041fec2892Skrw rval = DL_BLKTOSEC(lp, rval); 120514cc915fSmillert break; 12066fe57b42Smillert } 120796a888c6Smillert } 12086fe57b42Smillert 1209e15dcdb4Skrw /* Range check then apply [+-] operator */ 1210e15dcdb4Skrw if (operator == '+') { 1211aa3970cdSkrw if (CMD_ABORTED - oval > rval) 12126fe57b42Smillert rval += oval; 1213e15dcdb4Skrw else { 1214ac30837aSkrw goto invalid; 1215e15dcdb4Skrw } 1216e15dcdb4Skrw } else if (operator == '-') { 1217e15dcdb4Skrw if (oval >= rval) 12186fe57b42Smillert rval = oval - rval; 1219e15dcdb4Skrw else { 1220ac30837aSkrw goto invalid; 1221e15dcdb4Skrw } 1222e15dcdb4Skrw } 12236fe57b42Smillert } 122440b226e8Skrw 122540b226e8Skrw if (flags != NULL) { 12261fec2892Skrw if (unit != NULL) 122740b226e8Skrw *flags |= DO_ROUNDING; 1228fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 122940b226e8Skrw if (lp->d_flags & D_VENDOR) 123040b226e8Skrw *flags |= DO_ROUNDING; 1231dbffb156Smillert #endif 12326fe57b42Smillert } 12336fe57b42Smillert return (rval); 1234ac30837aSkrw 1235ac30837aSkrw invalid: 1236ac30837aSkrw fputs("Invalid entry\n", stderr); 1237aa3970cdSkrw return (CMD_BADVALUE); 12386fe57b42Smillert } 12396fe57b42Smillert 12406fe57b42Smillert /* 12411f0f871dSkrw * Check for partition overlap in lp and prompt the user to resolve the overlap 12421f0f871dSkrw * if any is found. Returns 1 if unable to resolve, else 0. 12436fe57b42Smillert */ 12446fe57b42Smillert int 12451f0f871dSkrw has_overlap(struct disklabel *lp) 12466fe57b42Smillert { 12476fe57b42Smillert struct partition **spp; 12480f1cd5a2Skrw int i, p1, p2; 12490f1cd5a2Skrw char *line = NULL; 12500f1cd5a2Skrw size_t linesize = 0; 12510f1cd5a2Skrw ssize_t linelen; 12526fe57b42Smillert 12530f1cd5a2Skrw for (;;) { 12540fbd3c97Skrw spp = sort_partitions(lp); 12550f1cd5a2Skrw for (i = 0; spp[i+1] != NULL; i++) { 1256430e1380Skrw if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) > 12570f1cd5a2Skrw DL_GETPOFFSET(spp[i+1])) 12580f1cd5a2Skrw break; 1259616cd1c4Smillert } 12600f1cd5a2Skrw if (spp[i+1] == NULL) { 12610f1cd5a2Skrw free(line); 1262e6aa8bafSmillert return (0); 12636fe57b42Smillert } 12646fe57b42Smillert 12650f1cd5a2Skrw p1 = 'a' + (spp[i] - lp->d_partitions); 12660f1cd5a2Skrw p2 = 'a' + (spp[i+1] - lp->d_partitions); 12670f1cd5a2Skrw printf("\nError, partitions %c and %c overlap:\n", p1, p2); 12680f1cd5a2Skrw printf("# %16.16s %16.16s fstype [fsize bsize cpg]\n", 12690f1cd5a2Skrw "size", "offset"); 12700f1cd5a2Skrw display_partition(stdout, lp, p1 - 'a', 0); 12710f1cd5a2Skrw display_partition(stdout, lp, p2 - 'a', 0); 12720f1cd5a2Skrw 12730f1cd5a2Skrw for (;;) { 12740f1cd5a2Skrw printf("Disable which one? (%c %c) ", p1, p2); 12750f1cd5a2Skrw linelen = getline(&line, &linesize, stdin); 12760f1cd5a2Skrw if (linelen == -1) 12770f1cd5a2Skrw goto done; 12780f1cd5a2Skrw if (linelen == 2 && (line[0] == p1 || line[0] == p2)) 12790f1cd5a2Skrw break; 12800f1cd5a2Skrw } 12810f1cd5a2Skrw lp->d_partitions[line[0] - 'a'].p_fstype = FS_UNUSED; 12820f1cd5a2Skrw } 12830f1cd5a2Skrw 12840f1cd5a2Skrw done: 12850f1cd5a2Skrw putchar('\n'); 12860f1cd5a2Skrw free(line); 12870f1cd5a2Skrw return (1); 12880f1cd5a2Skrw } 12890f1cd5a2Skrw 12906fe57b42Smillert void 12919fdcb4d6Skrw edit_parms(struct disklabel *lp) 12926fe57b42Smillert { 12936fe57b42Smillert char *p; 12949fdcb4d6Skrw u_int64_t freesectors, ui; 129596a888c6Smillert struct disklabel oldlabel = *lp; 12966fe57b42Smillert 1297ea37abd3Sderaadt printf("Changing device parameters for %s:\n", specname); 12986fe57b42Smillert 12990f820bbbSmillert /* disk type */ 13000f820bbbSmillert for (;;) { 1301c33fcabaSmillert p = getstring("disk type", 130241282a2aSmillert "What kind of disk is this? Usually SCSI, ESDI, ST506, or " 130341282a2aSmillert "floppy (use ESDI for IDE).", dktypenames[lp->d_type]); 1304ac30837aSkrw if (p == NULL) 130596a888c6Smillert return; 130641282a2aSmillert if (strcasecmp(p, "IDE") == 0) 130741282a2aSmillert ui = DTYPE_ESDI; 130841282a2aSmillert else 1309c5229dceSkrw for (ui = 1; ui < DKMAXTYPES && strcasecmp(p, 1310c5229dceSkrw dktypenames[ui]); ui++) 13110f820bbbSmillert ; 13120f820bbbSmillert if (ui < DKMAXTYPES) { 13130f820bbbSmillert break; 13140f820bbbSmillert } else { 13150f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", p); 13160f820bbbSmillert fputs("Valid types are: ", stdout); 13170f820bbbSmillert for (ui = 1; ui < DKMAXTYPES; ui++) { 13180f820bbbSmillert printf("\"%s\"", dktypenames[ui]); 13190f820bbbSmillert if (ui < DKMAXTYPES - 1) 13200f820bbbSmillert fputs(", ", stdout); 13210f820bbbSmillert } 13220f820bbbSmillert putchar('\n'); 13230f820bbbSmillert } 13240f820bbbSmillert } 13250f820bbbSmillert lp->d_type = ui; 13260f820bbbSmillert 13276fe57b42Smillert /* pack/label id */ 1328c33fcabaSmillert p = getstring("label name", 13296fe57b42Smillert "15 char string that describes this label, usually the disk name.", 13306fe57b42Smillert lp->d_packname); 133196a888c6Smillert if (p == NULL) { 133296a888c6Smillert *lp = oldlabel; /* undo damage */ 133396a888c6Smillert return; 133496a888c6Smillert } 13354fb6ab7cSmillert strncpy(lp->d_packname, p, sizeof(lp->d_packname)); /* checked */ 13366fe57b42Smillert 13376fe57b42Smillert /* sectors/track */ 13386fe57b42Smillert for (;;) { 13390db7769aSkrw ui = getnumber("sectors/track", 1340cfd24250Skrw "The Number of sectors per track.", lp->d_nsectors, 13410db7769aSkrw UINT32_MAX); 1342aa3970cdSkrw if (ui == CMD_ABORTED) { 134396a888c6Smillert *lp = oldlabel; /* undo damage */ 134496a888c6Smillert return; 1345aa3970cdSkrw } else if (ui == CMD_BADVALUE) 1346ac30837aSkrw ; /* Try again. */ 13476fe57b42Smillert else 13486fe57b42Smillert break; 13496fe57b42Smillert } 13506fe57b42Smillert lp->d_nsectors = ui; 13516fe57b42Smillert 13526fe57b42Smillert /* tracks/cylinder */ 13536fe57b42Smillert for (;;) { 13540db7769aSkrw ui = getnumber("tracks/cylinder", 13556fe57b42Smillert "The number of tracks per cylinder.", lp->d_ntracks, 13560db7769aSkrw UINT32_MAX); 1357aa3970cdSkrw if (ui == CMD_ABORTED) { 135896a888c6Smillert *lp = oldlabel; /* undo damage */ 135996a888c6Smillert return; 1360aa3970cdSkrw } else if (ui == CMD_BADVALUE) 1361ac30837aSkrw ; /* Try again. */ 13626fe57b42Smillert else 13636fe57b42Smillert break; 13646fe57b42Smillert } 13656fe57b42Smillert lp->d_ntracks = ui; 13666fe57b42Smillert 13676fe57b42Smillert /* sectors/cylinder */ 1368148b6188Smillert for (;;) { 13690db7769aSkrw ui = getnumber("sectors/cylinder", 1370148b6188Smillert "The number of sectors per cylinder (Usually sectors/track " 13710db7769aSkrw "* tracks/cylinder).", lp->d_secpercyl, UINT32_MAX); 1372aa3970cdSkrw if (ui == CMD_ABORTED) { 137396a888c6Smillert *lp = oldlabel; /* undo damage */ 137496a888c6Smillert return; 1375aa3970cdSkrw } else if (ui == CMD_BADVALUE) 1376ac30837aSkrw ; /* Try again. */ 1377148b6188Smillert else 1378148b6188Smillert break; 1379148b6188Smillert } 1380148b6188Smillert lp->d_secpercyl = ui; 13816fe57b42Smillert 13826fe57b42Smillert /* number of cylinders */ 13836fe57b42Smillert for (;;) { 13840db7769aSkrw ui = getnumber("number of cylinders", 13856fe57b42Smillert "The total number of cylinders on the disk.", 13860db7769aSkrw lp->d_ncylinders, UINT32_MAX); 1387aa3970cdSkrw if (ui == CMD_ABORTED) { 138896a888c6Smillert *lp = oldlabel; /* undo damage */ 138996a888c6Smillert return; 1390aa3970cdSkrw } else if (ui == CMD_BADVALUE) 1391ac30837aSkrw ; /* Try again. */ 13926fe57b42Smillert else 13936fe57b42Smillert break; 13946fe57b42Smillert } 13956fe57b42Smillert lp->d_ncylinders = ui; 13966fe57b42Smillert 13976fe57b42Smillert /* total sectors */ 13986fe57b42Smillert for (;;) { 1399b9fc9a72Sderaadt u_int64_t nsec = MAXIMUM(DL_GETDSIZE(lp), 140034af67a3Sotto (u_int64_t)lp->d_ncylinders * lp->d_secpercyl); 1401117239d3Skrw ui = getuint64(lp, "total sectors", 14026fe57b42Smillert "The total number of sectors on the disk.", 140340b226e8Skrw nsec, nsec, NULL); 1404aa3970cdSkrw if (ui == CMD_ABORTED) { 140596a888c6Smillert *lp = oldlabel; /* undo damage */ 140696a888c6Smillert return; 1407aa3970cdSkrw } else if (ui == CMD_BADVALUE) 1408ac30837aSkrw ; /* Try again. */ 14091e0ad43cSotto else if (ui > DL_GETDSIZE(lp) && 14101e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 1411f98aebd4Smillert puts("You may want to increase the size of the 'c' " 1412f98aebd4Smillert "partition."); 14136fe57b42Smillert break; 14141e0ad43cSotto } else if (ui < DL_GETDSIZE(lp) && 14151e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 14166fe57b42Smillert /* shrink free count */ 14179fdcb4d6Skrw freesectors = editor_countfree(lp); 14189fdcb4d6Skrw if (DL_GETDSIZE(lp) - ui > freesectors) 14196fe57b42Smillert fprintf(stderr, 14201e0ad43cSotto "Not enough free space to shrink by %llu " 14211e0ad43cSotto "sectors (only %llu sectors left)\n", 14229fdcb4d6Skrw DL_GETDSIZE(lp) - ui, freesectors); 1423c4f83f03Skrw else 14246fe57b42Smillert break; 14256fe57b42Smillert } else 14266fe57b42Smillert break; 14276fe57b42Smillert } 142841ed49b7Smillert /* Adjust ending_sector if necessary. */ 142978f0fb17Skrw if (ending_sector > ui) { 143096a888c6Smillert ending_sector = ui; 143178f0fb17Skrw DL_SETBEND(lp, ending_sector); 143278f0fb17Skrw } 14331e0ad43cSotto DL_SETDSIZE(lp, ui); 14346fe57b42Smillert } 1435a7e61405Smillert 1436a7e61405Smillert struct partition ** 14370fbd3c97Skrw sort_partitions(struct disklabel *lp) 1438a7e61405Smillert { 1439d18c2a43Skrw static struct partition *spp[MAXPARTITIONS+2]; 14400fbd3c97Skrw int i, npartitions; 1441a7e61405Smillert 1442d18c2a43Skrw memset(spp, 0, sizeof(spp)); 1443d18c2a43Skrw 1444a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1445a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1446a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 14471e0ad43cSotto DL_GETPSIZE(&lp->d_partitions[i]) != 0) 1448a7e61405Smillert spp[npartitions++] = &lp->d_partitions[i]; 1449a7e61405Smillert } 1450a7e61405Smillert 1451a7e61405Smillert /* 1452a7e61405Smillert * Sort the partitions based on starting offset. 1453a7e61405Smillert * This is safe because we guarantee no overlap. 1454a7e61405Smillert */ 1455a7e61405Smillert if (npartitions > 1) 14560f1cd5a2Skrw if (mergesort((void *)spp, npartitions, sizeof(spp[0]), 1457a7e61405Smillert partition_cmp)) 1458a7e61405Smillert err(4, "failed to sort partition table"); 1459a7e61405Smillert 1460a7e61405Smillert return (spp); 1461a7e61405Smillert } 14620f820bbbSmillert 14630f820bbbSmillert /* 14640f820bbbSmillert * Get a valid disk type if necessary. 14650f820bbbSmillert */ 14660f820bbbSmillert void 14678809fabbSderaadt getdisktype(struct disklabel *lp, char *banner, char *dev) 14680f820bbbSmillert { 14690f820bbbSmillert int i; 1470b228e876Smiod char *s; 1471b228e876Smiod const char *def = "SCSI"; 1472b228e876Smiod const struct dtypes { 1473b228e876Smiod const char *dev; 1474b228e876Smiod const char *type; 1475803ff7d5Smillert } dtypes[] = { 1476c33fcabaSmillert { "sd", "SCSI" }, 1477c33fcabaSmillert { "wd", "IDE" }, 1478c33fcabaSmillert { "fd", "FLOPPY" }, 1479c33fcabaSmillert { "xd", "SMD" }, 1480c33fcabaSmillert { "xy", "SMD" }, 1481c33fcabaSmillert { "hd", "HP-IB" }, 1482c33fcabaSmillert { "vnd", "VND" }, 1483c33fcabaSmillert { "svnd", "VND" }, 1484c33fcabaSmillert { NULL, NULL } 1485803ff7d5Smillert }; 1486803ff7d5Smillert 1487803ff7d5Smillert if ((s = basename(dev)) != NULL) { 1488803ff7d5Smillert if (*s == 'r') 1489803ff7d5Smillert s++; 1490803ff7d5Smillert i = strcspn(s, "0123456789"); 1491803ff7d5Smillert s[i] = '\0'; 1492803ff7d5Smillert dev = s; 1493803ff7d5Smillert for (i = 0; dtypes[i].dev != NULL; i++) { 1494803ff7d5Smillert if (strcmp(dev, dtypes[i].dev) == 0) { 1495803ff7d5Smillert def = dtypes[i].type; 1496803ff7d5Smillert break; 1497803ff7d5Smillert } 1498803ff7d5Smillert } 1499803ff7d5Smillert } 15000f820bbbSmillert 15010f820bbbSmillert if (lp->d_type > DKMAXTYPES || lp->d_type == 0) { 15020f820bbbSmillert puts(banner); 15030f820bbbSmillert puts("Possible values are:"); 1504eb5dd924Sderaadt printf("\"IDE\", "); 15050f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15060f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15070f820bbbSmillert if (i < DKMAXTYPES - 1) 15080f820bbbSmillert fputs(", ", stdout); 15090f820bbbSmillert } 15100f820bbbSmillert putchar('\n'); 15110f820bbbSmillert 15120f820bbbSmillert for (;;) { 1513c33fcabaSmillert s = getstring("Disk type", 1514803ff7d5Smillert "What kind of disk is this? Usually SCSI, IDE, " 1515d7878011Sderaadt "ESDI, ST506, or floppy.", def); 151696a888c6Smillert if (s == NULL) 151796a888c6Smillert continue; 15185b412421Smillert if (strcasecmp(s, "IDE") == 0) { 15195b412421Smillert lp->d_type = DTYPE_ESDI; 15205b412421Smillert return; 15215b412421Smillert } 15220f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) 15230f820bbbSmillert if (strcasecmp(s, dktypenames[i]) == 0) { 15240f820bbbSmillert lp->d_type = i; 15250f820bbbSmillert return; 15260f820bbbSmillert } 15270f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", s); 15280f820bbbSmillert fputs("Valid types are: ", stdout); 15290f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15300f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15310f820bbbSmillert if (i < DKMAXTYPES - 1) 15320f820bbbSmillert fputs(", ", stdout); 15330f820bbbSmillert } 15340f820bbbSmillert putchar('\n'); 15350f820bbbSmillert } 15360f820bbbSmillert } 15370f820bbbSmillert } 153896a888c6Smillert 153996a888c6Smillert /* 154096a888c6Smillert * Get beginning and ending sectors of the OpenBSD portion of the disk 154196a888c6Smillert * from the user. 154296a888c6Smillert */ 154396a888c6Smillert void 15449fdcb4d6Skrw set_bounds(struct disklabel *lp) 154596a888c6Smillert { 15461e0ad43cSotto u_int64_t ui, start_temp; 154796a888c6Smillert 154896a888c6Smillert /* Starting sector */ 1549f1bc1b27Skrw for (;;) { 1550117239d3Skrw ui = getuint64(lp, "Starting sector", 155196a888c6Smillert "The start of the OpenBSD portion of the disk.", 155240b226e8Skrw starting_sector, DL_GETDSIZE(lp), NULL); 1553aa3970cdSkrw if (ui == CMD_ABORTED) 155496a888c6Smillert return; 1555aa3970cdSkrw else if (ui == CMD_BADVALUE) 1556f1bc1b27Skrw ; /* Try again. */ 1557f1bc1b27Skrw else if (ui >= DL_GETDSIZE(lp)) 1558f1bc1b27Skrw fprintf(stderr, "starting sector must be < %llu\n", 1559f1bc1b27Skrw DL_GETDSIZE(lp)); 1560f1bc1b27Skrw else 1561f1bc1b27Skrw break; 1562f1bc1b27Skrw } 156396a888c6Smillert start_temp = ui; 156496a888c6Smillert 15654793b14cSmillert /* Size */ 1566f1bc1b27Skrw for (;;) { 1567117239d3Skrw ui = getuint64(lp, "Size ('*' for entire disk)", 1568f98aebd4Smillert "The size of the OpenBSD portion of the disk ('*' for the " 1569f98aebd4Smillert "entire disk).", ending_sector - starting_sector, 157040b226e8Skrw DL_GETDSIZE(lp) - start_temp, NULL); 1571aa3970cdSkrw if (ui == CMD_ABORTED) 157296a888c6Smillert return; 1573aa3970cdSkrw else if (ui == CMD_BADVALUE) 1574f1bc1b27Skrw ; /* Try again. */ 1575f1bc1b27Skrw else if (ui > DL_GETDSIZE(lp) - start_temp) 1576f1bc1b27Skrw fprintf(stderr, "size must be <= %llu\n", 1577f1bc1b27Skrw DL_GETDSIZE(lp) - start_temp); 1578f1bc1b27Skrw else 1579f1bc1b27Skrw break; 1580f1bc1b27Skrw } 15814793b14cSmillert ending_sector = start_temp + ui; 158278f0fb17Skrw DL_SETBEND(lp, ending_sector); 158396a888c6Smillert starting_sector = start_temp; 158478f0fb17Skrw DL_SETBSTART(lp, starting_sector); 158596a888c6Smillert } 158696a888c6Smillert 158796a888c6Smillert /* 15880d63cfbaSjsing * Allow user to interactively change disklabel UID. 15890d63cfbaSjsing */ 15900d63cfbaSjsing void 159169a6ffbcSjsing set_duid(struct disklabel *lp) 15920d63cfbaSjsing { 15930d63cfbaSjsing char *s; 15940d63cfbaSjsing int i; 15950d63cfbaSjsing 1596f6ad9e2dSjsing printf("The disklabel UID is currently: " 1597f6ad9e2dSjsing "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n", 1598f6ad9e2dSjsing lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3], 1599f6ad9e2dSjsing lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]); 16000d63cfbaSjsing 16010d63cfbaSjsing do { 160269a6ffbcSjsing s = getstring("duid", "The disklabel UID, given as a 16 " 16030d63cfbaSjsing "character hexadecimal string.", NULL); 1604ce98d1aeShalex if (s == NULL || strlen(s) == 0) { 16050d63cfbaSjsing fputs("Command aborted\n", stderr); 16060d63cfbaSjsing return; 16070d63cfbaSjsing } 160869a6ffbcSjsing i = duid_parse(lp, s); 16090d63cfbaSjsing if (i != 0) 16100d63cfbaSjsing fputs("Invalid UID entered.\n", stderr); 16110d63cfbaSjsing } while (i != 0); 16120d63cfbaSjsing } 16130d63cfbaSjsing 16140d63cfbaSjsing /* 161596a888c6Smillert * Return a list of the "chunks" of free space available 161696a888c6Smillert */ 161796a888c6Smillert struct diskchunk * 16188809fabbSderaadt free_chunks(struct disklabel *lp) 161996a888c6Smillert { 162096a888c6Smillert struct partition **spp; 162196a888c6Smillert static struct diskchunk chunks[MAXPARTITIONS + 2]; 162299bd27d2Skrw u_int64_t start, stop; 162396a888c6Smillert int i, numchunks; 162496a888c6Smillert 16250fbd3c97Skrw /* Sort the in-use partitions based on offset */ 16260fbd3c97Skrw spp = sort_partitions(lp); 162796a888c6Smillert 162896a888c6Smillert /* If there are no partitions, it's all free. */ 16290fbd3c97Skrw if (spp[0] == NULL) { 16302d8451b0Smillert chunks[0].start = starting_sector; 163196a888c6Smillert chunks[0].stop = ending_sector; 163296a888c6Smillert chunks[1].start = chunks[1].stop = 0; 163396a888c6Smillert return (chunks); 163496a888c6Smillert } 163596a888c6Smillert 163696a888c6Smillert /* Find chunks of free space */ 163796a888c6Smillert numchunks = 0; 16380fbd3c97Skrw if (DL_GETPOFFSET(spp[0]) > starting_sector) { 16392d8451b0Smillert chunks[0].start = starting_sector; 16401e0ad43cSotto chunks[0].stop = DL_GETPOFFSET(spp[0]); 164196a888c6Smillert numchunks++; 164296a888c6Smillert } 16430fbd3c97Skrw for (i = 0; spp[i] != NULL; i++) { 164499bd27d2Skrw start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]); 1645aff3f969Sotto if (start < starting_sector) 1646aff3f969Sotto start = starting_sector; 1647aff3f969Sotto else if (start > ending_sector) 1648aff3f969Sotto start = ending_sector; 164999bd27d2Skrw if (spp[i + 1] != NULL) 165099bd27d2Skrw stop = DL_GETPOFFSET(spp[i+1]); 165199bd27d2Skrw else 165299bd27d2Skrw stop = ending_sector; 1653aff3f969Sotto if (stop < starting_sector) 1654aff3f969Sotto stop = starting_sector; 1655aff3f969Sotto else if (stop > ending_sector) 1656aff3f969Sotto stop = ending_sector; 165799bd27d2Skrw if (start < stop) { 165899bd27d2Skrw chunks[numchunks].start = start; 165999bd27d2Skrw chunks[numchunks].stop = stop; 166096a888c6Smillert numchunks++; 166196a888c6Smillert } 166296a888c6Smillert } 166396a888c6Smillert 166496a888c6Smillert /* Terminate and return */ 166596a888c6Smillert chunks[numchunks].start = chunks[numchunks].stop = 0; 166696a888c6Smillert return (chunks); 166796a888c6Smillert } 16684793b14cSmillert 16694793b14cSmillert void 167087023ed9Skrw find_bounds(struct disklabel *lp) 16714793b14cSmillert { 16726534e983Sderaadt starting_sector = DL_GETBSTART(lp); 16736534e983Sderaadt ending_sector = DL_GETBEND(lp); 1674b2d4a455Smiod 16756534e983Sderaadt if (ending_sector) { 167634ae4198Skrw if (verbose) 167734ae4198Skrw printf("Treating sectors %llu-%llu as the OpenBSD" 167834ae4198Skrw " portion of the disk.\nYou can use the 'b'" 167934ae4198Skrw " command to change this.\n\n", starting_sector, 168034ae4198Skrw ending_sector); 16814793b14cSmillert } 1682b2d4a455Smiod } 1683c0bdc608Smillert 1684c0bdc608Smillert /* 1685c0bdc608Smillert * Calculate free space. 1686c0bdc608Smillert */ 16879fdcb4d6Skrw u_int64_t 16889fdcb4d6Skrw editor_countfree(struct disklabel *lp) 1689c0bdc608Smillert { 1690d93cb2bbSkrw struct diskchunk *chunks; 16919fdcb4d6Skrw u_int64_t freesectors = 0; 1692c0bdc608Smillert int i; 1693c0bdc608Smillert 1694d93cb2bbSkrw chunks = free_chunks(lp); 1695509930fbSotto 1696d93cb2bbSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) 16979fdcb4d6Skrw freesectors += chunks[i].stop - chunks[i].start; 16989fdcb4d6Skrw 16999fdcb4d6Skrw return (freesectors); 1700c0bdc608Smillert } 1701617e6e4aSmillert 1702617e6e4aSmillert void 17034d812bb6Slum editor_help(void) 1704617e6e4aSmillert { 1705617e6e4aSmillert puts("Available commands:"); 1706617e6e4aSmillert puts( 17074d812bb6Slum " ? | h - show help n [part] - set mount point\n" 170849159a67Skrw " A - auto partition all space p [unit] - print partitions\n" 170949159a67Skrw " a [part] - add partition q - quit & save changes\n" 17104659aa0dSotto " b - set OpenBSD boundaries R [part] - resize auto allocated partition\n" 171149159a67Skrw " c [part] - change partition size r - display free space\n" 17126aaa4aabSotto " D - reset label to default s [path] - save label to file\n" 17136aaa4aabSotto " d [part] - delete partition U - undo all changes\n" 17146aaa4aabSotto " e - edit drive parameters u - undo last change\n" 17156aaa4aabSotto " g [d|u] - [d]isk or [u]ser geometry w - write label to disk\n" 17160d63cfbaSjsing " i - modify disklabel UID X - toggle expert mode\n" 17170d63cfbaSjsing " l [unit] - print disk label header x - exit & lose changes\n" 17180d63cfbaSjsing " M - disklabel(8) man page z - delete all partitions\n" 17190d63cfbaSjsing " m [part] - modify partition\n" 1720c4884206Skrw "\n" 1721c4884206Skrw "Suffixes can be used to indicate units other than sectors:\n" 1722e5f81948Sotto " 'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes) 't' (terabytes)\n" 1723e5f81948Sotto " 'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n" 1724c4884206Skrw "Values in non-sector units are truncated to the nearest cylinder boundary."); 17254d812bb6Slum 1726617e6e4aSmillert } 1727bd6726faSmillert 17284f3bbbf0Skrw void 17298809fabbSderaadt mpcopy(char **to, char **from) 1730bd6726faSmillert { 1731bd6726faSmillert int i; 1732bd6726faSmillert 1733bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1734bd6726faSmillert free(to[i]); 1735bd6726faSmillert to[i] = NULL; 1736408ab9bcSkrw if (from[i] != NULL) { 1737408ab9bcSkrw to[i] = strdup(from[i]); 1738408ab9bcSkrw if (to[i] == NULL) 1739408ab9bcSkrw errx(4, "out of memory"); 1740bd6726faSmillert } 1741bd6726faSmillert } 1742bd6726faSmillert } 1743bd6726faSmillert 1744bd6726faSmillert int 17458809fabbSderaadt mpequal(char **mp1, char **mp2) 1746bd6726faSmillert { 1747bd6726faSmillert int i; 1748bd6726faSmillert 1749bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1750bd6726faSmillert if (mp1[i] == NULL && mp2[i] == NULL) 1751bd6726faSmillert continue; 1752bd6726faSmillert 1753bd6726faSmillert if ((mp1[i] != NULL && mp2[i] == NULL) || 1754bd6726faSmillert (mp1[i] == NULL && mp2[i] != NULL) || 1755bd6726faSmillert (strcmp(mp1[i], mp2[i]) != 0)) 1756bd6726faSmillert return (0); 1757bd6726faSmillert } 1758bd6726faSmillert return (1); 1759bd6726faSmillert } 1760bd6726faSmillert 176193160b9bSkrw void 176234ae4198Skrw mpsave(struct disklabel *lp) 1763bd6726faSmillert { 1764d8b446ceSderaadt int i, j; 1765b9fc9a72Sderaadt char bdev[PATH_MAX], *p; 17663f843443Smillert struct mountinfo mi[MAXPARTITIONS]; 1767bd6726faSmillert FILE *fp; 1768fe01da94Skrw u_int8_t fstype; 1769bd6726faSmillert 177093160b9bSkrw if (!fstabfile) 177193160b9bSkrw return; 177293160b9bSkrw 17733f843443Smillert memset(&mi, 0, sizeof(mi)); 17743f843443Smillert 1775d8b446ceSderaadt for (i = 0; i < MAXPARTITIONS; i++) { 1776fe01da94Skrw fstype = lp->d_partitions[i].p_fstype; 1777fe01da94Skrw if (mountpoints[i] != NULL || fstype == FS_SWAP) { 177834ae4198Skrw mi[i].mountpoint = mountpoints[i]; 17793f843443Smillert mi[i].partno = i; 1780bd6726faSmillert } 1781bd6726faSmillert } 1782bd6726faSmillert 178334ae4198Skrw /* Convert specname to bdev */ 1784d6d80bb0Skrw if (uidflag) { 1785d6d80bb0Skrw snprintf(bdev, sizeof(bdev), 1786d6d80bb0Skrw "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c", 1787d6d80bb0Skrw lab.d_uid[0], lab.d_uid[1], lab.d_uid[2], lab.d_uid[3], 1788d6d80bb0Skrw lab.d_uid[4], lab.d_uid[5], lab.d_uid[6], lab.d_uid[7], 1789d6d80bb0Skrw specname[strlen(specname)-1]); 1790d6d80bb0Skrw } else if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 && 179134ae4198Skrw specname[sizeof(_PATH_DEV) - 1] == 'r') { 1792bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV, 179334ae4198Skrw &specname[sizeof(_PATH_DEV)]); 1794bd6726faSmillert } else { 179534ae4198Skrw if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r') 179693160b9bSkrw return; 1797bd6726faSmillert *p = '\0'; 179834ae4198Skrw snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1); 1799bd6726faSmillert *p = 'r'; 1800bd6726faSmillert } 1801bd6726faSmillert bdev[strlen(bdev) - 1] = '\0'; 1802bd6726faSmillert 18033f843443Smillert /* Sort mountpoints so we don't try to mount /usr/local before /usr */ 18043f843443Smillert qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp); 18053f843443Smillert 1806d71533c9Stedu if ((fp = fopen(fstabfile, "w"))) { 1807fe01da94Skrw for (i = 0; i < MAXPARTITIONS; i++) { 18085fea0b85Smillert j = mi[i].partno; 1809fe01da94Skrw fstype = lp->d_partitions[j].p_fstype; 1810fe01da94Skrw if (fstype == FS_SWAP) { 1811fe01da94Skrw fprintf(fp, "%s%c none swap sw\n", bdev, 'a'+j); 1812fe01da94Skrw } else if (mi[i].mountpoint) { 1813fe01da94Skrw fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 1814fe01da94Skrw 'a' + j, mi[i].mountpoint, 1815fe01da94Skrw fstypesnames[fstype], j == 0 ? 1 : 2); 1816fe01da94Skrw } 1817bd6726faSmillert } 1818bd6726faSmillert fclose(fp); 181993160b9bSkrw } 1820bd6726faSmillert } 182124a2c1a4Smillert 1822408ab9bcSkrw void 1823408ab9bcSkrw mpfree(char **mp) 1824408ab9bcSkrw { 1825408ab9bcSkrw int part; 1826408ab9bcSkrw 1827408ab9bcSkrw if (mp == NULL) 1828408ab9bcSkrw return; 1829408ab9bcSkrw 183075691760Skrw for (part = 0; part < MAXPARTITIONS; part++) 1831408ab9bcSkrw free(mp[part]); 1832408ab9bcSkrw 1833408ab9bcSkrw free(mp); 1834408ab9bcSkrw } 1835408ab9bcSkrw 183624a2c1a4Smillert int 1837604d3bdeSkrw get_offset(struct disklabel *lp, int partno) 183824a2c1a4Smillert { 183940b226e8Skrw struct partition opp, *pp = &lp->d_partitions[partno]; 184040b226e8Skrw u_int64_t ui, offsetalign; 184140b226e8Skrw int flags; 184224a2c1a4Smillert 184340b226e8Skrw flags = DO_CONVERSIONS; 1844117239d3Skrw ui = getuint64(lp, "offset", 18451e0ad43cSotto "Starting sector for this partition.", 18461e0ad43cSotto DL_GETPOFFSET(pp), 184740b226e8Skrw DL_GETPOFFSET(pp), &flags); 1848e9ff19beSkrw 184940b226e8Skrw if (ui == CMD_ABORTED || ui == CMD_BADVALUE) 185040b226e8Skrw return (1); 1851fc1a4cc6Sderaadt #ifdef SUN_AAT0 185240b226e8Skrw if (partno == 0 && ui != 0) { 185349bf537cSderaadt fprintf(stderr, "This architecture requires that " 185440f544cdSderaadt "partition 'a' start at sector 0.\n"); 185540b226e8Skrw return (1); 185624a2c1a4Smillert } 185740b226e8Skrw #endif 185840b226e8Skrw opp = *pp; 185940b226e8Skrw DL_SETPOFFSET(pp, ui); 186040b226e8Skrw offsetalign = 1; 186140b226e8Skrw if ((flags & DO_ROUNDING) != 0 && pp->p_fstype == FS_BSDFFS) 186240b226e8Skrw offsetalign = lp->d_secpercyl; 186340b226e8Skrw 186440b226e8Skrw if (alignpartition(lp, partno, offsetalign, 1, ROUND_OFFSET_UP) == 1) { 186540b226e8Skrw *pp = opp; 186640b226e8Skrw return (1); 186715c15d8aSkrw } 1868e9ff19beSkrw 186940b226e8Skrw if (expert == 1 && quiet == 0 && ui != DL_GETPOFFSET(pp)) 187040b226e8Skrw printf("offset rounded to sector %llu\n", DL_GETPOFFSET(pp)); 187140b226e8Skrw 187240b226e8Skrw return (0); 187315c15d8aSkrw } 187424a2c1a4Smillert 187524a2c1a4Smillert int 18769fdcb4d6Skrw get_size(struct disklabel *lp, int partno) 187724a2c1a4Smillert { 187840b226e8Skrw struct partition opp, *pp = &lp->d_partitions[partno]; 187940b226e8Skrw u_int64_t maxsize, ui, sizealign; 188040b226e8Skrw int flags; 188114192793Skrw 188214192793Skrw maxsize = max_partition_size(lp, partno); 188340b226e8Skrw flags = DO_CONVERSIONS; 1884117239d3Skrw ui = getuint64(lp, "size", "Size of the partition. " 18857da73705Skrw "You may also say +/- amount for a relative change.", 188640b226e8Skrw DL_GETPSIZE(pp), maxsize, &flags); 1887e9ff19beSkrw 188840b226e8Skrw if (ui == CMD_ABORTED || ui == CMD_BADVALUE) 188940b226e8Skrw return (1); 189040b226e8Skrw 189140b226e8Skrw opp = *pp; 189259ccf790Skrw DL_SETPSIZE(pp, ui); 189340b226e8Skrw sizealign = 1; 189440b226e8Skrw if ((flags & DO_ROUNDING) != 0 && (pp->p_fstype == FS_SWAP || 189540b226e8Skrw pp->p_fstype == FS_BSDFFS)) 189640b226e8Skrw sizealign = lp->d_secpercyl; 189740b226e8Skrw 189840b226e8Skrw if (alignpartition(lp, partno, 1, sizealign, ROUND_SIZE_UP) == 1) { 189940b226e8Skrw *pp = opp; 190040b226e8Skrw return (1); 190124a2c1a4Smillert } 1902e9ff19beSkrw 190340b226e8Skrw if (expert == 1 && quiet == 0 && ui != DL_GETPSIZE(pp)) 190440b226e8Skrw printf("size rounded to %llu sectors\n", DL_GETPSIZE(pp)); 190540b226e8Skrw 190640b226e8Skrw return (0); 1907e9ff19beSkrw } 190824a2c1a4Smillert 190924a2c1a4Smillert int 1910a95dd767Sotto get_cpg(struct disklabel *lp, int partno) 1911a95dd767Sotto { 1912a95dd767Sotto u_int64_t ui; 1913a95dd767Sotto struct partition *pp = &lp->d_partitions[partno]; 1914a95dd767Sotto 19154aa85578Skrw if (pp->p_fstype != FS_BSDFFS) 19164aa85578Skrw return (0); 19174aa85578Skrw 19184aa85578Skrw if (pp->p_cpg == 0) 19194aa85578Skrw pp->p_cpg = 1; 19204aa85578Skrw 192140b226e8Skrw if (expert == 0) 1922a95dd767Sotto return (0); 1923a95dd767Sotto 1924a95dd767Sotto for (;;) { 19250db7769aSkrw ui = getnumber("cpg", "Size of partition in fs blocks.", 19260db7769aSkrw pp->p_cpg, USHRT_MAX); 1927aa3970cdSkrw if (ui == CMD_ABORTED) 1928a95dd767Sotto return (1); 1929aa3970cdSkrw else if (ui == CMD_BADVALUE) 1930ac30837aSkrw ; /* Try again. */ 1931ac30837aSkrw else 1932a95dd767Sotto break; 1933a95dd767Sotto } 1934a95dd767Sotto pp->p_cpg = ui; 1935a95dd767Sotto return (0); 1936a95dd767Sotto } 1937a95dd767Sotto 1938a95dd767Sotto int 19398809fabbSderaadt get_fsize(struct disklabel *lp, int partno) 194024a2c1a4Smillert { 194124a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 1942a3ad4147Skrw u_int64_t ui, bytes; 1943a3ad4147Skrw u_int32_t frag, fsize; 194424a2c1a4Smillert 1945a3ad4147Skrw if (pp->p_fstype != FS_BSDFFS) 1946a4c87e64Skrw return (0); 1947a4c87e64Skrw 1948ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 1949ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 1950a3ad4147Skrw if (fsize == 0) { 1951a3ad4147Skrw fsize = 2048; 1952ddfcbf38Sotto frag = 8; 1953a3ad4147Skrw bytes = DL_GETPSIZE(pp) * lp->d_secsize; 1954a3ad4147Skrw if (bytes > 128ULL * 1024 * 1024 * 1024) 1955a3ad4147Skrw fsize *= 2; 1956a3ad4147Skrw if (bytes > 512ULL * 1024 * 1024 * 1024) 1957a3ad4147Skrw fsize *= 2; 1958a3ad4147Skrw if (fsize < lp->d_secsize) 1959a3ad4147Skrw fsize = lp->d_secsize; 1960a3ad4147Skrw if (fsize > MAXBSIZE / frag) 1961a3ad4147Skrw fsize = MAXBSIZE / frag; 1962a3ad4147Skrw pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, frag); 1963a3ad4147Skrw } 1964a3ad4147Skrw 1965a3ad4147Skrw if (expert == 0) 1966a3ad4147Skrw return (0); 1967ddfcbf38Sotto 196824a2c1a4Smillert for (;;) { 19690db7769aSkrw ui = getnumber("fragment size", 1970c782b064Skrw "Size of ffs block fragments. A multiple of the disk " 19710db7769aSkrw "sector-size.", fsize, UINT32_MAX); 1972aa3970cdSkrw if (ui == CMD_ABORTED) 197324a2c1a4Smillert return (1); 1974aa3970cdSkrw else if (ui == CMD_BADVALUE) 1975ac30837aSkrw ; /* Try again. */ 1976ac30837aSkrw else if (ui < lp->d_secsize || (ui % lp->d_secsize) != 0) 1977c782b064Skrw fprintf(stderr, "Error: fragment size must be a " 1978c782b064Skrw "multiple of the disk sector size (%d)\n", 1979c782b064Skrw lp->d_secsize); 1980ac30837aSkrw else 198124a2c1a4Smillert break; 198224a2c1a4Smillert } 198324a2c1a4Smillert if (ui == 0) 198424a2c1a4Smillert puts("Zero fragment size implies zero block size"); 1985ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag); 198624a2c1a4Smillert return (0); 198724a2c1a4Smillert } 198824a2c1a4Smillert 198924a2c1a4Smillert int 19908809fabbSderaadt get_bsize(struct disklabel *lp, int partno) 199124a2c1a4Smillert { 19927a687b60Skrw u_int64_t ui, frag, fsize; 199340b226e8Skrw struct partition opp, *pp = &lp->d_partitions[partno]; 199440b226e8Skrw u_int64_t offsetalign, sizealign; 19956be94867Skrw char *p; 199624a2c1a4Smillert 1997a49bdda8Skrw if (pp->p_fstype != FS_BSDFFS) 1998a4c87e64Skrw return (0); 1999a4c87e64Skrw 200024a2c1a4Smillert /* Avoid dividing by zero... */ 2001ddfcbf38Sotto if (pp->p_fragblock == 0) 200224a2c1a4Smillert return (1); 2003ddfcbf38Sotto 200440b226e8Skrw opp = *pp; 200540b226e8Skrw if (expert == 0) 2006a49bdda8Skrw goto align; 2007a49bdda8Skrw 2008ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 2009ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 201024a2c1a4Smillert 201124a2c1a4Smillert for (;;) { 20120db7769aSkrw ui = getnumber("block size", 20130cf7e76dSotto "Size of ffs blocks. 1, 2, 4 or 8 times ffs fragment size.", 20140db7769aSkrw fsize * frag, UINT32_MAX); 201524a2c1a4Smillert 201624a2c1a4Smillert /* sanity checks */ 2017aa3970cdSkrw if (ui == CMD_ABORTED) 201824a2c1a4Smillert return (1); 2019aa3970cdSkrw else if (ui == CMD_BADVALUE) 2020ac30837aSkrw ; /* Try again. */ 202124a2c1a4Smillert else if (ui < getpagesize()) 202224a2c1a4Smillert fprintf(stderr, 202324a2c1a4Smillert "Error: block size must be at least as big " 202424a2c1a4Smillert "as page size (%d).\n", getpagesize()); 20250cf7e76dSotto else if (ui < fsize || (fsize != ui && fsize * 2 != ui && 20260cf7e76dSotto fsize * 4 != ui && fsize * 8 != ui)) 20270cf7e76dSotto fprintf(stderr, "Error: block size must be 1, 2, 4 or " 20280cf7e76dSotto "8 times fragment size (%llu).\n", 20292777acfaSchl (unsigned long long) fsize); 203024a2c1a4Smillert else 203124a2c1a4Smillert break; 203224a2c1a4Smillert } 20330cf7e76dSotto frag = ui / fsize; 20340cf7e76dSotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fsize, frag); 2035a49bdda8Skrw 203640b226e8Skrw #ifdef SUN_CYLCHECK 20376be94867Skrw return (0); 20386be94867Skrw #endif 203940b226e8Skrw p = getstring("Align partition to block size", 204040b226e8Skrw "Round the partition offset and size to multiples of bsize?", "y"); 204140b226e8Skrw if (*p == 'n' || *p == 'N') 204240b226e8Skrw return (0); 20436be94867Skrw 20446be94867Skrw align: 204540b226e8Skrw #ifdef SUN_CYLCHECK 204640b226e8Skrw return (0); 2047a49bdda8Skrw #endif 204840b226e8Skrw sizealign = (DISKLABELV1_FFS_FRAG(pp->p_fragblock) * 204940b226e8Skrw DISKLABELV1_FFS_FSIZE(pp->p_fragblock)) / lp->d_secsize; 205040b226e8Skrw offsetalign = 1; 205140b226e8Skrw if (DL_GETPOFFSET(pp) != starting_sector) 205240b226e8Skrw offsetalign = sizealign; 205340b226e8Skrw 2054922b28b8Skrw if (alignpartition(lp, partno, offsetalign, sizealign, ROUND_OFFSET_UP | 2055922b28b8Skrw ROUND_SIZE_DOWN | ROUND_SIZE_OVERLAP) == 1) { 205640b226e8Skrw *pp = opp; 205740b226e8Skrw return (1); 205840b226e8Skrw } 205940b226e8Skrw 206040b226e8Skrw if (expert == 1 && quiet == 0 && 206140b226e8Skrw DL_GETPOFFSET(&opp) != DL_GETPOFFSET(pp)) 206240b226e8Skrw printf("offset rounded to sector %llu\n", DL_GETPOFFSET(pp)); 206340b226e8Skrw if (expert == 1 && quiet == 0 && DL_GETPSIZE(&opp) != DL_GETPSIZE(pp)) 206440b226e8Skrw printf("size rounded to %llu sectors\n", DL_GETPSIZE(pp)); 206540b226e8Skrw 206624a2c1a4Smillert return (0); 206724a2c1a4Smillert } 206824a2c1a4Smillert 206924a2c1a4Smillert int 20708809fabbSderaadt get_fstype(struct disklabel *lp, int partno) 207124a2c1a4Smillert { 207224a2c1a4Smillert char *p; 20731e0ad43cSotto u_int64_t ui; 207424a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 207524a2c1a4Smillert 207624a2c1a4Smillert if (pp->p_fstype < FSMAXTYPES) { 2077c33fcabaSmillert p = getstring("FS type", 207824a2c1a4Smillert "Filesystem type (usually 4.2BSD or swap)", 207924a2c1a4Smillert fstypenames[pp->p_fstype]); 208024a2c1a4Smillert if (p == NULL) { 208124a2c1a4Smillert return (1); 208224a2c1a4Smillert } 208324a2c1a4Smillert for (ui = 0; ui < FSMAXTYPES; ui++) { 208424a2c1a4Smillert if (!strcasecmp(p, fstypenames[ui])) { 208524a2c1a4Smillert pp->p_fstype = ui; 208624a2c1a4Smillert break; 208724a2c1a4Smillert } 208824a2c1a4Smillert } 208924a2c1a4Smillert if (ui >= FSMAXTYPES) { 2090430e1380Skrw printf("Unrecognized filesystem type '%s', treating " 2091430e1380Skrw "as 'unknown'\n", p); 209224a2c1a4Smillert pp->p_fstype = FS_OTHER; 209324a2c1a4Smillert } 209424a2c1a4Smillert } else { 209524a2c1a4Smillert for (;;) { 20960db7769aSkrw ui = getnumber("FS type (decimal)", 2097430e1380Skrw "Filesystem type as a decimal number; usually 7 " 2098430e1380Skrw "(4.2BSD) or 1 (swap).", 20990db7769aSkrw pp->p_fstype, UINT8_MAX); 2100aa3970cdSkrw if (ui == CMD_ABORTED) 210124a2c1a4Smillert return (1); 2102aa3970cdSkrw else if (ui == CMD_BADVALUE) 2103ac30837aSkrw ; /* Try again. */ 210424a2c1a4Smillert else 210524a2c1a4Smillert break; 210624a2c1a4Smillert } 210724a2c1a4Smillert pp->p_fstype = ui; 210824a2c1a4Smillert } 210924a2c1a4Smillert return (0); 211024a2c1a4Smillert } 211124a2c1a4Smillert 211224a2c1a4Smillert int 211334ae4198Skrw get_mp(struct disklabel *lp, int partno) 211424a2c1a4Smillert { 211524a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 2116ec9fde5fSkrw char *p; 2117ec9fde5fSkrw int i; 211824a2c1a4Smillert 2119b308f3d4Skrw if (fstabfile == NULL || 2120b308f3d4Skrw pp->p_fstype == FS_UNUSED || 2121b308f3d4Skrw pp->p_fstype == FS_SWAP || 2122b308f3d4Skrw pp->p_fstype == FS_BOOT || 2123b308f3d4Skrw pp->p_fstype == FS_OTHER || 2124b308f3d4Skrw pp->p_fstype == FS_RAID) { 2125b308f3d4Skrw /* No fstabfile, no names. Not all fstypes can be named */ 2126b308f3d4Skrw return 0; 2127b308f3d4Skrw } 2128b308f3d4Skrw 2129ddaff619Smillert for (;;) { 2130c33fcabaSmillert p = getstring("mount point", 213124a2c1a4Smillert "Where to mount this filesystem (ie: / /var /usr)", 213234ae4198Skrw mountpoints[partno] ? mountpoints[partno] : "none"); 2133ac30837aSkrw if (p == NULL) 213424a2c1a4Smillert return (1); 2135ddaff619Smillert if (strcasecmp(p, "none") == 0) { 213634ae4198Skrw free(mountpoints[partno]); 213734ae4198Skrw mountpoints[partno] = NULL; 2138ddaff619Smillert break; 2139ddaff619Smillert } 2140ec9fde5fSkrw for (i = 0; i < MAXPARTITIONS; i++) 214193160b9bSkrw if (mountpoints[i] != NULL && i != partno && 2142ec9fde5fSkrw strcmp(p, mountpoints[i]) == 0) 2143ec9fde5fSkrw break; 2144ec9fde5fSkrw if (i < MAXPARTITIONS) { 214593160b9bSkrw fprintf(stderr, "'%c' already being mounted at " 214693160b9bSkrw "'%s'\n", 'a'+i, p); 2147ec9fde5fSkrw break; 2148ec9fde5fSkrw } 2149ddaff619Smillert if (*p == '/') { 2150ddaff619Smillert /* XXX - might as well realloc */ 215134ae4198Skrw free(mountpoints[partno]); 215234ae4198Skrw if ((mountpoints[partno] = strdup(p)) == NULL) 215324a2c1a4Smillert errx(4, "out of memory"); 2154ddaff619Smillert break; 2155ddaff619Smillert } 2156ddaff619Smillert fputs("Mount points must start with '/'\n", stderr); 215724a2c1a4Smillert } 2158b308f3d4Skrw 215924a2c1a4Smillert return (0); 216024a2c1a4Smillert } 21613f843443Smillert 21623f843443Smillert int 21638809fabbSderaadt micmp(const void *a1, const void *a2) 21643f843443Smillert { 21653f843443Smillert struct mountinfo *mi1 = (struct mountinfo *)a1; 21663f843443Smillert struct mountinfo *mi2 = (struct mountinfo *)a2; 21673f843443Smillert 21683f843443Smillert /* We want all the NULLs at the end... */ 21693f843443Smillert if (mi1->mountpoint == NULL && mi2->mountpoint == NULL) 21703f843443Smillert return (0); 21713f843443Smillert else if (mi1->mountpoint == NULL) 21723f843443Smillert return (1); 21733f843443Smillert else if (mi2->mountpoint == NULL) 21743f843443Smillert return (-1); 21753f843443Smillert else 21763f843443Smillert return (strcmp(mi1->mountpoint, mi2->mountpoint)); 21773f843443Smillert } 2178c33fcabaSmillert 2179c33fcabaSmillert void 218087023ed9Skrw get_geometry(int f, struct disklabel **dgpp) 2181c33fcabaSmillert { 2182c33fcabaSmillert struct stat st; 2183c33fcabaSmillert struct disklabel *disk_geop; 218487023ed9Skrw 2185c33fcabaSmillert if (fstat(f, &st) == -1) 2186c33fcabaSmillert err(4, "Can't stat device"); 2187c33fcabaSmillert 2188c33fcabaSmillert /* Get disk geometry */ 2189c33fcabaSmillert if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL) 2190c33fcabaSmillert errx(4, "out of memory"); 21919a379a6cSkrw if (ioctl(f, DIOCGPDINFO, disk_geop) < 0) 21929a379a6cSkrw err(4, "ioctl DIOCGPDINFO"); 2193c33fcabaSmillert *dgpp = disk_geop; 2194c33fcabaSmillert } 2195c33fcabaSmillert 2196c33fcabaSmillert void 21978809fabbSderaadt set_geometry(struct disklabel *lp, struct disklabel *dgp, 219887023ed9Skrw struct disklabel *ugp, char *p) 2199c33fcabaSmillert { 2200ac30837aSkrw if (p == NULL) 22019a36aa41Ssthen p = getstring("[d]isk or [u]ser geometry", 2202c33fcabaSmillert "Enter 'd' to use the geometry based on what the disk " 22039a36aa41Ssthen "itself thinks it is, or 'u' to use the geometry that " 22049a36aa41Ssthen "was found in the label.", 2205c33fcabaSmillert "d"); 2206ac30837aSkrw if (p == NULL) 2207c33fcabaSmillert return; 2208c33fcabaSmillert switch (*p) { 2209c33fcabaSmillert case 'd': 2210c33fcabaSmillert case 'D': 2211c33fcabaSmillert if (dgp == NULL) 2212c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2213c33fcabaSmillert else { 2214c33fcabaSmillert lp->d_secsize = dgp->d_secsize; 2215c33fcabaSmillert lp->d_nsectors = dgp->d_nsectors; 2216c33fcabaSmillert lp->d_ntracks = dgp->d_ntracks; 2217c33fcabaSmillert lp->d_ncylinders = dgp->d_ncylinders; 2218c33fcabaSmillert lp->d_secpercyl = dgp->d_secpercyl; 221934af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(dgp)); 2220c33fcabaSmillert } 2221c33fcabaSmillert break; 2222c33fcabaSmillert case 'u': 2223c33fcabaSmillert case 'U': 2224c33fcabaSmillert if (ugp == NULL) 2225c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2226c33fcabaSmillert else { 2227c33fcabaSmillert lp->d_secsize = ugp->d_secsize; 2228c33fcabaSmillert lp->d_nsectors = ugp->d_nsectors; 2229c33fcabaSmillert lp->d_ntracks = ugp->d_ntracks; 2230c33fcabaSmillert lp->d_ncylinders = ugp->d_ncylinders; 2231c33fcabaSmillert lp->d_secpercyl = ugp->d_secpercyl; 223234af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(ugp)); 2233c33fcabaSmillert if (dgp != NULL && ugp->d_secsize == dgp->d_secsize && 2234c33fcabaSmillert ugp->d_nsectors == dgp->d_nsectors && 2235c33fcabaSmillert ugp->d_ntracks == dgp->d_ntracks && 2236c33fcabaSmillert ugp->d_ncylinders == dgp->d_ncylinders && 2237c33fcabaSmillert ugp->d_secpercyl == dgp->d_secpercyl && 223834af67a3Sotto DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp)) 2239c33fcabaSmillert fputs("Note: user geometry is the same as disk " 2240c33fcabaSmillert "geometry.\n", stderr); 2241c33fcabaSmillert } 2242c33fcabaSmillert break; 2243c33fcabaSmillert default: 22449a36aa41Ssthen fputs("You must enter either 'd' or 'u'.\n", stderr); 2245c33fcabaSmillert break; 2246c33fcabaSmillert } 2247c33fcabaSmillert } 22489afbe9eeSmillert 22499afbe9eeSmillert void 22509fdcb4d6Skrw zero_partitions(struct disklabel *lp) 22519afbe9eeSmillert { 22529afbe9eeSmillert int i; 22539afbe9eeSmillert 2254b4ed6301Skrw for (i = 0; i < MAXPARTITIONS; i++) { 22559afbe9eeSmillert memset(&lp->d_partitions[i], 0, sizeof(struct partition)); 2256b4ed6301Skrw free(mountpoints[i]); 2257b4ed6301Skrw mountpoints[i] = NULL; 2258b4ed6301Skrw } 2259b4ed6301Skrw 226034af67a3Sotto DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); 22619afbe9eeSmillert } 226214192793Skrw 226314192793Skrw u_int64_t 226414192793Skrw max_partition_size(struct disklabel *lp, int partno) 226514192793Skrw { 226614192793Skrw struct partition *pp = &lp->d_partitions[partno]; 226714192793Skrw struct diskchunk *chunks; 226844ffe03bSotto u_int64_t maxsize = 0, offset; 226914192793Skrw int fstype, i; 227014192793Skrw 227114192793Skrw fstype = pp->p_fstype; 227214192793Skrw pp->p_fstype = FS_UNUSED; 227314192793Skrw chunks = free_chunks(lp); 227414192793Skrw pp->p_fstype = fstype; 227514192793Skrw 227614192793Skrw offset = DL_GETPOFFSET(pp); 227714192793Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 227814192793Skrw if (offset < chunks[i].start || offset >= chunks[i].stop) 227914192793Skrw continue; 228014192793Skrw maxsize = chunks[i].stop - offset; 228114192793Skrw break; 228214192793Skrw } 228314192793Skrw return (maxsize); 228414192793Skrw } 2285aff3f969Sotto 2286aff3f969Sotto void 2287eafadddfSkrw psize(u_int64_t sz, char unit, struct disklabel *lp) 2288aff3f969Sotto { 2289aff3f969Sotto double d = scale(sz, unit, lp); 2290aff3f969Sotto if (d < 0) 2291aff3f969Sotto printf("%llu", sz); 2292aff3f969Sotto else 2293aff3f969Sotto printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit); 2294aff3f969Sotto } 2295aff3f969Sotto 2296aff3f969Sotto void 22977ad973c1Skrw display_edit(struct disklabel *lp, char unit) 2298aff3f969Sotto { 22997ad973c1Skrw u_int64_t fr; 2300aff3f969Sotto int i; 2301aff3f969Sotto 23027ad973c1Skrw fr = editor_countfree(lp); 2303352d199bSkrw unit = canonical_unit(lp, unit); 2304aff3f969Sotto 2305aff3f969Sotto printf("OpenBSD area: "); 230659882f1dSkrw psize(starting_sector, 0, lp); 2307aff3f969Sotto printf("-"); 230859882f1dSkrw psize(ending_sector, 0, lp); 2309aff3f969Sotto printf("; size: "); 2310aff3f969Sotto psize(ending_sector - starting_sector, unit, lp); 2311aff3f969Sotto printf("; free: "); 2312aff3f969Sotto psize(fr, unit, lp); 2313aff3f969Sotto 2314aff3f969Sotto printf("\n# %16.16s %16.16s fstype [fsize bsize cpg]\n", 2315aff3f969Sotto "size", "offset"); 2316aff3f969Sotto for (i = 0; i < lp->d_npartitions; i++) 231734ae4198Skrw display_partition(stdout, lp, i, unit); 2318aff3f969Sotto } 2319a2c1f847Shenning 2320a2c1f847Shenning void 2321a2c1f847Shenning parse_autotable(char *filename) 2322a2c1f847Shenning { 2323a2c1f847Shenning FILE *cfile; 2324a2c1f847Shenning size_t len; 23250b857d83Shenning char *buf, *t; 2326a2c1f847Shenning uint idx = 0, pctsum = 0; 2327a2c1f847Shenning struct space_allocation *sa; 2328a2c1f847Shenning 2329a2c1f847Shenning if ((cfile = fopen(filename, "r")) == NULL) 2330a2c1f847Shenning err(1, "%s", filename); 2331a2c1f847Shenning if ((alloc_table = calloc(1, sizeof(struct alloc_table))) == NULL) 2332a2c1f847Shenning err(1, NULL); 2333f55524eaSsthen alloc_table_nitems = 1; 2334a2c1f847Shenning 2335a2c1f847Shenning while ((buf = fgetln(cfile, &len)) != NULL) { 2336a2c1f847Shenning if ((alloc_table[0].table = reallocarray(alloc_table[0].table, 2337a2c1f847Shenning idx + 1, sizeof(*sa))) == NULL) 2338a2c1f847Shenning err(1, NULL); 2339a2c1f847Shenning sa = &(alloc_table[0].table[idx]); 2340ee18520dSotto memset(sa, 0, sizeof(*sa)); 2341a2c1f847Shenning idx++; 2342a2c1f847Shenning 23430b857d83Shenning if ((sa->mp = get_token(&buf, &len)) == NULL || 2344a2c1f847Shenning (sa->mp[0] != '/' && strcmp(sa->mp, "swap"))) 2345a2c1f847Shenning errx(1, "%s: parse error on line %u", filename, idx); 23460b857d83Shenning if ((t = get_token(&buf, &len)) == NULL || 2347a2c1f847Shenning parse_sizerange(t, &sa->minsz, &sa->maxsz) == -1) 2348a2c1f847Shenning errx(1, "%s: parse error on line %u", filename, idx); 23490b857d83Shenning if ((t = get_token(&buf, &len)) != NULL && 2350a2c1f847Shenning parse_pct(t, &sa->rate) == -1) 2351a2c1f847Shenning errx(1, "%s: parse error on line %u", filename, idx); 2352a2c1f847Shenning if (sa->minsz > sa->maxsz) 2353a2c1f847Shenning errx(1, "%s: min size > max size on line %u", filename, 2354a2c1f847Shenning idx); 2355a2c1f847Shenning pctsum += sa->rate; 2356a2c1f847Shenning } 2357a2c1f847Shenning if (pctsum > 100) 2358a2c1f847Shenning errx(1, "%s: sum of extra space allocation > 100%%", filename); 2359a2c1f847Shenning alloc_table[0].sz = idx; 2360a2c1f847Shenning fclose(cfile); 2361a2c1f847Shenning } 2362a2c1f847Shenning 2363a2c1f847Shenning char * 2364a2c1f847Shenning get_token(char **s, size_t *len) 2365a2c1f847Shenning { 2366a2c1f847Shenning char *p, *r; 2367a2c1f847Shenning size_t tlen = 0; 2368a2c1f847Shenning 2369a2c1f847Shenning p = *s; 2370a2c1f847Shenning while (*len > 0 && !isspace((u_char)*s[0])) { 2371a2c1f847Shenning (*s)++; 2372a2c1f847Shenning (*len)--; 2373a2c1f847Shenning tlen++; 2374a2c1f847Shenning } 2375a2c1f847Shenning if (tlen == 0) 2376a2c1f847Shenning return (NULL); 2377a2c1f847Shenning 2378a2c1f847Shenning /* eat whitespace */ 2379a2c1f847Shenning while (*len > 0 && isspace((u_char)*s[0])) { 2380a2c1f847Shenning (*s)++; 2381a2c1f847Shenning (*len)--; 2382a2c1f847Shenning } 2383a2c1f847Shenning 2384104c1c3cSmillert if ((r = strndup(p, tlen)) == NULL) 2385a2c1f847Shenning err(1, NULL); 2386a2c1f847Shenning return (r); 2387a2c1f847Shenning } 2388a2c1f847Shenning 2389a2c1f847Shenning int 2390a2c1f847Shenning apply_unit(double val, u_char unit, u_int64_t *n) 2391a2c1f847Shenning { 2392a2c1f847Shenning u_int64_t factor = 1; 2393a2c1f847Shenning 2394a2c1f847Shenning switch (tolower(unit)) { 2395a2c1f847Shenning case 't': 2396a2c1f847Shenning factor *= 1024; 2397a2c1f847Shenning /* FALLTHROUGH */ 2398a2c1f847Shenning case 'g': 2399a2c1f847Shenning factor *= 1024; 2400a2c1f847Shenning /* FALLTHROUGH */ 2401a2c1f847Shenning case 'm': 2402a2c1f847Shenning factor *= 1024; 2403a2c1f847Shenning /* FALLTHROUGH */ 2404a2c1f847Shenning case 'k': 2405a2c1f847Shenning factor *= 1024; 2406a2c1f847Shenning break; 2407a2c1f847Shenning default: 2408a2c1f847Shenning return (-1); 2409a2c1f847Shenning } 2410a2c1f847Shenning 2411a2c1f847Shenning val *= factor / DEV_BSIZE; 2412a2c1f847Shenning if (val > ULLONG_MAX) 2413a2c1f847Shenning return (-1); 2414a2c1f847Shenning *n = val; 2415a2c1f847Shenning return (0); 2416a2c1f847Shenning } 2417a2c1f847Shenning 2418a2c1f847Shenning int 2419a2c1f847Shenning parse_sizespec(const char *buf, double *val, char **unit) 2420a2c1f847Shenning { 24215f6cf98aSkrw errno = 0; 2422a2c1f847Shenning *val = strtod(buf, unit); 24235f6cf98aSkrw if (errno == ERANGE || *val < 0 || *val > ULLONG_MAX) 24245f6cf98aSkrw return (-1); /* too big/small */ 24255f6cf98aSkrw if (*val == 0 && *unit == buf) 24265f6cf98aSkrw return (-1); /* No conversion performed. */ 2427a2c1f847Shenning if (*unit != NULL && *unit[0] == '\0') 2428a2c1f847Shenning *unit = NULL; 2429a2c1f847Shenning return (0); 2430a2c1f847Shenning } 2431a2c1f847Shenning 2432a2c1f847Shenning int 2433a2c1f847Shenning parse_sizerange(char *buf, u_int64_t *min, u_int64_t *max) 2434a2c1f847Shenning { 2435a2c1f847Shenning char *p, *unit1 = NULL, *unit2 = NULL; 2436a2c1f847Shenning double val1 = 0, val2 = 0; 2437a2c1f847Shenning 2438a2c1f847Shenning if ((p = strchr(buf, '-')) != NULL) { 2439a2c1f847Shenning p[0] = '\0'; 2440a2c1f847Shenning p++; 2441a2c1f847Shenning } 2442a2c1f847Shenning *max = 0; 2443a2c1f847Shenning if (parse_sizespec(buf, &val1, &unit1) == -1) 2444a2c1f847Shenning return (-1); 2445a2c1f847Shenning if (p != NULL && p[0] != '\0') { 2446a2c1f847Shenning if (p[0] == '*') 2447a2c1f847Shenning *max = -1; 2448a2c1f847Shenning else 2449a2c1f847Shenning if (parse_sizespec(p, &val2, &unit2) == -1) 2450a2c1f847Shenning return (-1); 2451a2c1f847Shenning } 2452a2c1f847Shenning if (unit1 == NULL && (unit1 = unit2) == NULL) 2453a2c1f847Shenning return (-1); 2454a2c1f847Shenning if (apply_unit(val1, unit1[0], min) == -1) 2455a2c1f847Shenning return (-1); 2456a2c1f847Shenning if (val2 > 0) { 2457a2c1f847Shenning if (apply_unit(val2, unit2[0], max) == -1) 2458a2c1f847Shenning return (-1); 2459a2c1f847Shenning } else 2460a2c1f847Shenning if (*max == 0) 2461a2c1f847Shenning *max = *min; 2462a2c1f847Shenning free(buf); 2463a2c1f847Shenning return (0); 2464a2c1f847Shenning } 2465a2c1f847Shenning 2466a2c1f847Shenning int 2467a2c1f847Shenning parse_pct(char *buf, int *n) 2468a2c1f847Shenning { 2469a2c1f847Shenning const char *errstr; 2470a2c1f847Shenning 2471a2c1f847Shenning if (buf[strlen(buf) - 1] == '%') 2472a2c1f847Shenning buf[strlen(buf) - 1] = '\0'; 2473a2c1f847Shenning *n = strtonum(buf, 0, 100, &errstr); 2474a2c1f847Shenning if (errstr) { 2475a2c1f847Shenning warnx("parse percent %s: %s", buf, errstr); 2476a2c1f847Shenning return (-1); 2477a2c1f847Shenning } 2478a2c1f847Shenning free(buf); 2479a2c1f847Shenning return (0); 2480a2c1f847Shenning } 248140b226e8Skrw 248240b226e8Skrw int 248340b226e8Skrw alignpartition(struct disklabel *lp, int partno, u_int64_t startalign, 248440b226e8Skrw u_int64_t stopalign, int flags) 248540b226e8Skrw { 248640b226e8Skrw struct partition *pp = &lp->d_partitions[partno]; 248740b226e8Skrw struct diskchunk *chunks; 248840b226e8Skrw u_int64_t start, stop, maxstop; 248940b226e8Skrw unsigned int i; 249040b226e8Skrw u_int8_t fstype; 249140b226e8Skrw 249240b226e8Skrw start = DL_GETPOFFSET(pp); 249340b226e8Skrw if ((flags & ROUND_OFFSET_UP) == ROUND_OFFSET_UP) 249440b226e8Skrw start = ((start + startalign - 1) / startalign) * startalign; 249540b226e8Skrw else if ((flags & ROUND_OFFSET_DOWN) == ROUND_OFFSET_DOWN) 249640b226e8Skrw start = (start / startalign) * startalign; 249740b226e8Skrw 249840b226e8Skrw /* Find the chunk that contains 'start'. */ 249940b226e8Skrw fstype = pp->p_fstype; 250040b226e8Skrw pp->p_fstype = FS_UNUSED; 250140b226e8Skrw chunks = free_chunks(lp); 250240b226e8Skrw pp->p_fstype = fstype; 250340b226e8Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 250440b226e8Skrw if (start >= chunks[i].start && start < chunks[i].stop) 250540b226e8Skrw break; 250640b226e8Skrw } 250740b226e8Skrw if (chunks[i].stop == 0) { 2508aef735d2Skrw fprintf(stderr, "'%c' aligned offset %llu lies outside " 2509aef735d2Skrw "the OpenBSD bounds or inside another partition\n", 2510aef735d2Skrw 'a' + partno, start); 251140b226e8Skrw return (1); 251240b226e8Skrw } 251340b226e8Skrw 251440b226e8Skrw /* Calculate the new 'stop' sector, the sector after the partition. */ 2515aef735d2Skrw if ((flags & ROUND_SIZE_OVERLAP) == 0) 2516aef735d2Skrw maxstop = (chunks[i].stop / stopalign) * stopalign; 2517aef735d2Skrw else 2518aef735d2Skrw maxstop = (ending_sector / stopalign) * stopalign; 2519aef735d2Skrw 252040b226e8Skrw stop = DL_GETPOFFSET(pp) + DL_GETPSIZE(pp); 252140b226e8Skrw if ((flags & ROUND_SIZE_UP) == ROUND_SIZE_UP) 252240b226e8Skrw stop = ((stop + stopalign - 1) / stopalign) * stopalign; 252340b226e8Skrw else if ((flags & ROUND_SIZE_DOWN) == ROUND_SIZE_DOWN) 252440b226e8Skrw stop = (stop / stopalign) * stopalign; 2525aef735d2Skrw if (stop > maxstop) 252640b226e8Skrw stop = maxstop; 252740b226e8Skrw 2528aef735d2Skrw if (stop <= start) { 2529aef735d2Skrw fprintf(stderr, "'%c' aligned size <= 0\n", 'a' + partno); 2530aef735d2Skrw return (1); 2531aef735d2Skrw } 2532aef735d2Skrw 253340b226e8Skrw if (start != DL_GETPOFFSET(pp)) 253440b226e8Skrw DL_SETPOFFSET(pp, start); 2535aef735d2Skrw if (stop != DL_GETPOFFSET(pp) + DL_GETPSIZE(pp)) 253640b226e8Skrw DL_SETPSIZE(pp, stop - start); 253740b226e8Skrw 253840b226e8Skrw return (0); 253940b226e8Skrw } 2540