1*c88f83bdSotto /* $OpenBSD: editor.c,v 1.231 2010/04/04 14:12:12 otto Exp $ */ 26fe57b42Smillert 36fe57b42Smillert /* 42d8451b0Smillert * Copyright (c) 1997-2000 Todd C. Miller <Todd.Miller@courtesan.com> 56fe57b42Smillert * 606f01696Smillert * Permission to use, copy, modify, and distribute this software for any 706f01696Smillert * purpose with or without fee is hereby granted, provided that the above 806f01696Smillert * copyright notice and this permission notice appear in all copies. 96fe57b42Smillert * 10328f1f07Smillert * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11328f1f07Smillert * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12328f1f07Smillert * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13328f1f07Smillert * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14328f1f07Smillert * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15328f1f07Smillert * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16328f1f07Smillert * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 176fe57b42Smillert */ 186fe57b42Smillert 196fe57b42Smillert #include <sys/types.h> 206fe57b42Smillert #include <sys/param.h> 21c33fcabaSmillert #include <sys/stat.h> 22c33fcabaSmillert #include <sys/ioctl.h> 238dde8bb6Sotto #include <sys/sysctl.h> 246fe57b42Smillert #define DKTYPENAMES 256fe57b42Smillert #include <sys/disklabel.h> 266fe57b42Smillert 276fe57b42Smillert #include <ufs/ffs/fs.h> 286fe57b42Smillert 296fe57b42Smillert #include <ctype.h> 306fe57b42Smillert #include <err.h> 316fe57b42Smillert #include <errno.h> 326fe57b42Smillert #include <string.h> 33803ff7d5Smillert #include <libgen.h> 346fe57b42Smillert #include <stdio.h> 356fe57b42Smillert #include <stdlib.h> 366fe57b42Smillert #include <unistd.h> 376fe57b42Smillert 38f21a098bSotto #include "extern.h" 394793b14cSmillert #include "pathnames.h" 404793b14cSmillert 416fe57b42Smillert /* flags for getuint() */ 426fe57b42Smillert #define DO_CONVERSIONS 0x00000001 436fe57b42Smillert #define DO_ROUNDING 0x00000002 446fe57b42Smillert 45f98aebd4Smillert #ifndef NUMBOOT 46f98aebd4Smillert #define NUMBOOT 0 47f98aebd4Smillert #endif 48f98aebd4Smillert 4996a888c6Smillert /* structure to describe a portion of a disk */ 5096a888c6Smillert struct diskchunk { 511e0ad43cSotto u_int64_t start; 521e0ad43cSotto u_int64_t stop; 5396a888c6Smillert }; 5496a888c6Smillert 553f843443Smillert /* used when sorting mountpoints in mpsave() */ 563f843443Smillert struct mountinfo { 573f843443Smillert char *mountpoint; 583f843443Smillert int partno; 593f843443Smillert }; 603f843443Smillert 61557f712bSkrw /* used when allocating all space according to recommendations */ 62557f712bSkrw 63557f712bSkrw struct space_allocation { 645f3e1104Skrw daddr64_t minsz; /* starts as blocks, xlated to sectors. */ 655f3e1104Skrw daddr64_t maxsz; /* starts as blocks, xlated to sectors. */ 66557f712bSkrw int rate; /* % of extra space to use */ 67557f712bSkrw char *mp; 68557f712bSkrw }; 69557f712bSkrw 708dde8bb6Sotto /* entries for swap and var are changed by editor_allocspace() */ 718dde8bb6Sotto const struct space_allocation alloc_big[] = { 7292adb55fSderaadt { MEG(80), GIG(1), 5, "/" }, 738dde8bb6Sotto { MEG(80), MEG(256), 5, "swap" }, 744ab111d2Sderaadt { MEG(120), GIG(4), 8, "/tmp" }, 7592adb55fSderaadt { MEG(80), GIG(4), 13, "/var" }, 7621a0d117Sderaadt { MEG(900), GIG(2), 5, "/usr" }, 7792adb55fSderaadt { MEG(512), GIG(1), 3, "/usr/X11R6" }, 7892adb55fSderaadt { GIG(2), GIG(6), 5, "/usr/local" }, 7992adb55fSderaadt { GIG(1), GIG(2), 3, "/usr/src" }, 8092adb55fSderaadt { GIG(1), GIG(2), 3, "/usr/obj" }, 8121a0d117Sderaadt { GIG(1), GIG(300), 50, "/home" } 824ab111d2Sderaadt /* Anything beyond this leave for the user to decide */ 838dde8bb6Sotto }; 848dde8bb6Sotto 858dde8bb6Sotto const struct space_allocation alloc_medium[] = { 86905e8239Sderaadt { MEG(800), GIG(2), 5, "/" }, 878dde8bb6Sotto { MEG(80), MEG(256), 10, "swap" }, 88905e8239Sderaadt { MEG(900), GIG(3), 78, "/usr" }, 89905e8239Sderaadt { MEG(256), GIG(2), 7, "/home" } 908dde8bb6Sotto }; 918dde8bb6Sotto 928dde8bb6Sotto const struct space_allocation alloc_small[] = { 9392adb55fSderaadt { MEG(700), GIG(4), 95, "/" }, 948dde8bb6Sotto { MEG(1), MEG(256), 5, "swap" } 958dde8bb6Sotto }; 968dde8bb6Sotto 978dde8bb6Sotto const struct space_allocation alloc_stupid[] = { 988dde8bb6Sotto { MEG(1), MEG(2048), 100, "/" } 998dde8bb6Sotto }; 1008dde8bb6Sotto 101b2813ff1Sderaadt #ifndef nitems 102b2813ff1Sderaadt #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 103b2813ff1Sderaadt #endif 104b2813ff1Sderaadt 1058a862940Sderaadt const struct { 1068a862940Sderaadt const struct space_allocation *table; 1078a862940Sderaadt int sz; 1088a862940Sderaadt } alloc_table[] = { 1098dde8bb6Sotto { alloc_big, nitems(alloc_big) }, 1108dde8bb6Sotto { alloc_medium, nitems(alloc_medium) }, 1118dde8bb6Sotto { alloc_small, nitems(alloc_small) }, 1128dde8bb6Sotto { alloc_stupid, nitems(alloc_stupid) } 113557f712bSkrw }; 114557f712bSkrw 1159fdcb4d6Skrw void edit_parms(struct disklabel *); 1166aaa4aabSotto void editor_resize(struct disklabel *, char *); 11734ae4198Skrw void editor_add(struct disklabel *, char *); 1189fdcb4d6Skrw void editor_change(struct disklabel *, char *); 1199fdcb4d6Skrw u_int64_t editor_countfree(struct disklabel *); 12034ae4198Skrw void editor_delete(struct disklabel *, char *); 121c72b5b24Smillert void editor_help(char *); 12234ae4198Skrw void editor_modify(struct disklabel *, char *); 12334ae4198Skrw void editor_name(struct disklabel *, char *); 124c72b5b24Smillert char *getstring(char *, char *, char *); 125dea75673Skrw u_int64_t getuint(struct disklabel *, char *, char *, u_int64_t, u_int64_t, u_int64_t, int); 1261f0f871dSkrw int has_overlap(struct disklabel *); 127c72b5b24Smillert int partition_cmp(const void *, const void *); 1280fbd3c97Skrw struct partition **sort_partitions(struct disklabel *); 129c72b5b24Smillert void getdisktype(struct disklabel *, char *, char *); 13087023ed9Skrw void find_bounds(struct disklabel *); 1319fdcb4d6Skrw void set_bounds(struct disklabel *); 132c72b5b24Smillert struct diskchunk *free_chunks(struct disklabel *); 1334f3bbbf0Skrw void mpcopy(char **, char **); 134c72b5b24Smillert int micmp(const void *, const void *); 135c72b5b24Smillert int mpequal(char **, char **); 136c72b5b24Smillert int get_bsize(struct disklabel *, int); 137c72b5b24Smillert int get_fsize(struct disklabel *, int); 138c72b5b24Smillert int get_fstype(struct disklabel *, int); 13934ae4198Skrw int get_mp(struct disklabel *, int); 140604d3bdeSkrw int get_offset(struct disklabel *, int); 1419fdcb4d6Skrw int get_size(struct disklabel *, int); 14287023ed9Skrw void get_geometry(int, struct disklabel **); 14387023ed9Skrw void set_geometry(struct disklabel *, struct disklabel *, struct disklabel *, 14487023ed9Skrw char *); 1459fdcb4d6Skrw void zero_partitions(struct disklabel *); 14614192793Skrw u_int64_t max_partition_size(struct disklabel *, int); 14734ae4198Skrw void display_edit(struct disklabel *, char, u_int64_t); 14896a888c6Smillert 1491e0ad43cSotto static u_int64_t starting_sector; 1501e0ad43cSotto static u_int64_t ending_sector; 1512d8451b0Smillert static int expert; 152fc6e9c48Sotto static int overlap; 1536fe57b42Smillert 1546fe57b42Smillert /* 1554d4a335eSkrw * Simple partition editor. 1566fe57b42Smillert */ 1576fe57b42Smillert int 15834ae4198Skrw editor(struct disklabel *lp, int f) 1596fe57b42Smillert { 1604f3bbbf0Skrw struct disklabel origlabel, lastlabel, tmplabel, label = *lp; 1617e28fb0fSderaadt struct disklabel *disk_geop = NULL; 16296a888c6Smillert struct partition *pp; 1636fe57b42Smillert FILE *fp; 1646fe57b42Smillert char buf[BUFSIZ], *cmd, *arg; 16534ae4198Skrw char **omountpoints = NULL; 1664f3bbbf0Skrw char **origmountpoints = NULL, **tmpmountpoints = NULL; 1677e28fb0fSderaadt int i, error = 0; 168bd6726faSmillert 169bd6726faSmillert /* Alloc and init mount point info */ 17034ae4198Skrw if (!(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 1714f3bbbf0Skrw !(origmountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 172bd6726faSmillert !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *)))) 173bd6726faSmillert errx(4, "out of memory"); 1746fe57b42Smillert 17596a888c6Smillert /* Don't allow disk type of "unknown" */ 17634ae4198Skrw getdisktype(&label, "You need to specify a type for this disk.", specname); 1776fe57b42Smillert 17887023ed9Skrw /* Get the on-disk geometries if possible */ 17987023ed9Skrw get_geometry(f, &disk_geop); 180c33fcabaSmillert 181d09f3941Smillert /* How big is the OpenBSD portion of the disk? */ 18287023ed9Skrw find_bounds(&label); 183d09f3941Smillert 18496a888c6Smillert /* Make sure there is no partition overlap. */ 1851f0f871dSkrw if (has_overlap(&label)) 1866fe57b42Smillert errx(1, "can't run when there is partition overlap."); 1876fe57b42Smillert 18896a888c6Smillert /* If we don't have a 'c' partition, create one. */ 189d09f3941Smillert pp = &label.d_partitions[RAW_PART]; 1901e0ad43cSotto if (label.d_npartitions < 3 || DL_GETPSIZE(pp) == 0) { 19196a888c6Smillert puts("No 'c' partition found, adding one that spans the disk."); 19296a888c6Smillert if (label.d_npartitions < 3) 19396a888c6Smillert label.d_npartitions = 3; 19434af67a3Sotto DL_SETPOFFSET(pp, 0); 19534af67a3Sotto DL_SETPSIZE(pp, DL_GETDSIZE(&label)); 19696a888c6Smillert pp->p_fstype = FS_UNUSED; 197ddfcbf38Sotto pp->p_fragblock = pp->p_cpg = 0; 19896a888c6Smillert } 1990f820bbbSmillert 200fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 201fc1a4cc6Sderaadt if (label.d_flags & D_VENDOR) { 202fc1a4cc6Sderaadt puts("This platform requires that partition offsets/sizes " 203fc1a4cc6Sderaadt "be on cylinder boundaries.\n" 204fc1a4cc6Sderaadt "Partition offsets/sizes will be rounded to the " 205fc1a4cc6Sderaadt "nearest cylinder automatically."); 206fc1a4cc6Sderaadt } 2076fe57b42Smillert #endif 2086fe57b42Smillert 209bd6726faSmillert /* Set d_bbsize and d_sbsize as necessary */ 21055403f76Smillert if (label.d_bbsize == 0) 21155403f76Smillert label.d_bbsize = BBSIZE; 21255403f76Smillert if (label.d_sbsize == 0) 21355403f76Smillert label.d_sbsize = SBSIZE; 214f98aebd4Smillert 215440b1d70Smillert /* Interleave must be >= 1 */ 216440b1d70Smillert if (label.d_interleave == 0) 217440b1d70Smillert label.d_interleave = 1; 218440b1d70Smillert 21993160b9bSkrw /* Save the (U|u)ndo labels and mountpoints. */ 22093160b9bSkrw mpcopy(origmountpoints, mountpoints); 2214f3bbbf0Skrw origlabel = label; 2226fe57b42Smillert lastlabel = label; 22334ae4198Skrw 22434ae4198Skrw puts("Label editor (enter '?' for help at any prompt)"); 2256fe57b42Smillert for (;;) { 2266fe57b42Smillert fputs("> ", stdout); 2276e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 2286e0becc5Smillert putchar('\n'); 2296e0becc5Smillert buf[0] = 'q'; 2306e0becc5Smillert buf[1] = '\0'; 2316e0becc5Smillert } 232260513deSmillert if ((cmd = strtok(buf, " \t\r\n")) == NULL) 233260513deSmillert continue; 234260513deSmillert arg = strtok(NULL, " \t\r\n"); 2356fe57b42Smillert 2364f3bbbf0Skrw if ((*cmd != 'u') && (*cmd != 'U')) { 2374f3bbbf0Skrw /* 2384f3bbbf0Skrw * Save undo info in case the command tries to make 2394f3bbbf0Skrw * changes but decides not to. 2404f3bbbf0Skrw */ 2414f3bbbf0Skrw tmplabel = lastlabel; 2424f3bbbf0Skrw lastlabel = label; 2434f3bbbf0Skrw mpcopy(tmpmountpoints, omountpoints); 2444f3bbbf0Skrw mpcopy(omountpoints, mountpoints); 2454f3bbbf0Skrw } 2466fe57b42Smillert 2474f3bbbf0Skrw switch (*cmd) { 2486fe57b42Smillert case '?': 249ea37abd3Sderaadt case 'h': 250617e6e4aSmillert editor_help(arg ? arg : ""); 2516fe57b42Smillert break; 2526fe57b42Smillert 253557f712bSkrw case 'A': 254ab20a3eaSkrw if (ioctl(f, DIOCGPDINFO, &label) == 0) { 255ab20a3eaSkrw aflag = 1; 25634ae4198Skrw editor_allocspace(&label); 257ab20a3eaSkrw } else 25834ae4198Skrw label = lastlabel; 259557f712bSkrw break; 2606fe57b42Smillert case 'a': 26134ae4198Skrw editor_add(&label, arg); 26296a888c6Smillert break; 26396a888c6Smillert 26496a888c6Smillert case 'b': 2659fdcb4d6Skrw set_bounds(&label); 2666fe57b42Smillert break; 2676fe57b42Smillert 2686fe57b42Smillert case 'c': 2699fdcb4d6Skrw editor_change(&label, arg); 2706fe57b42Smillert break; 2716fe57b42Smillert 2729afbe9eeSmillert case 'D': 27393160b9bSkrw if (ioctl(f, DIOCGPDINFO, &label) == 0) { 27471bba4ecSkrw dflag = 1; 27593160b9bSkrw for (i=0; i<MAXPARTITIONS; i++) { 27693160b9bSkrw free(mountpoints[i]); 27793160b9bSkrw mountpoints[i] = NULL; 27893160b9bSkrw } 27993160b9bSkrw } else 280cdd7eb76Smillert warn("unable to get default partition table"); 2819afbe9eeSmillert break; 2829afbe9eeSmillert 2836fe57b42Smillert case 'd': 28434ae4198Skrw editor_delete(&label, arg); 2856fe57b42Smillert break; 2866fe57b42Smillert 2879afbe9eeSmillert case 'e': 2889fdcb4d6Skrw edit_parms(&label); 2899afbe9eeSmillert break; 2909afbe9eeSmillert 291c33fcabaSmillert case 'g': 29287023ed9Skrw set_geometry(&label, disk_geop, lp, arg); 293c33fcabaSmillert break; 294c33fcabaSmillert 2956fe57b42Smillert case 'm': 29634ae4198Skrw editor_modify(&label, arg); 297bd6726faSmillert break; 298bd6726faSmillert 299bd6726faSmillert case 'n': 3005c79e1cfSkrw if (!fstabfile) { 301bd6726faSmillert fputs("This option is not valid when run " 30284d0bb16Sderaadt "without the -f flag.\n", stderr); 303bd6726faSmillert break; 304bd6726faSmillert } 30534ae4198Skrw editor_name(&label, arg); 3066fe57b42Smillert break; 3076fe57b42Smillert 3086fe57b42Smillert case 'p': 30934ae4198Skrw display_edit(&label, arg ? *arg : 0, editor_countfree(&label)); 3106fe57b42Smillert break; 3116fe57b42Smillert 312aff3f969Sotto case 'l': 31334ae4198Skrw display(stdout, &label, arg ? *arg : 0, 0); 314aff3f969Sotto break; 315aff3f969Sotto 316508086e9Smillert case 'M': { 317508086e9Smillert sig_t opipe = signal(SIGPIPE, SIG_IGN); 31845decb36Sderaadt char *pager, *comm = NULL; 319e7936562Sderaadt extern const u_char manpage[]; 32008f8e31fSotto extern const int manpage_sz; 3215d12b01bSderaadt 322489bd112Spjanzen if ((pager = getenv("PAGER")) == NULL || *pager == '\0') 323508086e9Smillert pager = _PATH_LESS; 32408f8e31fSotto 32545decb36Sderaadt if (asprintf(&comm, "gunzip -qc|%s", pager) != -1 && 32645decb36Sderaadt (fp = popen(comm, "w")) != NULL) { 32708f8e31fSotto (void) fwrite(manpage, manpage_sz, 1, fp); 3285d12b01bSderaadt pclose(fp); 329508086e9Smillert } else 330508086e9Smillert warn("unable to execute %s", pager); 331508086e9Smillert 33245decb36Sderaadt free(comm); 333508086e9Smillert (void)signal(SIGPIPE, opipe); 3345d12b01bSderaadt break; 335508086e9Smillert } 3365d12b01bSderaadt 3376fe57b42Smillert case 'q': 33869220492Smillert if (donothing) { 33969220492Smillert puts("In no change mode, not writing label."); 3407e28fb0fSderaadt goto done; 34169220492Smillert } 342bd6726faSmillert /* Save mountpoint info if there is any. */ 34334ae4198Skrw mpsave(&label); 34493160b9bSkrw 34571bba4ecSkrw /* 34693160b9bSkrw * If we haven't changed the original label, and it 34793160b9bSkrw * wasn't a default label or an auto-allocated label, 34893160b9bSkrw * there is no need to do anything before exiting. Note 34993160b9bSkrw * that 'w' will reset dflag and aflag to allow 'q' to 35093160b9bSkrw * exit without further questions. 35171bba4ecSkrw */ 352ab20a3eaSkrw if (!dflag && !aflag && 353ab20a3eaSkrw memcmp(lp, &label, sizeof(label)) == 0) { 354bd6726faSmillert puts("No label changes."); 3557e28fb0fSderaadt goto done; 3566fe57b42Smillert } 3576fe57b42Smillert do { 358d0e67762Smillert arg = getstring("Write new label?", 359d0e67762Smillert "Write the modified label to disk?", 360d0e67762Smillert "y"); 36196a888c6Smillert } while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n'); 36296a888c6Smillert if (arg && tolower(*arg) == 'y') { 363d0e67762Smillert if (writelabel(f, bootarea, &label) == 0) { 3646fe57b42Smillert *lp = label; 3657e28fb0fSderaadt goto done; 3666fe57b42Smillert } 367d0e67762Smillert warnx("unable to write label"); 368d0e67762Smillert } 3697e28fb0fSderaadt error = 1; 3707e28fb0fSderaadt goto done; 3716fe57b42Smillert /* NOTREACHED */ 3726fe57b42Smillert break; 3736fe57b42Smillert 3746aaa4aabSotto case 'R': 375fc6e9c48Sotto if (aflag && !overlap) 3766aaa4aabSotto editor_resize(&label, arg); 3776aaa4aabSotto else 3786aaa4aabSotto fputs("Resize only implemented for auto " 379fc6e9c48Sotto "allocated labels\n", stderr); 3806aaa4aabSotto break; 3816aaa4aabSotto 38225f9c360Skrw case 'r': { 38325f9c360Skrw struct diskchunk *chunks; 38425f9c360Skrw int i; 3859fdcb4d6Skrw /* Display free space. */ 38625f9c360Skrw chunks = free_chunks(&label); 38725f9c360Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; 38825f9c360Skrw i++) 38925f9c360Skrw fprintf(stderr, "Free sectors: %16llu - %16llu " 39025f9c360Skrw "(%16llu)\n", 39125f9c360Skrw chunks[i].start, chunks[i].stop - 1, 39225f9c360Skrw chunks[i].stop - chunks[i].start); 39325f9c360Skrw fprintf(stderr, "Total free sectors: %llu.\n", 3949fdcb4d6Skrw editor_countfree(&label)); 395c0bdc608Smillert break; 39625f9c360Skrw } 397c0bdc608Smillert 3986fe57b42Smillert case 's': 3996fe57b42Smillert if (arg == NULL) { 400c33fcabaSmillert arg = getstring("Filename", 4016fe57b42Smillert "Name of the file to save label into.", 4026fe57b42Smillert NULL); 403e97229a3Scnst if (arg == NULL || *arg == '\0') 4046fe57b42Smillert break; 4056fe57b42Smillert } 4066fe57b42Smillert if ((fp = fopen(arg, "w")) == NULL) { 4076fe57b42Smillert warn("cannot open %s", arg); 4086fe57b42Smillert } else { 40934ae4198Skrw display(fp, &label, 0, 1); 4106fe57b42Smillert (void)fclose(fp); 4116fe57b42Smillert } 4126fe57b42Smillert break; 4136fe57b42Smillert 4144f3bbbf0Skrw case 'U': 41593160b9bSkrw /* 41693160b9bSkrw * If we allow 'U' repeatedly, information would be lost. This way 41793160b9bSkrw * multiple 'U's followed by 'u' would undo the 'U's. 41893160b9bSkrw */ 41993160b9bSkrw if (memcmp(&label, &origlabel, sizeof(label)) || 42093160b9bSkrw !mpequal(mountpoints, origmountpoints)) { 4214f3bbbf0Skrw tmplabel = label; 4224f3bbbf0Skrw label = origlabel; 4234f3bbbf0Skrw lastlabel = tmplabel; 4244f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 4254f3bbbf0Skrw mpcopy(mountpoints, origmountpoints); 4264f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4274f3bbbf0Skrw } 42893160b9bSkrw puts("Original label and mount points restored."); 4294f3bbbf0Skrw break; 4304f3bbbf0Skrw 4316fe57b42Smillert case 'u': 4326fe57b42Smillert tmplabel = label; 4336fe57b42Smillert label = lastlabel; 4346fe57b42Smillert lastlabel = tmplabel; 4354f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 436bd6726faSmillert mpcopy(mountpoints, omountpoints); 4374f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4386fe57b42Smillert puts("Last change undone."); 4396fe57b42Smillert break; 4406fe57b42Smillert 441040947cfSmillert case 'w': 442bd6726faSmillert if (donothing) { 443040947cfSmillert puts("In no change mode, not writing label."); 444bd6726faSmillert break; 445bd6726faSmillert } 44693160b9bSkrw 44741f684b9Skrw /* Write label to disk. */ 44841f684b9Skrw if (writelabel(f, bootarea, &label) != 0) 449040947cfSmillert warnx("unable to write label"); 45071bba4ecSkrw else { 451ab20a3eaSkrw dflag = aflag = 0; 4525af08e9cSmillert *lp = label; 45371bba4ecSkrw } 454040947cfSmillert break; 455040947cfSmillert 4562d8451b0Smillert case 'X': 4572d8451b0Smillert expert = !expert; 4582d8451b0Smillert printf("%s expert mode\n", expert ? "Entering" : 4592d8451b0Smillert "Exiting"); 4602d8451b0Smillert break; 4612d8451b0Smillert 4626fe57b42Smillert case 'x': 4637e28fb0fSderaadt goto done; 4646fe57b42Smillert break; 4656fe57b42Smillert 4669afbe9eeSmillert case 'z': 4679fdcb4d6Skrw zero_partitions(&label); 4686fe57b42Smillert break; 4696fe57b42Smillert 4709afbe9eeSmillert case '\n': 4716fe57b42Smillert break; 4726fe57b42Smillert 4736fe57b42Smillert default: 4746fe57b42Smillert printf("Unknown option: %c ('?' for help)\n", *cmd); 4756fe57b42Smillert break; 4766fe57b42Smillert } 4774f3bbbf0Skrw 4784f3bbbf0Skrw /* 4794f3bbbf0Skrw * If no changes were made to label or mountpoints, then 4804f3bbbf0Skrw * restore undo info. 4814f3bbbf0Skrw */ 4824f3bbbf0Skrw if (memcmp(&label, &lastlabel, sizeof(label)) == 0 && 48393160b9bSkrw (mpequal(mountpoints, omountpoints))) { 4844f3bbbf0Skrw lastlabel = tmplabel; 4854f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4864f3bbbf0Skrw } 4876fe57b42Smillert } 4887e28fb0fSderaadt done: 4897e28fb0fSderaadt free(omountpoints); 4907e28fb0fSderaadt free(origmountpoints); 4917e28fb0fSderaadt free(tmpmountpoints); 4927e28fb0fSderaadt if (disk_geop) 4937e28fb0fSderaadt free(disk_geop); 4947e28fb0fSderaadt return(error); 4956fe57b42Smillert } 4966fe57b42Smillert 4978dde8bb6Sotto int64_t 4988dde8bb6Sotto getphysmem(void) 4998dde8bb6Sotto { 5008dde8bb6Sotto int64_t physmem; 5018dde8bb6Sotto size_t sz = sizeof(physmem); 5028dde8bb6Sotto int mib[] = { CTL_HW, HW_PHYSMEM64 }; 5038dde8bb6Sotto if (sysctl(mib, 2, &physmem, &sz, NULL, (size_t)0) == -1) 5048dde8bb6Sotto errx(4, "can't get mem size"); 5058dde8bb6Sotto return physmem; 5068dde8bb6Sotto } 5078dde8bb6Sotto 5086fe57b42Smillert /* 509557f712bSkrw * Allocate all disk space according to standard recommendations for a 510557f712bSkrw * root disk. 511557f712bSkrw */ 512557f712bSkrw void 5138dde8bb6Sotto editor_allocspace(struct disklabel *lp_org) 514557f712bSkrw { 5158dde8bb6Sotto struct disklabel *lp, label; 5168dde8bb6Sotto struct space_allocation *alloc; 51734ae4198Skrw struct space_allocation *ap; 518557f712bSkrw struct partition *pp; 51934ae4198Skrw struct diskchunk *chunks; 52034ae4198Skrw daddr64_t secs, chunkstart, chunksize, cylsecs, totsecs, xtrasecs; 52134ae4198Skrw char **partmp; 5226e312d52Sotto int i, j, lastalloc, index = 0, fragsize; 5238dde8bb6Sotto int64_t physmem; 5248dde8bb6Sotto 52534ae4198Skrw /* How big is the OpenBSD portion of the disk? */ 5268dde8bb6Sotto find_bounds(lp_org); 527557f712bSkrw 528fc6e9c48Sotto overlap = 0; 529fc6e9c48Sotto for (i = 0; i < MAXPARTITIONS; i++) { 530fc6e9c48Sotto daddr64_t psz, pstart, pend; 531fc6e9c48Sotto 532fc6e9c48Sotto pp = &lp_org->d_partitions[i]; 533fc6e9c48Sotto psz = DL_GETPSIZE(pp); 534fc6e9c48Sotto pstart = DL_GETPOFFSET(pp); 535fc6e9c48Sotto pend = pstart + psz; 536fc6e9c48Sotto if (i != RAW_PART && psz != 0 && 537fc6e9c48Sotto ((pstart >= starting_sector && pstart <= ending_sector) || 538fc6e9c48Sotto (pend > starting_sector && pend < ending_sector))) { 539fc6e9c48Sotto overlap = 1; 540fc6e9c48Sotto break; 541fc6e9c48Sotto } 542fc6e9c48Sotto } 543fc6e9c48Sotto 544fc6e9c48Sotto physmem = getphysmem() / lp_org->d_secsize; 545fc6e9c48Sotto 5468dde8bb6Sotto cylsecs = lp_org->d_secpercyl; 5478dde8bb6Sotto again: 5488dde8bb6Sotto lp = &label; 5493d98fc8cSkrw for (i=0; i<MAXPARTITIONS; i++) { 5503d98fc8cSkrw free(mountpoints[i]); 5513d98fc8cSkrw mountpoints[i] = NULL; 5523d98fc8cSkrw } 5538dde8bb6Sotto memcpy(lp, lp_org, sizeof(struct disklabel)); 5540a7398ceSderaadt lp->d_npartitions = MAXPARTITIONS; 5558dde8bb6Sotto lastalloc = alloc_table[index].sz; 5568dde8bb6Sotto alloc = malloc(lastalloc * sizeof(struct space_allocation)); 5578dde8bb6Sotto if (alloc == NULL) 5588dde8bb6Sotto errx(4, "out of memory"); 5598dde8bb6Sotto memcpy(alloc, alloc_table[index].table, 5608dde8bb6Sotto lastalloc * sizeof(struct space_allocation)); 5618dde8bb6Sotto 5628dde8bb6Sotto /* bump max swap based on phys mem, little physmem gets 2x swap */ 5638dde8bb6Sotto if (index == 0) { 5648dde8bb6Sotto if (physmem < 256LL * 1024 * 1024 / lp->d_secsize) 5658dde8bb6Sotto alloc[1].maxsz = 2 * physmem; 5668dde8bb6Sotto else 5678dde8bb6Sotto alloc[1].maxsz += physmem; 5688dde8bb6Sotto /* bump max /var to make room for 2 crash dumps */ 5698dde8bb6Sotto alloc[3].maxsz += 2 * physmem; 5708dde8bb6Sotto } 5718dde8bb6Sotto 57234ae4198Skrw xtrasecs = totsecs = editor_countfree(lp); 573557f712bSkrw 57434ae4198Skrw for (i = 0; i < lastalloc; i++) { 5755f3e1104Skrw alloc[i].minsz = DL_BLKTOSEC(lp, alloc[i].minsz); 5765f3e1104Skrw alloc[i].maxsz = DL_BLKTOSEC(lp, alloc[i].maxsz); 57734ae4198Skrw if (xtrasecs > alloc[i].minsz) 57834ae4198Skrw xtrasecs -= alloc[i].minsz; 57934ae4198Skrw else 58034ae4198Skrw xtrasecs = 0; 581557f712bSkrw } 582557f712bSkrw 58334ae4198Skrw for (i = 0; i < lastalloc; i++) { 58434ae4198Skrw /* Find next available partition. */ 58534ae4198Skrw for (j = 0; j < MAXPARTITIONS; j++) 58634ae4198Skrw if (DL_GETPSIZE(&lp->d_partitions[j]) == 0) 58734ae4198Skrw break; 58834ae4198Skrw if (j == MAXPARTITIONS) 58934ae4198Skrw return; 59034ae4198Skrw pp = &lp->d_partitions[j]; 59134ae4198Skrw partmp = &mountpoints[j]; 59234ae4198Skrw ap = &alloc[i]; 593557f712bSkrw 59434ae4198Skrw /* Figure out the size of the partition. */ 59534ae4198Skrw if (i == lastalloc - 1) { 59634ae4198Skrw if (totsecs > ap->maxsz) 59734ae4198Skrw secs = ap->maxsz; 598557f712bSkrw else 5995f3e1104Skrw secs = totsecs; 6001f5ea549Skrw #ifdef SUN_CYLCHECK 6011f5ea549Skrw goto cylinderalign; 6021f5ea549Skrw #endif 603557f712bSkrw } else { 60434ae4198Skrw secs = ap->minsz; 6055f3e1104Skrw if (xtrasecs > 0) 60634ae4198Skrw secs += (xtrasecs / 100) * ap->rate; 60734ae4198Skrw if (secs > ap->maxsz) 60834ae4198Skrw secs = ap->maxsz; 6091f5ea549Skrw #ifdef SUN_CYLCHECK 6101f5ea549Skrw cylinderalign: 6115f3e1104Skrw secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; 6121f5ea549Skrw #endif 6135f3e1104Skrw totsecs -= secs; 6141f5ea549Skrw #ifdef SUN_CYLCHECK 6155f3e1104Skrw while (totsecs < 0) { 6165f3e1104Skrw secs -= cylsecs; 6175f3e1104Skrw totsecs += cylsecs; 618557f712bSkrw } 6191f5ea549Skrw #endif 620557f712bSkrw } 62134ae4198Skrw 62234ae4198Skrw /* Find largest chunk of free space. */ 62334ae4198Skrw chunks = free_chunks(lp); 62434ae4198Skrw chunkstart = 0; 62534ae4198Skrw chunksize = 0; 62634ae4198Skrw for (j = 0; chunks[j].start != 0 || chunks[j].stop != 0; j++) 62734ae4198Skrw if ((chunks[j].stop - chunks[j].start) > chunksize) { 62834ae4198Skrw chunkstart = chunks[j].start; 62934ae4198Skrw chunksize = chunks[j].stop - chunks[j].start; 630557f712bSkrw } 63134ae4198Skrw #ifdef SUN_CYLCHECK 63234ae4198Skrw if (lp->d_flags & D_VENDOR) { 63334ae4198Skrw /* Align chunk to cylinder boundaries. */ 63434ae4198Skrw chunksize -= chunksize % cylsecs; 6356ab0bb66Skrw chunkstart = ((chunkstart + cylsecs - 1) / cylsecs) * 6366ab0bb66Skrw cylsecs; 63734ae4198Skrw } 63834ae4198Skrw #endif 63934ae4198Skrw /* See if partition can fit into chunk. */ 64034ae4198Skrw if (secs > chunksize) { 64134ae4198Skrw totsecs += secs - chunksize; 64234ae4198Skrw secs = chunksize; 64334ae4198Skrw } 64434ae4198Skrw if (secs < ap->minsz) { 6458dde8bb6Sotto /* It did not work out, try next strategy */ 6468dde8bb6Sotto free(alloc); 6478dde8bb6Sotto if (++index < nitems(alloc_table)) 6488dde8bb6Sotto goto again; 6498dde8bb6Sotto else 6508dde8bb6Sotto return; 651557f712bSkrw } 65234ae4198Skrw 65334ae4198Skrw /* Everything seems ok so configure the partition. */ 6545f3e1104Skrw DL_SETPSIZE(pp, secs); 65534ae4198Skrw DL_SETPOFFSET(pp, chunkstart); 6566e312d52Sotto fragsize = 2048; 657*c88f83bdSotto if (secs * lp->d_secsize > 128ULL * 1024 * 1024 * 1024) 658*c88f83bdSotto fragsize *= 2; 659*c88f83bdSotto if (secs * lp->d_secsize > 512ULL * 1024 * 1024 * 1024) 660*c88f83bdSotto fragsize *= 2; 661557f712bSkrw #if defined (__sparc__) && !defined(__sparc64__) 662557f712bSkrw /* can't boot from > 8k boot blocks */ 663557f712bSkrw pp->p_fragblock = 6646e312d52Sotto DISKLABELV1_FFS_FRAGBLOCK(i == 0 ? 1024 : fragsize, 8); 665557f712bSkrw #else 6666e312d52Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8); 667557f712bSkrw #endif 668557f712bSkrw pp->p_cpg = 1; 66934ae4198Skrw if (ap->mp[0] != '/') 67034ae4198Skrw pp->p_fstype = FS_SWAP; 67134ae4198Skrw else { 67234ae4198Skrw pp->p_fstype = FS_BSDFFS; 67334ae4198Skrw free(*partmp); 67434ae4198Skrw if ((*partmp = strdup(ap->mp)) == NULL) 675557f712bSkrw errx(4, "out of memory"); 676557f712bSkrw } 677557f712bSkrw } 678557f712bSkrw 6798dde8bb6Sotto free(alloc); 6808dde8bb6Sotto memcpy(lp_org, lp, sizeof(struct disklabel)); 681557f712bSkrw } 682557f712bSkrw 683557f712bSkrw /* 6846aaa4aabSotto * Resize a partition, moving all subsequent partitions 6856aaa4aabSotto */ 6866aaa4aabSotto void 6876aaa4aabSotto editor_resize(struct disklabel *lp, char *p) 6886aaa4aabSotto { 6896aaa4aabSotto struct disklabel label; 6906aaa4aabSotto struct partition *pp, *prev; 6916aaa4aabSotto daddr64_t secs, sz, off; 6926aaa4aabSotto #ifdef SUN_CYLCHECK 6936aaa4aabSotto daddr64_t cylsecs; 6946aaa4aabSotto #endif 6956aaa4aabSotto int partno, i; 6966aaa4aabSotto 6976aaa4aabSotto label = *lp; 6986aaa4aabSotto 6996aaa4aabSotto /* Change which partition? */ 7006aaa4aabSotto if (p == NULL) { 7016aaa4aabSotto p = getstring("partition to resize", 7026aaa4aabSotto "The letter of the partition to name, a - p.", NULL); 7036aaa4aabSotto } 7046aaa4aabSotto if (p == NULL) { 7056aaa4aabSotto fputs("Command aborted\n", stderr); 7066aaa4aabSotto return; 7076aaa4aabSotto } 7086aaa4aabSotto partno = p[0] - 'a'; 7096aaa4aabSotto if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 7106aaa4aabSotto fprintf(stderr, "Partition must be between 'a' and '%c' " 7116aaa4aabSotto "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 7126aaa4aabSotto return; 7136aaa4aabSotto } 7146aaa4aabSotto 7156aaa4aabSotto pp = &label.d_partitions[partno]; 716fc6e9c48Sotto sz = DL_GETPSIZE(pp); 717fc6e9c48Sotto if (sz == 0) { 718fc6e9c48Sotto fputs("No such partition\n", stderr); 719fc6e9c48Sotto return; 720fc6e9c48Sotto } 721fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) { 722fc6e9c48Sotto fputs("Cannot resize spoofed partition\n", stderr); 723fc6e9c48Sotto return; 724fc6e9c48Sotto } 7256aaa4aabSotto secs = getuint(lp, "resize", "amount to grow (+) or shrink (-)", 726fc6e9c48Sotto 0, editor_countfree(lp), 0, DO_CONVERSIONS); 7276aaa4aabSotto 728fc6e9c48Sotto if (secs == 0 || secs == -1) { 7296aaa4aabSotto fputs("Command aborted\n", stderr); 7306aaa4aabSotto return; 7316aaa4aabSotto } 7326aaa4aabSotto 7336aaa4aabSotto #ifdef SUN_CYLCHECK 7346aaa4aabSotto cylsecs = lp->d_secpercyl; 7356aaa4aabSotto if (secs > 0) 7366aaa4aabSotto secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; 7376aaa4aabSotto else 7386aaa4aabSotto secs = ((secs - cylsecs + 1) / cylsecs) * cylsecs; 7396aaa4aabSotto #endif 7406aaa4aabSotto if (DL_GETPOFFSET(pp) + sz + secs > ending_sector) { 7416aaa4aabSotto fputs("Amount too big\n", stderr); 7426aaa4aabSotto return; 7436aaa4aabSotto } 7446aaa4aabSotto if (sz + secs < 0) { 7456aaa4aabSotto fputs("Amount too small\n", stderr); 7466aaa4aabSotto return; 7476aaa4aabSotto } 7486aaa4aabSotto 7496aaa4aabSotto DL_SETPSIZE(pp, sz + secs); 7506aaa4aabSotto 7516aaa4aabSotto /* 7526aaa4aabSotto * Pack partitions above the resized partition, leaving unused 7536aaa4aabSotto * partions alone. 7546aaa4aabSotto */ 7556aaa4aabSotto prev = pp; 7566aaa4aabSotto for (i = partno + 1; i < MAXPARTITIONS; i++) { 7576aaa4aabSotto if (i == RAW_PART) 7586aaa4aabSotto continue; 759fc6e9c48Sotto pp = &label.d_partitions[i]; 760fc6e9c48Sotto if (pp->p_fstype != FS_BSDFFS && pp->p_fstype != FS_SWAP) 761fc6e9c48Sotto continue; 762fc6e9c48Sotto sz = DL_GETPSIZE(pp); 7636aaa4aabSotto if (sz == 0) 7646aaa4aabSotto continue; 7656aaa4aabSotto 7666aaa4aabSotto off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev); 7676aaa4aabSotto 7686aaa4aabSotto if (off < ending_sector) { 7696aaa4aabSotto DL_SETPOFFSET(pp, off); 7706aaa4aabSotto if (off + DL_GETPSIZE(pp) > ending_sector) { 7716aaa4aabSotto DL_SETPSIZE(pp, ending_sector - off); 7726aaa4aabSotto fprintf(stderr, 7736aaa4aabSotto "Partition %c shrunk to make room\n", 7746aaa4aabSotto i + 'a'); 7756aaa4aabSotto } 7766aaa4aabSotto } else { 7776aaa4aabSotto fputs("No room left for all partitions\n", stderr); 7786aaa4aabSotto return; 7796aaa4aabSotto } 7806aaa4aabSotto prev = pp; 7816aaa4aabSotto } 7826aaa4aabSotto *lp = label; 7836aaa4aabSotto } 7846aaa4aabSotto 7856aaa4aabSotto /* 7866fe57b42Smillert * Add a new partition. 7876fe57b42Smillert */ 7886fe57b42Smillert void 78934ae4198Skrw editor_add(struct disklabel *lp, char *p) 7906fe57b42Smillert { 79196a888c6Smillert struct partition *pp; 79296a888c6Smillert struct diskchunk *chunks; 7935caa08b2Skrw char buf[2]; 7946e312d52Sotto int i, partno, fragsize; 795f8ab7229Schl u_int64_t freesectors, new_offset, new_size; 7969fdcb4d6Skrw 7979fdcb4d6Skrw freesectors = editor_countfree(lp); 7986fe57b42Smillert 7996fe57b42Smillert /* XXX - prompt user to steal space from another partition instead */ 800fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 8019fdcb4d6Skrw if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) { 802fc1a4cc6Sderaadt fputs("No space left, you need to shrink a partition " 803fc1a4cc6Sderaadt "(need at least one full cylinder)\n", 804fc1a4cc6Sderaadt stderr); 805fc1a4cc6Sderaadt return; 806fc1a4cc6Sderaadt } 8078390cf28Smillert #endif 8089fdcb4d6Skrw if (freesectors == 0) { 8096fe57b42Smillert fputs("No space left, you need to shrink a partition\n", 8106fe57b42Smillert stderr); 8116fe57b42Smillert return; 8126fe57b42Smillert } 8136fe57b42Smillert 8145caa08b2Skrw if (p == NULL) { 8155caa08b2Skrw /* 8165caa08b2Skrw * Use the first unused partition that is not 'c' as the 8175caa08b2Skrw * default partition in the prompt string. 8185caa08b2Skrw */ 8195caa08b2Skrw pp = &lp->d_partitions[0]; 8205caa08b2Skrw buf[0] = buf[1] = '\0'; 8215caa08b2Skrw for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) { 8225caa08b2Skrw if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) { 8235caa08b2Skrw buf[0] = partno + 'a'; 8245caa08b2Skrw p = &buf[0]; 8256fe57b42Smillert break; 8266fe57b42Smillert } 8275caa08b2Skrw } 828c33fcabaSmillert p = getstring("partition", 8296fe57b42Smillert "The letter of the new partition, a - p.", p); 8306fe57b42Smillert } 8315caa08b2Skrw if (p == NULL) { 8325caa08b2Skrw fputs("Command aborted\n", stderr); 8335caa08b2Skrw return; 8345caa08b2Skrw } 8355caa08b2Skrw partno = p[0] - 'a'; 8365caa08b2Skrw if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) { 8375caa08b2Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 8385caa08b2Skrw "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1); 8395caa08b2Skrw return; 8405caa08b2Skrw } 8415caa08b2Skrw pp = &lp->d_partitions[partno]; 8425caa08b2Skrw 8435caa08b2Skrw if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) { 8445caa08b2Skrw fprintf(stderr, "Partition '%c' exists. Delete it first.\n", 8455caa08b2Skrw p[0]); 8465caa08b2Skrw return; 8476fe57b42Smillert } 84896a888c6Smillert 849caf41f96Skrw /* 850caf41f96Skrw * Increase d_npartitions if necessary. Ensure all new partitions are 851855d4e83Ssobrado * zero'ed to avoid inadvertent overlaps. 852caf41f96Skrw */ 853caf41f96Skrw for(; lp->d_npartitions <= partno; lp->d_npartitions++) 854caf41f96Skrw memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp)); 85596a888c6Smillert 85689f4601dSkrw /* Make sure selected partition is zero'd too. */ 85789f4601dSkrw memset(pp, 0, sizeof(*pp)); 85815c15d8aSkrw chunks = free_chunks(lp); 85915c15d8aSkrw 86015c15d8aSkrw /* 86115c15d8aSkrw * Since we know there's free space, there must be at least one 86215c15d8aSkrw * chunk. So find the largest chunk and assume we want to add the 86315c15d8aSkrw * partition in that free space. 86415c15d8aSkrw */ 86515c15d8aSkrw new_size = new_offset = 0; 86615c15d8aSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 86715c15d8aSkrw if (chunks[i].stop - chunks[i].start > new_size) { 86815c15d8aSkrw new_size = chunks[i].stop - chunks[i].start; 86915c15d8aSkrw new_offset = chunks[i].start; 87015c15d8aSkrw } 87115c15d8aSkrw } 8721e0ad43cSotto DL_SETPSIZE(pp, new_size); 8731e0ad43cSotto DL_SETPOFFSET(pp, new_offset); 87496a888c6Smillert pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS; 875*c88f83bdSotto pp->p_cpg = 1; 876*c88f83bdSotto 877*c88f83bdSotto if (get_offset(lp, partno) == 0 && 878*c88f83bdSotto get_size(lp, partno) == 0) { 8796e312d52Sotto fragsize = 2048; 880*c88f83bdSotto new_size = DL_GETPSIZE(pp) * lp->d_secsize; 881*c88f83bdSotto if (new_size > 128ULL * 1024 * 1024 * 1024) 882*c88f83bdSotto fragsize *= 2; 883*c88f83bdSotto if (new_size > 512ULL * 1024 * 1024 * 1024) 884*c88f83bdSotto fragsize *= 2; 8854a8b9208Stedu #if defined (__sparc__) && !defined(__sparc64__) 886d98d4df7Stedu /* can't boot from > 8k boot blocks */ 887ddfcbf38Sotto pp->p_fragblock = 8886e312d52Sotto DISKLABELV1_FFS_FRAGBLOCK(partno == 0 ? 1024 : fragsize, 8); 889d98d4df7Stedu #else 8906e312d52Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8); 891d98d4df7Stedu #endif 892*c88f83bdSotto if (get_fstype(lp, partno) == 0 && 89334ae4198Skrw get_mp(lp, partno) == 0 && 894a4c87e64Skrw get_fsize(lp, partno) == 0 && 895a4c87e64Skrw get_bsize(lp, partno) == 0) 89696a888c6Smillert return; 897*c88f83bdSotto } 898a4c87e64Skrw /* Bailed out at some point, so effectively delete the partition. */ 899a4c87e64Skrw DL_SETPSIZE(pp, 0); 9006fe57b42Smillert } 9016fe57b42Smillert 9026fe57b42Smillert /* 903bd6726faSmillert * Set the mountpoint of an existing partition ('name'). 904bd6726faSmillert */ 905bd6726faSmillert void 90634ae4198Skrw editor_name(struct disklabel *lp, char *p) 907bd6726faSmillert { 908bd6726faSmillert struct partition *pp; 909bd6726faSmillert int partno; 910bd6726faSmillert 911bd6726faSmillert /* Change which partition? */ 912bd6726faSmillert if (p == NULL) { 913c33fcabaSmillert p = getstring("partition to name", 914bd6726faSmillert "The letter of the partition to name, a - p.", NULL); 915bd6726faSmillert } 916bd6726faSmillert if (p == NULL) { 917bd6726faSmillert fputs("Command aborted\n", stderr); 918bd6726faSmillert return; 919bd6726faSmillert } 920bd6726faSmillert partno = p[0] - 'a'; 9216c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9226c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9236c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 924bd6726faSmillert return; 92566df1f0cSkrw } 92666df1f0cSkrw pp = &lp->d_partitions[partno]; 92766df1f0cSkrw 92866df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 92966df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 930bd6726faSmillert return; 931bd6726faSmillert } 932bd6726faSmillert 933bd6726faSmillert /* Not all fstypes can be named */ 934bd6726faSmillert if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP || 935bd387921Stodd pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER || 936bd387921Stodd pp->p_fstype == FS_RAID) { 937bd6726faSmillert fprintf(stderr, "You cannot name a filesystem of type %s.\n", 938baa55472Smillert fstypenames[lp->d_partitions[partno].p_fstype]); 939bd6726faSmillert return; 940bd6726faSmillert } 941bd6726faSmillert 94234ae4198Skrw get_mp(lp, partno); 943bd6726faSmillert } 944bd6726faSmillert 945bd6726faSmillert /* 9466fe57b42Smillert * Change an existing partition. 9476fe57b42Smillert */ 9486fe57b42Smillert void 94934ae4198Skrw editor_modify(struct disklabel *lp, char *p) 9506fe57b42Smillert { 9516fe57b42Smillert struct partition origpart, *pp; 952f8ab7229Schl int partno; 9536fe57b42Smillert 9546fe57b42Smillert /* Change which partition? */ 9556fe57b42Smillert if (p == NULL) { 956c33fcabaSmillert p = getstring("partition to modify", 9576fe57b42Smillert "The letter of the partition to modify, a - p.", NULL); 9586fe57b42Smillert } 95996a888c6Smillert if (p == NULL) { 96096a888c6Smillert fputs("Command aborted\n", stderr); 96196a888c6Smillert return; 96296a888c6Smillert } 9636fe57b42Smillert partno = p[0] - 'a'; 9646c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9656c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9666c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 9676fe57b42Smillert return; 96866df1f0cSkrw } 96966df1f0cSkrw pp = &lp->d_partitions[partno]; 97066df1f0cSkrw 97166df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 97266df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 9736fe57b42Smillert return; 9746fe57b42Smillert } 9756fe57b42Smillert 97666df1f0cSkrw origpart = *pp; 97766df1f0cSkrw 978a4c87e64Skrw if (get_offset(lp, partno) == 0 && 979a4c87e64Skrw get_size(lp, partno) == 0 && 980a4c87e64Skrw get_fstype(lp, partno) == 0 && 98134ae4198Skrw get_mp(lp, partno) == 0 && 982a4c87e64Skrw get_fsize(lp, partno) == 0 && 983a4c87e64Skrw get_bsize(lp, partno) == 0) 98496a888c6Smillert return; 9856fe57b42Smillert 986a4c87e64Skrw /* Bailed out at some point, so undo any changes. */ 987a4c87e64Skrw *pp = origpart; 9886fe57b42Smillert } 9896fe57b42Smillert 9906fe57b42Smillert /* 9916fe57b42Smillert * Delete an existing partition. 9926fe57b42Smillert */ 9936fe57b42Smillert void 99434ae4198Skrw editor_delete(struct disklabel *lp, char *p) 9956fe57b42Smillert { 99666df1f0cSkrw struct partition *pp; 997135c90d1Skrw int partno; 9986fe57b42Smillert 9996fe57b42Smillert if (p == NULL) { 1000c33fcabaSmillert p = getstring("partition to delete", 1001945ae268Smillert "The letter of the partition to delete, a - p, or '*'.", 1002945ae268Smillert NULL); 10036fe57b42Smillert } 100496a888c6Smillert if (p == NULL) { 100596a888c6Smillert fputs("Command aborted\n", stderr); 100696a888c6Smillert return; 100796a888c6Smillert } 1008945ae268Smillert if (p[0] == '*') { 10099fdcb4d6Skrw zero_partitions(lp); 1010945ae268Smillert return; 1011945ae268Smillert } 1012135c90d1Skrw partno = p[0] - 'a'; 1013135c90d1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 10146c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 10156c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 101633262abfSmiod return; 101766df1f0cSkrw } 1018135c90d1Skrw pp = &lp->d_partitions[partno]; 101966df1f0cSkrw 102066df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 102166df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 102233262abfSmiod return; 102366df1f0cSkrw } 102466df1f0cSkrw 10256fe57b42Smillert /* Really delete it (as opposed to just setting to "unused") */ 1026135c90d1Skrw memset(pp, 0, sizeof(*pp)); 102734ae4198Skrw free(mountpoints[partno]); 102834ae4198Skrw mountpoints[partno] = NULL; 10296fe57b42Smillert } 10306fe57b42Smillert 10316fe57b42Smillert /* 10326fe57b42Smillert * Change the size of an existing partition. 10336fe57b42Smillert */ 10346fe57b42Smillert void 10359fdcb4d6Skrw editor_change(struct disklabel *lp, char *p) 10366fe57b42Smillert { 10374b9a3bdaSmillert struct partition *pp; 103866df1f0cSkrw int partno; 10396fe57b42Smillert 10406fe57b42Smillert if (p == NULL) { 1041c33fcabaSmillert p = getstring("partition to change size", 10426fe57b42Smillert "The letter of the partition to change size, a - p.", NULL); 10436fe57b42Smillert } 104496a888c6Smillert if (p == NULL) { 104596a888c6Smillert fputs("Command aborted\n", stderr); 104696a888c6Smillert return; 104796a888c6Smillert } 10486fe57b42Smillert partno = p[0] - 'a'; 10496c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 10506c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 10516c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 10526fe57b42Smillert return; 10536fe57b42Smillert } 10544b9a3bdaSmillert pp = &lp->d_partitions[partno]; 10556fe57b42Smillert 105666df1f0cSkrw if (DL_GETPSIZE(pp) == 0) { 105766df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 105866df1f0cSkrw return; 105966df1f0cSkrw } 106066df1f0cSkrw 106114192793Skrw printf("Partition %c is currently %llu sectors in size, and can have " 106214192793Skrw "a maximum\nsize of %llu sectors.\n", 106314192793Skrw p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno)); 10647da73705Skrw 106559ccf790Skrw /* Get new size */ 10669fdcb4d6Skrw get_size(lp, partno); 10676fe57b42Smillert } 10686fe57b42Smillert 10696fe57b42Smillert /* 10706fe57b42Smillert * Sort the partitions based on starting offset. 10716fe57b42Smillert * This assumes there can be no overlap. 10726fe57b42Smillert */ 10736fe57b42Smillert int 10748809fabbSderaadt partition_cmp(const void *e1, const void *e2) 10756fe57b42Smillert { 10766fe57b42Smillert struct partition *p1 = *(struct partition **)e1; 10776fe57b42Smillert struct partition *p2 = *(struct partition **)e2; 10781e0ad43cSotto u_int64_t o1 = DL_GETPOFFSET(p1); 10791e0ad43cSotto u_int64_t o2 = DL_GETPOFFSET(p2); 10806fe57b42Smillert 10811e0ad43cSotto if (o1 < o2) 1082651d5bd9Sotto return -1; 10831e0ad43cSotto else if (o1 > o2) 1084651d5bd9Sotto return 1; 1085651d5bd9Sotto else 1086651d5bd9Sotto return 0; 10876fe57b42Smillert } 10886fe57b42Smillert 10896fe57b42Smillert char * 10908809fabbSderaadt getstring(char *prompt, char *helpstring, char *oval) 10916fe57b42Smillert { 10926fe57b42Smillert static char buf[BUFSIZ]; 10936fe57b42Smillert int n; 10946fe57b42Smillert 10956fe57b42Smillert buf[0] = '\0'; 10966fe57b42Smillert do { 10976fe57b42Smillert printf("%s: [%s] ", prompt, oval ? oval : ""); 10986e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1099260513deSmillert buf[0] = '\0'; 110096a888c6Smillert if (feof(stdin)) { 110124c6582eSmillert clearerr(stdin); 110296a888c6Smillert putchar('\n'); 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 /* 11191e0ad43cSotto * Returns ULLONG_MAX on error 112024a2c1a4Smillert * Usually only called by helper functions. 11216fe57b42Smillert */ 11221e0ad43cSotto u_int64_t 1123dea75673Skrw getuint(struct disklabel *lp, char *prompt, char *helpstring, 11241e0ad43cSotto u_int64_t oval, u_int64_t maxval, u_int64_t offset, int flags) 11256fe57b42Smillert { 11266fe57b42Smillert char buf[BUFSIZ], *endptr, *p, operator = '\0'; 11271e0ad43cSotto u_int64_t rval = oval; 11286fe57b42Smillert size_t n; 11296fe57b42Smillert int mult = 1; 113014cc915fSmillert double d, percent = 1.0; 11316fe57b42Smillert 11324b9a3bdaSmillert /* We only care about the remainder */ 11334b9a3bdaSmillert offset = offset % lp->d_secpercyl; 11344b9a3bdaSmillert 11356fe57b42Smillert buf[0] = '\0'; 11366fe57b42Smillert do { 11371e0ad43cSotto printf("%s: [%llu] ", prompt, oval); 11386e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 11396e0becc5Smillert buf[0] = '\0'; 114096a888c6Smillert if (feof(stdin)) { 114124c6582eSmillert clearerr(stdin); 114296a888c6Smillert putchar('\n'); 11431e0ad43cSotto return(ULLONG_MAX - 1); 114496a888c6Smillert } 11456e0becc5Smillert } 11466fe57b42Smillert n = strlen(buf); 11476fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 11486fe57b42Smillert buf[--n] = '\0'; 11496fe57b42Smillert if (buf[0] == '?') 11506fe57b42Smillert puts(helpstring); 11516fe57b42Smillert } while (buf[0] == '?'); 11526fe57b42Smillert 11536fe57b42Smillert if (buf[0] == '*' && buf[1] == '\0') { 11546fe57b42Smillert rval = maxval; 11556fe57b42Smillert } else { 11566fe57b42Smillert /* deal with units */ 11576fe57b42Smillert if (buf[0] != '\0' && n > 0) { 11586fe57b42Smillert if ((flags & DO_CONVERSIONS)) { 115996a888c6Smillert switch (tolower(buf[n-1])) { 11606fe57b42Smillert 11616fe57b42Smillert case 'c': 11626fe57b42Smillert mult = lp->d_secpercyl; 11636fe57b42Smillert buf[--n] = '\0'; 11646fe57b42Smillert break; 11656fe57b42Smillert case 'b': 11666fe57b42Smillert mult = -lp->d_secsize; 11676fe57b42Smillert buf[--n] = '\0'; 11686fe57b42Smillert break; 11696fe57b42Smillert case 'k': 117050c0f47aSkrw if (lp->d_secsize > 1024) 117150c0f47aSkrw mult = -lp->d_secsize / 1024; 117250c0f47aSkrw else 11736fe57b42Smillert mult = 1024 / lp->d_secsize; 11746fe57b42Smillert buf[--n] = '\0'; 11756fe57b42Smillert break; 11766fe57b42Smillert case 'm': 11776fe57b42Smillert mult = 1048576 / lp->d_secsize; 11786fe57b42Smillert buf[--n] = '\0'; 11796fe57b42Smillert break; 11801a51a1eeSmillert case 'g': 11811a51a1eeSmillert mult = 1073741824 / lp->d_secsize; 11821a51a1eeSmillert buf[--n] = '\0'; 11831a51a1eeSmillert break; 118414cc915fSmillert case '%': 118514cc915fSmillert buf[--n] = '\0'; 118614cc915fSmillert percent = strtod(buf, NULL) / 100.0; 11871e0ad43cSotto snprintf(buf, sizeof(buf), "%lld", 11881e0ad43cSotto DL_GETDSIZE(lp)); 118914cc915fSmillert break; 119014cc915fSmillert case '&': 119114cc915fSmillert buf[--n] = '\0'; 119214cc915fSmillert percent = strtod(buf, NULL) / 100.0; 11931e0ad43cSotto snprintf(buf, sizeof(buf), "%lld", 119414cc915fSmillert maxval); 119514cc915fSmillert break; 11966fe57b42Smillert } 119796a888c6Smillert } 11986fe57b42Smillert 11996fe57b42Smillert /* Did they give us an operator? */ 12006fe57b42Smillert p = &buf[0]; 12016fe57b42Smillert if (*p == '+' || *p == '-') 12026fe57b42Smillert operator = *p++; 12036fe57b42Smillert 12046fe57b42Smillert endptr = p; 120596a888c6Smillert errno = 0; 120696a888c6Smillert d = strtod(p, &endptr); 120796a888c6Smillert if (errno == ERANGE) 12081e0ad43cSotto rval = ULLONG_MAX; /* too big/small */ 120996a888c6Smillert else if (*endptr != '\0') { 12106fe57b42Smillert errno = EINVAL; /* non-numbers in str */ 12111e0ad43cSotto rval = ULLONG_MAX; 12126fe57b42Smillert } else { 121396a888c6Smillert /* XXX - should check for overflow */ 121496a888c6Smillert if (mult > 0) 121514cc915fSmillert rval = d * mult * percent; 121696a888c6Smillert else 121796a888c6Smillert /* Negative mult means divide (fancy) */ 121814cc915fSmillert rval = d / (-mult) * percent; 12196fe57b42Smillert 122096a888c6Smillert /* Apply the operator */ 12216fe57b42Smillert if (operator == '+') 12226fe57b42Smillert rval += oval; 12236fe57b42Smillert else if (operator == '-') 12246fe57b42Smillert rval = oval - rval; 12256fe57b42Smillert } 12266fe57b42Smillert } 12276fe57b42Smillert } 12288390cf28Smillert if ((flags & DO_ROUNDING) && rval != ULLONG_MAX) { 122996a888c6Smillert /* Round to nearest cylinder unless given in sectors */ 12308390cf28Smillert if ( 1231fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 1232fc1a4cc6Sderaadt ((lp->d_flags & D_VENDOR) || mult != 1) && 1233fc1a4cc6Sderaadt #else 12348390cf28Smillert mult != 1 && 1235dbffb156Smillert #endif 12368390cf28Smillert (rval + offset) % lp->d_secpercyl != 0) { 12371e0ad43cSotto u_int64_t cyls; 1238dbffb156Smillert 12398390cf28Smillert /* Round to higher cylinder but no more than maxval */ 12408390cf28Smillert cyls = (rval / lp->d_secpercyl) + 1; 12418390cf28Smillert if ((cyls * lp->d_secpercyl) - offset > maxval) 1242dbffb156Smillert cyls--; 12434b9a3bdaSmillert rval = (cyls * lp->d_secpercyl) - offset; 12448390cf28Smillert printf("Rounding to cylinder: %llu\n", rval); 12456fe57b42Smillert } 12464b9a3bdaSmillert } 12476fe57b42Smillert 12486fe57b42Smillert return(rval); 12496fe57b42Smillert } 12506fe57b42Smillert 12516fe57b42Smillert /* 12521f0f871dSkrw * Check for partition overlap in lp and prompt the user to resolve the overlap 12531f0f871dSkrw * if any is found. Returns 1 if unable to resolve, else 0. 12546fe57b42Smillert */ 12556fe57b42Smillert int 12561f0f871dSkrw has_overlap(struct disklabel *lp) 12576fe57b42Smillert { 12586fe57b42Smillert struct partition **spp; 1259e6aa8bafSmillert int c, i, j; 1260e6aa8bafSmillert char buf[BUFSIZ]; 12616fe57b42Smillert 12620fbd3c97Skrw /* Get a sorted list of the in-use partitions. */ 12630fbd3c97Skrw spp = sort_partitions(lp); 12646fe57b42Smillert 12650fbd3c97Skrw /* If there are less than two partitions in use, there is no overlap. */ 12660fbd3c97Skrw if (spp[1] == NULL) 12670fbd3c97Skrw return(0); 12686fe57b42Smillert 12696fe57b42Smillert /* Now that we have things sorted by starting sector check overlap */ 12700fbd3c97Skrw for (i = 0; spp[i] != NULL; i++) { 12710fbd3c97Skrw for (j = i + 1; spp[j] != NULL; j++) { 12726fe57b42Smillert /* `if last_sec_in_part + 1 > first_sec_in_next_part' */ 12731e0ad43cSotto if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) > DL_GETPOFFSET(spp[j])) { 12746fe57b42Smillert /* Overlap! Convert to real part numbers. */ 12756fe57b42Smillert i = ((char *)spp[i] - (char *)lp->d_partitions) 12766fe57b42Smillert / sizeof(**spp); 12776fe57b42Smillert j = ((char *)spp[j] - (char *)lp->d_partitions) 12786fe57b42Smillert / sizeof(**spp); 12796fe57b42Smillert printf("\nError, partitions %c and %c overlap:\n", 12806fe57b42Smillert 'a' + i, 'a' + j); 1281366bf641Skrw printf("# %16.16s %16.16s fstype " 1282651d5bd9Sotto "[fsize bsize cpg]\n", "size", "offset"); 128334ae4198Skrw display_partition(stdout, lp, i, 0); 128434ae4198Skrw display_partition(stdout, lp, j, 0); 12856fe57b42Smillert 1286e6aa8bafSmillert /* Get partition to disable or ^D */ 1287e6aa8bafSmillert do { 1288616cd1c4Smillert printf("Disable which one? (^D to abort) [%c %c] ", 12896fe57b42Smillert 'a' + i, 'a' + j); 1290e6aa8bafSmillert buf[0] = '\0'; 1291616cd1c4Smillert if (!fgets(buf, sizeof(buf), stdin)) { 1292616cd1c4Smillert putchar('\n'); 1293e6aa8bafSmillert return(1); /* ^D */ 1294616cd1c4Smillert } 1295e6aa8bafSmillert c = buf[0] - 'a'; 1296e6aa8bafSmillert } while (buf[1] != '\n' && buf[1] != '\0' && 1297e6aa8bafSmillert c != i && c != j); 1298e6aa8bafSmillert 1299e6aa8bafSmillert /* Mark the selected one as unused */ 13006fe57b42Smillert lp->d_partitions[c].p_fstype = FS_UNUSED; 13011f0f871dSkrw return (has_overlap(lp)); 13026fe57b42Smillert } 13036fe57b42Smillert } 13046fe57b42Smillert } 1305f0b4d0a9Smillert 1306e6aa8bafSmillert return(0); 13076fe57b42Smillert } 13086fe57b42Smillert 13096fe57b42Smillert void 13109fdcb4d6Skrw edit_parms(struct disklabel *lp) 13116fe57b42Smillert { 13126fe57b42Smillert char *p; 13139fdcb4d6Skrw u_int64_t freesectors, ui; 131496a888c6Smillert struct disklabel oldlabel = *lp; 13156fe57b42Smillert 1316ea37abd3Sderaadt printf("Changing device parameters for %s:\n", specname); 13176fe57b42Smillert 13180f820bbbSmillert /* disk type */ 13190f820bbbSmillert for (;;) { 1320c33fcabaSmillert p = getstring("disk type", 132141282a2aSmillert "What kind of disk is this? Usually SCSI, ESDI, ST506, or " 132241282a2aSmillert "floppy (use ESDI for IDE).", dktypenames[lp->d_type]); 132396a888c6Smillert if (p == NULL) { 132496a888c6Smillert fputs("Command aborted\n", stderr); 132596a888c6Smillert return; 132696a888c6Smillert } 132741282a2aSmillert if (strcasecmp(p, "IDE") == 0) 132841282a2aSmillert ui = DTYPE_ESDI; 132941282a2aSmillert else 133041282a2aSmillert for (ui = 1; ui < DKMAXTYPES && 133141282a2aSmillert strcasecmp(p, dktypenames[ui]); ui++) 13320f820bbbSmillert ; 13330f820bbbSmillert if (ui < DKMAXTYPES) { 13340f820bbbSmillert break; 13350f820bbbSmillert } else { 13360f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", p); 13370f820bbbSmillert fputs("Valid types are: ", stdout); 13380f820bbbSmillert for (ui = 1; ui < DKMAXTYPES; ui++) { 13390f820bbbSmillert printf("\"%s\"", dktypenames[ui]); 13400f820bbbSmillert if (ui < DKMAXTYPES - 1) 13410f820bbbSmillert fputs(", ", stdout); 13420f820bbbSmillert } 13430f820bbbSmillert putchar('\n'); 13440f820bbbSmillert } 13450f820bbbSmillert } 13460f820bbbSmillert lp->d_type = ui; 13470f820bbbSmillert 13486fe57b42Smillert /* pack/label id */ 1349c33fcabaSmillert p = getstring("label name", 13506fe57b42Smillert "15 char string that describes this label, usually the disk name.", 13516fe57b42Smillert lp->d_packname); 135296a888c6Smillert if (p == NULL) { 135396a888c6Smillert fputs("Command aborted\n", stderr); 135496a888c6Smillert *lp = oldlabel; /* undo damage */ 135596a888c6Smillert return; 135696a888c6Smillert } 13574fb6ab7cSmillert strncpy(lp->d_packname, p, sizeof(lp->d_packname)); /* checked */ 13586fe57b42Smillert 13596fe57b42Smillert /* sectors/track */ 13606fe57b42Smillert for (;;) { 1361dea75673Skrw ui = getuint(lp, "sectors/track", 1362cfd24250Skrw "The Number of sectors per track.", lp->d_nsectors, 13634b9a3bdaSmillert lp->d_nsectors, 0, 0); 13641e0ad43cSotto if (ui == ULLONG_MAX - 1) { 136596a888c6Smillert fputs("Command aborted\n", stderr); 136696a888c6Smillert *lp = oldlabel; /* undo damage */ 136796a888c6Smillert return; 13681e0ad43cSotto } if (ui == ULLONG_MAX) 13696fe57b42Smillert fputs("Invalid entry\n", stderr); 13706fe57b42Smillert else 13716fe57b42Smillert break; 13726fe57b42Smillert } 13736fe57b42Smillert lp->d_nsectors = ui; 13746fe57b42Smillert 13756fe57b42Smillert /* tracks/cylinder */ 13766fe57b42Smillert for (;;) { 1377dea75673Skrw ui = getuint(lp, "tracks/cylinder", 13786fe57b42Smillert "The number of tracks per cylinder.", lp->d_ntracks, 13794b9a3bdaSmillert lp->d_ntracks, 0, 0); 13801e0ad43cSotto if (ui == ULLONG_MAX - 1) { 138196a888c6Smillert fputs("Command aborted\n", stderr); 138296a888c6Smillert *lp = oldlabel; /* undo damage */ 138396a888c6Smillert return; 13841e0ad43cSotto } else if (ui == ULLONG_MAX) 13856fe57b42Smillert fputs("Invalid entry\n", stderr); 13866fe57b42Smillert else 13876fe57b42Smillert break; 13886fe57b42Smillert } 13896fe57b42Smillert lp->d_ntracks = ui; 13906fe57b42Smillert 13916fe57b42Smillert /* sectors/cylinder */ 1392148b6188Smillert for (;;) { 1393dea75673Skrw ui = getuint(lp, "sectors/cylinder", 1394148b6188Smillert "The number of sectors per cylinder (Usually sectors/track " 13954b9a3bdaSmillert "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl, 13964b9a3bdaSmillert 0, 0); 13971e0ad43cSotto if (ui == ULLONG_MAX - 1) { 139896a888c6Smillert fputs("Command aborted\n", stderr); 139996a888c6Smillert *lp = oldlabel; /* undo damage */ 140096a888c6Smillert return; 14011e0ad43cSotto } else if (ui == ULLONG_MAX) 1402148b6188Smillert fputs("Invalid entry\n", stderr); 1403148b6188Smillert else 1404148b6188Smillert break; 1405148b6188Smillert } 1406148b6188Smillert lp->d_secpercyl = ui; 14076fe57b42Smillert 14086fe57b42Smillert /* number of cylinders */ 14096fe57b42Smillert for (;;) { 1410dea75673Skrw ui = getuint(lp, "number of cylinders", 14116fe57b42Smillert "The total number of cylinders on the disk.", 14124b9a3bdaSmillert lp->d_ncylinders, lp->d_ncylinders, 0, 0); 14131e0ad43cSotto if (ui == ULLONG_MAX - 1) { 141496a888c6Smillert fputs("Command aborted\n", stderr); 141596a888c6Smillert *lp = oldlabel; /* undo damage */ 141696a888c6Smillert return; 14171e0ad43cSotto } else if (ui == ULLONG_MAX) 14186fe57b42Smillert fputs("Invalid entry\n", stderr); 14196fe57b42Smillert else 14206fe57b42Smillert break; 14216fe57b42Smillert } 14226fe57b42Smillert lp->d_ncylinders = ui; 14236fe57b42Smillert 14246fe57b42Smillert /* total sectors */ 14256fe57b42Smillert for (;;) { 142634af67a3Sotto u_int64_t nsec = MAX(DL_GETDSIZE(lp), 142734af67a3Sotto (u_int64_t)lp->d_ncylinders * lp->d_secpercyl); 1428dea75673Skrw ui = getuint(lp, "total sectors", 14296fe57b42Smillert "The total number of sectors on the disk.", 1430baaa8969Smillert nsec, nsec, 0, 0); 14311e0ad43cSotto if (ui == ULLONG_MAX - 1) { 143296a888c6Smillert fputs("Command aborted\n", stderr); 143396a888c6Smillert *lp = oldlabel; /* undo damage */ 143496a888c6Smillert return; 14351e0ad43cSotto } else if (ui == ULLONG_MAX) 14366fe57b42Smillert fputs("Invalid entry\n", stderr); 14371e0ad43cSotto else if (ui > DL_GETDSIZE(lp) && 14381e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 1439f98aebd4Smillert puts("You may want to increase the size of the 'c' " 1440f98aebd4Smillert "partition."); 14416fe57b42Smillert break; 14421e0ad43cSotto } else if (ui < DL_GETDSIZE(lp) && 14431e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 14446fe57b42Smillert /* shrink free count */ 14459fdcb4d6Skrw freesectors = editor_countfree(lp); 14469fdcb4d6Skrw if (DL_GETDSIZE(lp) - ui > freesectors) 14476fe57b42Smillert fprintf(stderr, 14481e0ad43cSotto "Not enough free space to shrink by %llu " 14491e0ad43cSotto "sectors (only %llu sectors left)\n", 14509fdcb4d6Skrw DL_GETDSIZE(lp) - ui, freesectors); 1451c4f83f03Skrw else 14526fe57b42Smillert break; 14536fe57b42Smillert } else 14546fe57b42Smillert break; 14556fe57b42Smillert } 145641ed49b7Smillert /* Adjust ending_sector if necessary. */ 145796a888c6Smillert if (ending_sector > ui) 145896a888c6Smillert ending_sector = ui; 14591e0ad43cSotto DL_SETDSIZE(lp, ui); 14606fe57b42Smillert 14616fe57b42Smillert /* rpm */ 14626fe57b42Smillert for (;;) { 1463dea75673Skrw ui = getuint(lp, "rpm", 1464a7e61405Smillert "The rotational speed of the disk in revolutions per minute.", 14654b9a3bdaSmillert lp->d_rpm, lp->d_rpm, 0, 0); 14661e0ad43cSotto if (ui == ULLONG_MAX - 1) { 146796a888c6Smillert fputs("Command aborted\n", stderr); 146896a888c6Smillert *lp = oldlabel; /* undo damage */ 146996a888c6Smillert return; 14701e0ad43cSotto } else if (ui == ULLONG_MAX) 14716fe57b42Smillert fputs("Invalid entry\n", stderr); 14726fe57b42Smillert else 14736fe57b42Smillert break; 14746fe57b42Smillert } 14756fe57b42Smillert lp->d_rpm = ui; 1476440b1d70Smillert 1477440b1d70Smillert /* interleave */ 1478440b1d70Smillert for (;;) { 1479dea75673Skrw ui = getuint(lp, "interleave", 1480440b1d70Smillert "The physical sector interleave, set when formatting. Almost always 1.", 14814b9a3bdaSmillert lp->d_interleave, lp->d_interleave, 0, 0); 14821e0ad43cSotto if (ui == ULLONG_MAX - 1) { 1483440b1d70Smillert fputs("Command aborted\n", stderr); 1484440b1d70Smillert *lp = oldlabel; /* undo damage */ 1485440b1d70Smillert return; 14861e0ad43cSotto } else if (ui == ULLONG_MAX || ui == 0) 1487440b1d70Smillert fputs("Invalid entry\n", stderr); 1488440b1d70Smillert else 1489440b1d70Smillert break; 1490440b1d70Smillert } 1491440b1d70Smillert lp->d_interleave = ui; 14926fe57b42Smillert } 1493a7e61405Smillert 1494a7e61405Smillert struct partition ** 14950fbd3c97Skrw sort_partitions(struct disklabel *lp) 1496a7e61405Smillert { 1497d18c2a43Skrw static struct partition *spp[MAXPARTITIONS+2]; 14980fbd3c97Skrw int i, npartitions; 1499a7e61405Smillert 1500d18c2a43Skrw memset(spp, 0, sizeof(spp)); 1501d18c2a43Skrw 1502a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1503a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1504a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 15051e0ad43cSotto DL_GETPSIZE(&lp->d_partitions[i]) != 0) 1506a7e61405Smillert spp[npartitions++] = &lp->d_partitions[i]; 1507a7e61405Smillert } 1508a7e61405Smillert 1509a7e61405Smillert /* 1510a7e61405Smillert * Sort the partitions based on starting offset. 1511a7e61405Smillert * This is safe because we guarantee no overlap. 1512a7e61405Smillert */ 1513a7e61405Smillert if (npartitions > 1) 1514a7e61405Smillert if (heapsort((void *)spp, npartitions, sizeof(spp[0]), 1515a7e61405Smillert partition_cmp)) 1516a7e61405Smillert err(4, "failed to sort partition table"); 1517a7e61405Smillert 1518a7e61405Smillert return(spp); 1519a7e61405Smillert } 15200f820bbbSmillert 15210f820bbbSmillert /* 15220f820bbbSmillert * Get a valid disk type if necessary. 15230f820bbbSmillert */ 15240f820bbbSmillert void 15258809fabbSderaadt getdisktype(struct disklabel *lp, char *banner, char *dev) 15260f820bbbSmillert { 15270f820bbbSmillert int i; 1528803ff7d5Smillert char *s, *def = "SCSI"; 1529803ff7d5Smillert struct dtypes { 1530803ff7d5Smillert char *dev; 1531803ff7d5Smillert char *type; 1532803ff7d5Smillert } dtypes[] = { 1533c33fcabaSmillert { "sd", "SCSI" }, 1534c33fcabaSmillert { "rz", "SCSI" }, 1535c33fcabaSmillert { "wd", "IDE" }, 1536c33fcabaSmillert { "fd", "FLOPPY" }, 1537c33fcabaSmillert { "xd", "SMD" }, 1538c33fcabaSmillert { "xy", "SMD" }, 1539c33fcabaSmillert { "hd", "HP-IB" }, 1540c33fcabaSmillert { "ccd", "CCD" }, 1541c33fcabaSmillert { "vnd", "VND" }, 1542c33fcabaSmillert { "svnd", "VND" }, 1543c33fcabaSmillert { NULL, NULL } 1544803ff7d5Smillert }; 1545803ff7d5Smillert 1546803ff7d5Smillert if ((s = basename(dev)) != NULL) { 1547803ff7d5Smillert if (*s == 'r') 1548803ff7d5Smillert s++; 1549803ff7d5Smillert i = strcspn(s, "0123456789"); 1550803ff7d5Smillert s[i] = '\0'; 1551803ff7d5Smillert dev = s; 1552803ff7d5Smillert for (i = 0; dtypes[i].dev != NULL; i++) { 1553803ff7d5Smillert if (strcmp(dev, dtypes[i].dev) == 0) { 1554803ff7d5Smillert def = dtypes[i].type; 1555803ff7d5Smillert break; 1556803ff7d5Smillert } 1557803ff7d5Smillert } 1558803ff7d5Smillert } 15590f820bbbSmillert 15600f820bbbSmillert if (lp->d_type > DKMAXTYPES || lp->d_type == 0) { 15610f820bbbSmillert puts(banner); 15620f820bbbSmillert puts("Possible values are:"); 1563eb5dd924Sderaadt printf("\"IDE\", "); 15640f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15650f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15660f820bbbSmillert if (i < DKMAXTYPES - 1) 15670f820bbbSmillert fputs(", ", stdout); 15680f820bbbSmillert } 15690f820bbbSmillert putchar('\n'); 15700f820bbbSmillert 15710f820bbbSmillert for (;;) { 1572c33fcabaSmillert s = getstring("Disk type", 1573803ff7d5Smillert "What kind of disk is this? Usually SCSI, IDE, " 1574803ff7d5Smillert "ESDI, CCD, ST506, or floppy.", def); 157596a888c6Smillert if (s == NULL) 157696a888c6Smillert continue; 15775b412421Smillert if (strcasecmp(s, "IDE") == 0) { 15785b412421Smillert lp->d_type = DTYPE_ESDI; 15795b412421Smillert return; 15805b412421Smillert } 15810f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) 15820f820bbbSmillert if (strcasecmp(s, dktypenames[i]) == 0) { 15830f820bbbSmillert lp->d_type = i; 15840f820bbbSmillert return; 15850f820bbbSmillert } 15860f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", s); 15870f820bbbSmillert fputs("Valid types are: ", stdout); 15880f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15890f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15900f820bbbSmillert if (i < DKMAXTYPES - 1) 15910f820bbbSmillert fputs(", ", stdout); 15920f820bbbSmillert } 15930f820bbbSmillert putchar('\n'); 15940f820bbbSmillert } 15950f820bbbSmillert } 15960f820bbbSmillert } 159796a888c6Smillert 159896a888c6Smillert /* 159996a888c6Smillert * Get beginning and ending sectors of the OpenBSD portion of the disk 160096a888c6Smillert * from the user. 160196a888c6Smillert */ 160296a888c6Smillert void 16039fdcb4d6Skrw set_bounds(struct disklabel *lp) 160496a888c6Smillert { 16051e0ad43cSotto u_int64_t ui, start_temp; 160696a888c6Smillert 160796a888c6Smillert /* Starting sector */ 160896a888c6Smillert do { 1609dea75673Skrw ui = getuint(lp, "Starting sector", 161096a888c6Smillert "The start of the OpenBSD portion of the disk.", 16111e0ad43cSotto starting_sector, DL_GETDSIZE(lp), 0, 0); 16121e0ad43cSotto if (ui == ULLONG_MAX - 1) { 161396a888c6Smillert fputs("Command aborted\n", stderr); 161496a888c6Smillert return; 161596a888c6Smillert } 16161e0ad43cSotto } while (ui >= DL_GETDSIZE(lp)); 161796a888c6Smillert start_temp = ui; 161896a888c6Smillert 16194793b14cSmillert /* Size */ 162096a888c6Smillert do { 1621dea75673Skrw ui = getuint(lp, "Size ('*' for entire disk)", 1622f98aebd4Smillert "The size of the OpenBSD portion of the disk ('*' for the " 1623f98aebd4Smillert "entire disk).", ending_sector - starting_sector, 16241e0ad43cSotto DL_GETDSIZE(lp) - start_temp, 0, 0); 16251e0ad43cSotto if (ui == ULLONG_MAX - 1) { 162696a888c6Smillert fputs("Command aborted\n", stderr); 162796a888c6Smillert return; 162896a888c6Smillert } 16291e0ad43cSotto } while (ui > DL_GETDSIZE(lp) - start_temp); 16304793b14cSmillert ending_sector = start_temp + ui; 163196a888c6Smillert starting_sector = start_temp; 163296a888c6Smillert } 163396a888c6Smillert 163496a888c6Smillert /* 163596a888c6Smillert * Return a list of the "chunks" of free space available 163696a888c6Smillert */ 163796a888c6Smillert struct diskchunk * 16388809fabbSderaadt free_chunks(struct disklabel *lp) 163996a888c6Smillert { 164096a888c6Smillert struct partition **spp; 164196a888c6Smillert static struct diskchunk chunks[MAXPARTITIONS + 2]; 164299bd27d2Skrw u_int64_t start, stop; 164396a888c6Smillert int i, numchunks; 164496a888c6Smillert 16450fbd3c97Skrw /* Sort the in-use partitions based on offset */ 16460fbd3c97Skrw spp = sort_partitions(lp); 164796a888c6Smillert 164896a888c6Smillert /* If there are no partitions, it's all free. */ 16490fbd3c97Skrw if (spp[0] == NULL) { 16502d8451b0Smillert chunks[0].start = starting_sector; 165196a888c6Smillert chunks[0].stop = ending_sector; 165296a888c6Smillert chunks[1].start = chunks[1].stop = 0; 165396a888c6Smillert return(chunks); 165496a888c6Smillert } 165596a888c6Smillert 165696a888c6Smillert /* Find chunks of free space */ 165796a888c6Smillert numchunks = 0; 16580fbd3c97Skrw if (DL_GETPOFFSET(spp[0]) > starting_sector) { 16592d8451b0Smillert chunks[0].start = starting_sector; 16601e0ad43cSotto chunks[0].stop = DL_GETPOFFSET(spp[0]); 166196a888c6Smillert numchunks++; 166296a888c6Smillert } 16630fbd3c97Skrw for (i = 0; spp[i] != NULL; i++) { 166499bd27d2Skrw start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]); 1665aff3f969Sotto if (start < starting_sector) 1666aff3f969Sotto start = starting_sector; 1667aff3f969Sotto else if (start > ending_sector) 1668aff3f969Sotto start = ending_sector; 166999bd27d2Skrw if (spp[i + 1] != NULL) 167099bd27d2Skrw stop = DL_GETPOFFSET(spp[i+1]); 167199bd27d2Skrw else 167299bd27d2Skrw stop = ending_sector; 1673aff3f969Sotto if (stop < starting_sector) 1674aff3f969Sotto stop = starting_sector; 1675aff3f969Sotto else if (stop > ending_sector) 1676aff3f969Sotto stop = ending_sector; 167799bd27d2Skrw if (start < stop) { 167899bd27d2Skrw chunks[numchunks].start = start; 167999bd27d2Skrw chunks[numchunks].stop = stop; 168096a888c6Smillert numchunks++; 168196a888c6Smillert } 168296a888c6Smillert } 168396a888c6Smillert 168496a888c6Smillert /* Terminate and return */ 168596a888c6Smillert chunks[numchunks].start = chunks[numchunks].stop = 0; 168696a888c6Smillert return(chunks); 168796a888c6Smillert } 16884793b14cSmillert 16894793b14cSmillert void 169087023ed9Skrw find_bounds(struct disklabel *lp) 16914793b14cSmillert { 16926534e983Sderaadt starting_sector = DL_GETBSTART(lp); 16936534e983Sderaadt ending_sector = DL_GETBEND(lp); 1694b2d4a455Smiod 16956534e983Sderaadt if (ending_sector) { 169634ae4198Skrw if (verbose) 169734ae4198Skrw printf("Treating sectors %llu-%llu as the OpenBSD" 169834ae4198Skrw " portion of the disk.\nYou can use the 'b'" 169934ae4198Skrw " command to change this.\n\n", starting_sector, 170034ae4198Skrw ending_sector); 1701b2d4a455Smiod } else { 1702b2d4a455Smiod #if (NUMBOOT == 1) 1703d3f02056Smillert /* Boot blocks take up the first cylinder */ 1704d3f02056Smillert starting_sector = lp->d_secpercyl; 170534ae4198Skrw if (verbose) 170634ae4198Skrw printf("Reserving the first data cylinder for boot" 170734ae4198Skrw " blocks.\nYou can use the 'b' command to change" 170834ae4198Skrw " this.\n\n"); 17094793b14cSmillert #endif 17104793b14cSmillert } 1711b2d4a455Smiod } 1712c0bdc608Smillert 1713c0bdc608Smillert /* 1714c0bdc608Smillert * Calculate free space. 1715c0bdc608Smillert */ 17169fdcb4d6Skrw u_int64_t 17179fdcb4d6Skrw editor_countfree(struct disklabel *lp) 1718c0bdc608Smillert { 1719d93cb2bbSkrw struct diskchunk *chunks; 17209fdcb4d6Skrw u_int64_t freesectors = 0; 1721c0bdc608Smillert int i; 1722c0bdc608Smillert 1723d93cb2bbSkrw chunks = free_chunks(lp); 1724509930fbSotto 1725d93cb2bbSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) 17269fdcb4d6Skrw freesectors += chunks[i].stop - chunks[i].start; 17279fdcb4d6Skrw 17289fdcb4d6Skrw return (freesectors); 1729c0bdc608Smillert } 1730617e6e4aSmillert 1731617e6e4aSmillert void 17328809fabbSderaadt editor_help(char *arg) 1733617e6e4aSmillert { 1734617e6e4aSmillert 1735617e6e4aSmillert /* XXX - put these strings in a table instead? */ 1736617e6e4aSmillert switch (*arg) { 1737617e6e4aSmillert case 'p': 1738617e6e4aSmillert puts( 1739aff3f969Sotto "The 'p' command prints the current partitions. By default, it prints size\n" 1740aff3f969Sotto "and offset in sectors (a sector is usually 512 bytes). The 'p' command\n" 1741aff3f969Sotto "takes an optional units argument. Possible values are 'b' for bytes, 'c'\n" 1742aff3f969Sotto "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n"); 1743eb176802Sjsg break; 1744aff3f969Sotto case 'l': 1745aff3f969Sotto puts( 1746aff3f969Sotto "The 'l' command prints the header of the disk label. By default, it prints\n" 1747617e6e4aSmillert "size and offset in sectors (a sector is usually 512 bytes). The 'p' command\n" 1748617e6e4aSmillert "takes an optional units argument. Possible values are 'b' for bytes, 'c'\n" 1749617e6e4aSmillert "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n"); 1750617e6e4aSmillert break; 1751617e6e4aSmillert case 'M': 1752617e6e4aSmillert puts( 17539afbe9eeSmillert "The 'M' command pipes the entire OpenBSD manual page for disk label through\n" 1754508086e9Smillert "the pager specified by the PAGER environment variable or 'less' if PAGER is\n" 1755508086e9Smillert "not set. It is especially useful during install when the normal system\n" 1756508086e9Smillert "manual is not available.\n"); 1757617e6e4aSmillert break; 1758617e6e4aSmillert case 'e': 1759617e6e4aSmillert puts( 1760617e6e4aSmillert "The 'e' command is used to edit the disk drive parameters. These include\n" 1761617e6e4aSmillert "the number of sectors/track, tracks/cylinder, sectors/cylinder, number of\n" 1762617e6e4aSmillert "cylinders on the disk , total sectors on the disk, rpm, interleave, disk\n" 1763617e6e4aSmillert "type, and a descriptive label string. You should not change these unless\n" 1764617e6e4aSmillert "you know what you are doing\n"); 1765617e6e4aSmillert break; 1766617e6e4aSmillert case 'a': 1767617e6e4aSmillert puts( 1768617e6e4aSmillert "The 'a' command adds new partitions to the disk. It takes as an optional\n" 1769617e6e4aSmillert "argument the partition letter to add. If you do not specify a partition\n" 1770617e6e4aSmillert "letter, you will be prompted for it; the next available letter will be the\n" 1771617e6e4aSmillert "default answer\n"); 1772617e6e4aSmillert break; 17736aaa4aabSotto case 'A': 17746aaa4aabSotto puts( 17756aaa4aabSotto "The 'A' command clears the existing partitions and creates a new label\n" 17766aaa4aabSotto "based on the size of the disk\n"); 17776aaa4aabSotto break; 1778617e6e4aSmillert case 'b': 1779617e6e4aSmillert puts( 1780617e6e4aSmillert "The 'b' command is used to change the boundaries of the OpenBSD portion of\n" 1781617e6e4aSmillert "the disk. This is only useful on disks with an fdisk partition. By default,\n" 1782617e6e4aSmillert "on a disk with an fdisk partition, the boundaries are set to be the first\n" 1783617e6e4aSmillert "and last sectors of the OpenBSD fdisk partition. You should only change\n" 1784617e6e4aSmillert "these if your fdisk partition table is incorrect or you have a disk larger\n" 1785617e6e4aSmillert "than 8gig, since 8gig is the maximum size an fdisk partition can be. You\n" 1786617e6e4aSmillert "may enter '*' at the 'Size' prompt to indicate the entire size of the disk\n" 1787617e6e4aSmillert "(minus the starting sector). Use this option with care; if you extend the\n" 1788617e6e4aSmillert "boundaries such that they overlap with another operating system you will\n" 1789617e6e4aSmillert "corrupt the other operating system's data.\n"); 1790617e6e4aSmillert break; 1791617e6e4aSmillert case 'c': 1792617e6e4aSmillert puts( 1793617e6e4aSmillert "The 'c' command is used to change the size of an existing partition. It\n" 1794617e6e4aSmillert "takes as an optional argument the partition letter to change. If you do not\n" 1795617e6e4aSmillert "specify a partition letter, you will be prompted for one. You may add a '+'\n" 1796617e6e4aSmillert "or '-' prefix to the new size to increase or decrease the existing value\n" 1797617e6e4aSmillert "instead of entering an absolute value. You may also use a suffix to indicate\n" 1798617e6e4aSmillert "the units the values is in terms of. Possible suffixes are 'b' for bytes,\n" 1799617e6e4aSmillert "'c' for cylinders, 'k' for kilobytes, 'm' for megabytes, 'g' for gigabytes or\n" 1800617e6e4aSmillert "no suffix for sectors (usually 512 bytes). You may also enter '*' to change\n" 1801617e6e4aSmillert "the size to be the total number of free sectors remaining.\n"); 1802617e6e4aSmillert break; 18039afbe9eeSmillert case 'D': 18049afbe9eeSmillert puts( 18059afbe9eeSmillert "The 'D' command will set the disk label to the default values as reported\n" 18069afbe9eeSmillert "by the disk itself. This similates the case where there is no disk label.\n"); 18079afbe9eeSmillert break; 1808617e6e4aSmillert case 'd': 1809617e6e4aSmillert puts( 1810617e6e4aSmillert "The 'd' command is used to delete an existing partition. It takes as an\n" 1811617e6e4aSmillert "optional argument the partition letter to change. If you do not specify a\n" 1812617e6e4aSmillert "partition letter, you will be prompted for one. You may not delete the ``c''\n" 1813617e6e4aSmillert "partition as 'c' must always exist and by default is marked as 'unused' (so\n" 1814617e6e4aSmillert "it does not take up any space).\n"); 1815617e6e4aSmillert break; 1816c33fcabaSmillert case 'g': 1817c33fcabaSmillert puts( 181887023ed9Skrw "The 'g' command is used select which disk geometry to use, the disk or a\n" 181987023ed9Skrw "user geometry. It takes as an optional argument ``d'' or ``u''. If \n" 1820c33fcabaSmillert "you do not specify the type as an argument, you will be prompted for it.\n"); 1821c33fcabaSmillert break; 1822617e6e4aSmillert case 'm': 1823617e6e4aSmillert puts( 182487023ed9Skrw "The 'm' command is used to modify an existing partition. It takes as an\n" 182587023ed9Skrw "optional argument the partition letter to change. If you do not specify a\n" 1826617e6e4aSmillert "partition letter, you will be prompted for one. This option allows the user\n" 1827617e6e4aSmillert "to change the filesystem type, starting offset, partition size, block fragment\n" 1828617e6e4aSmillert "size, block size, and cylinders per group for the specified partition (not all\n" 1829617e6e4aSmillert "parameters are configurable for non-BSD partitions).\n"); 1830617e6e4aSmillert break; 1831bd6726faSmillert case 'n': 1832bd6726faSmillert puts( 1833fb932baaSaaron "The 'n' command is used to set the mount point for a partition (ie: name it).\n" 1834bd6726faSmillert "It takes as an optional argument the partition letter to name. If you do\n" 1835bd6726faSmillert "not specify a partition letter, you will be prompted for one. This option\n" 1836ac7ae62cSderaadt "is only valid if disklabel was invoked with the -f flag.\n"); 1837bd6726faSmillert break; 18386aaa4aabSotto case 'R': 18396aaa4aabSotto puts( 18406aaa4aabSotto "Resize a a partition, compacting unused space between partitions\n" 18416aaa4aabSotto "with a higher offset. The last partition will be shrunk if needed.\n" 1842fc6e9c48Sotto "Works only for auto allocated labels.\n"); 18436aaa4aabSotto break; 1844617e6e4aSmillert case 'r': 1845617e6e4aSmillert puts( 184625f9c360Skrw "The 'r' command is used to recalculate and display details about\n" 184725f9c360Skrw "the available free space.\n"); 1848617e6e4aSmillert break; 1849617e6e4aSmillert case 'u': 1850617e6e4aSmillert puts( 1851617e6e4aSmillert "The 'u' command will undo (or redo) the last change. Entering 'u' once will\n" 1852617e6e4aSmillert "undo your last change. Entering it again will restore the change.\n"); 1853617e6e4aSmillert break; 1854617e6e4aSmillert case 's': 1855617e6e4aSmillert puts( 1856617e6e4aSmillert "The 's' command is used to save a copy of the label to a file in ascii format\n" 1857617e6e4aSmillert "(suitable for loading via disklabel's [-R] option). It takes as an optional\n" 1858617e6e4aSmillert "argument the filename to save the label to. If you do not specify a filename,\n" 1859617e6e4aSmillert "you will be prompted for one.\n"); 1860617e6e4aSmillert break; 1861617e6e4aSmillert case 'w': 1862617e6e4aSmillert puts( 1863617e6e4aSmillert "The 'w' command will write the current label to disk. This option will\n" 1864617e6e4aSmillert "commit any changes to the on-disk label.\n"); 1865617e6e4aSmillert break; 1866617e6e4aSmillert case 'q': 1867617e6e4aSmillert puts( 1868617e6e4aSmillert "The 'q' command quits the label editor. If any changes have been made you\n" 1869617e6e4aSmillert "will be asked whether or not to save the changes to the on-disk label.\n"); 1870617e6e4aSmillert break; 18719afbe9eeSmillert case 'X': 18729afbe9eeSmillert puts( 18739afbe9eeSmillert "The 'X' command toggles disklabel in to/out of 'expert mode'. By default,\n" 18749afbe9eeSmillert "some settings are reserved for experts only (such as the block and fragment\n" 18759afbe9eeSmillert "size on ffs partitions).\n"); 18769afbe9eeSmillert break; 1877617e6e4aSmillert case 'x': 1878617e6e4aSmillert puts( 1879617e6e4aSmillert "The 'x' command exits the label editor without saving any changes to the\n" 1880617e6e4aSmillert "on-disk label.\n"); 1881617e6e4aSmillert break; 18829afbe9eeSmillert case 'z': 18839afbe9eeSmillert puts( 18849afbe9eeSmillert "The 'z' command zeroes out the existing partition table, leaving only the 'c'\n" 18859afbe9eeSmillert "partition. The drive parameters are not changed.\n"); 18869afbe9eeSmillert break; 1887617e6e4aSmillert default: 1888617e6e4aSmillert puts("Available commands:"); 1889617e6e4aSmillert puts( 189049159a67Skrw " ? [cmd] - show help n [part] - set mount point\n" 189149159a67Skrw " A - auto partition all space p [unit] - print partitions\n" 189249159a67Skrw " a [part] - add partition q - quit & save changes\n" 18936aaa4aabSotto " b - set OpenBSD boundaries R [part] - resize a partition\n" 189449159a67Skrw " c [part] - change partition size r - display free space\n" 18956aaa4aabSotto " D - reset label to default s [path] - save label to file\n" 18966aaa4aabSotto " d [part] - delete partition U - undo all changes\n" 18976aaa4aabSotto " e - edit drive parameters u - undo last change\n" 18986aaa4aabSotto " g [d|u] - [d]isk or [u]ser geometry w - write label to disk\n" 18996aaa4aabSotto " l [unit] - print disk label header X - toggle expert mode\n" 19006aaa4aabSotto " M - disklabel(8) man page x - exit & lose changes\n" 19016aaa4aabSotto " m [part] - modify partition z - delete all partitions\n" 1902c4884206Skrw "\n" 1903c4884206Skrw "Suffixes can be used to indicate units other than sectors:\n" 1904c4884206Skrw "\t'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes)\n" 1905c4884206Skrw "\t'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n" 1906c4884206Skrw "Values in non-sector units are truncated to the nearest cylinder boundary."); 1907617e6e4aSmillert break; 1908617e6e4aSmillert } 1909617e6e4aSmillert } 1910bd6726faSmillert 19114f3bbbf0Skrw void 19128809fabbSderaadt mpcopy(char **to, char **from) 1913bd6726faSmillert { 1914bd6726faSmillert int i; 19150612d09dSderaadt char *top; 1916bd6726faSmillert 1917bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1918bd6726faSmillert if (from[i] != NULL) { 1919dcab0d16Sderaadt int len = strlen(from[i]) + 1; 1920dcab0d16Sderaadt 19210612d09dSderaadt top = realloc(to[i], len); 19220612d09dSderaadt if (top == NULL) 1923bd6726faSmillert errx(4, "out of memory"); 19240612d09dSderaadt to[i] = top; 1925dcab0d16Sderaadt (void)strlcpy(to[i], from[i], len); 1926bd6726faSmillert } else if (to[i] != NULL) { 1927bd6726faSmillert free(to[i]); 1928bd6726faSmillert to[i] = NULL; 1929bd6726faSmillert } 1930bd6726faSmillert } 1931bd6726faSmillert } 1932bd6726faSmillert 1933bd6726faSmillert int 19348809fabbSderaadt mpequal(char **mp1, char **mp2) 1935bd6726faSmillert { 1936bd6726faSmillert int i; 1937bd6726faSmillert 1938bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1939bd6726faSmillert if (mp1[i] == NULL && mp2[i] == NULL) 1940bd6726faSmillert continue; 1941bd6726faSmillert 1942bd6726faSmillert if ((mp1[i] != NULL && mp2[i] == NULL) || 1943bd6726faSmillert (mp1[i] == NULL && mp2[i] != NULL) || 1944bd6726faSmillert (strcmp(mp1[i], mp2[i]) != 0)) 1945bd6726faSmillert return(0); 1946bd6726faSmillert } 1947bd6726faSmillert return(1); 1948bd6726faSmillert } 1949bd6726faSmillert 195093160b9bSkrw void 195134ae4198Skrw mpsave(struct disklabel *lp) 1952bd6726faSmillert { 1953d8b446ceSderaadt int i, j; 1954bd6726faSmillert char bdev[MAXPATHLEN], *p; 19553f843443Smillert struct mountinfo mi[MAXPARTITIONS]; 1956bd6726faSmillert FILE *fp; 1957bd6726faSmillert 195893160b9bSkrw if (!fstabfile) 195993160b9bSkrw return; 196093160b9bSkrw 19613f843443Smillert memset(&mi, 0, sizeof(mi)); 19623f843443Smillert 1963d8b446ceSderaadt for (i = 0; i < MAXPARTITIONS; i++) { 196434ae4198Skrw if (mountpoints[i] != NULL) { 196534ae4198Skrw mi[i].mountpoint = mountpoints[i]; 19663f843443Smillert mi[i].partno = i; 1967bd6726faSmillert } 1968bd6726faSmillert } 1969bd6726faSmillert 197034ae4198Skrw /* Convert specname to bdev */ 197134ae4198Skrw if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 && 197234ae4198Skrw specname[sizeof(_PATH_DEV) - 1] == 'r') { 1973bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV, 197434ae4198Skrw &specname[sizeof(_PATH_DEV)]); 1975bd6726faSmillert } else { 197634ae4198Skrw if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r') 197793160b9bSkrw return; 1978bd6726faSmillert *p = '\0'; 197934ae4198Skrw snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1); 1980bd6726faSmillert *p = 'r'; 1981bd6726faSmillert } 1982bd6726faSmillert bdev[strlen(bdev) - 1] = '\0'; 1983bd6726faSmillert 19843f843443Smillert /* Sort mountpoints so we don't try to mount /usr/local before /usr */ 19853f843443Smillert qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp); 19863f843443Smillert 198793160b9bSkrw if (fp = fopen(fstabfile, "w")) { 198893160b9bSkrw for (i = 0; i < MAXPARTITIONS && mi[i].mountpoint; i++) { 19895fea0b85Smillert j = mi[i].partno; 19905fea0b85Smillert fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 'a' + j, 19913f843443Smillert mi[i].mountpoint, 19925fea0b85Smillert fstypesnames[lp->d_partitions[j].p_fstype], 19935fea0b85Smillert j == 0 ? 1 : 2); 1994bd6726faSmillert } 1995bd6726faSmillert fclose(fp); 199693160b9bSkrw } 1997bd6726faSmillert } 199824a2c1a4Smillert 199924a2c1a4Smillert int 2000604d3bdeSkrw get_offset(struct disklabel *lp, int partno) 200124a2c1a4Smillert { 2002604d3bdeSkrw struct diskchunk *chunks; 200324a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 200415c15d8aSkrw u_int64_t ui, maxsize; 2005604d3bdeSkrw int i, fstype; 200624a2c1a4Smillert 2007dea75673Skrw ui = getuint(lp, "offset", 20081e0ad43cSotto "Starting sector for this partition.", 20091e0ad43cSotto DL_GETPOFFSET(pp), 20101e0ad43cSotto DL_GETPOFFSET(pp), 0, DO_CONVERSIONS | 201124a2c1a4Smillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 2012e9ff19beSkrw 2013e9ff19beSkrw if (ui == ULLONG_MAX - 1) 201424a2c1a4Smillert fputs("Command aborted\n", stderr); 2015e9ff19beSkrw else if (ui == ULLONG_MAX) 201624a2c1a4Smillert fputs("Invalid entry\n", stderr); 201740e98e9fSkrw else if (ui < starting_sector || ui >= ending_sector) 2018e9ff19beSkrw fprintf(stderr, "The offset must be >= %llu and < %llu, " 2019e9ff19beSkrw "the limits of the OpenBSD portion\n" 2020e9ff19beSkrw "of the disk. The 'b' command can change these limits.\n", 202140e98e9fSkrw starting_sector, ending_sector); 2022fc1a4cc6Sderaadt #ifdef SUN_AAT0 202349bf537cSderaadt else if (partno == 0 && ui != 0) 202449bf537cSderaadt fprintf(stderr, "This architecture requires that " 202540f544cdSderaadt "partition 'a' start at sector 0.\n"); 202649bf537cSderaadt #endif 202715c15d8aSkrw else { 2028604d3bdeSkrw fstype = pp->p_fstype; 2029604d3bdeSkrw pp->p_fstype = FS_UNUSED; 2030604d3bdeSkrw chunks = free_chunks(lp); 2031604d3bdeSkrw pp->p_fstype = fstype; 2032e9ff19beSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 2033e9ff19beSkrw if (ui < chunks[i].start || ui >= chunks[i].stop) 203415c15d8aSkrw continue; 20351e0ad43cSotto DL_SETPOFFSET(pp, ui); 203615c15d8aSkrw maxsize = chunks[i].stop - DL_GETPOFFSET(pp); 203715c15d8aSkrw if (DL_GETPSIZE(pp) > maxsize) 203815c15d8aSkrw DL_SETPSIZE(pp, maxsize); 203924a2c1a4Smillert return (0); 204024a2c1a4Smillert } 204115c15d8aSkrw fputs("The offset must be in a free area.\n", stderr); 204215c15d8aSkrw } 2043e9ff19beSkrw 2044e9ff19beSkrw /* Partition offset was not set. */ 2045e9ff19beSkrw return (1); 204615c15d8aSkrw } 204724a2c1a4Smillert 204824a2c1a4Smillert int 20499fdcb4d6Skrw get_size(struct disklabel *lp, int partno) 205024a2c1a4Smillert { 205124a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 205214192793Skrw u_int64_t maxsize, ui; 205314192793Skrw 205414192793Skrw maxsize = max_partition_size(lp, partno); 205524a2c1a4Smillert 2056dea75673Skrw ui = getuint(lp, "size", "Size of the partition. " 20577da73705Skrw "You may also say +/- amount for a relative change.", 205814192793Skrw DL_GETPSIZE(pp), maxsize, DL_GETPOFFSET(pp), 2059525051f1Sotto DO_CONVERSIONS | ((pp->p_fstype == FS_BSDFFS || 2060525051f1Sotto pp->p_fstype == FS_SWAP) ? DO_ROUNDING : 0)); 2061e9ff19beSkrw 2062e9ff19beSkrw if (ui == ULLONG_MAX - 1) 206324a2c1a4Smillert fputs("Command aborted\n", stderr); 2064e9ff19beSkrw else if (ui == ULLONG_MAX) 206524a2c1a4Smillert fputs("Invalid entry\n", stderr); 206628e3704eSkrw else if (ui == 0) 206728e3704eSkrw fputs("The size must be > 0\n", stderr); 206840e98e9fSkrw else if (ui + DL_GETPOFFSET(pp) > ending_sector) 206940e98e9fSkrw fprintf(stderr, "The size can't be more than " 207040e98e9fSkrw "%llu sectors, or the partition would\n" 207140e98e9fSkrw "extend beyond the last sector (%llu) of the " 207240e98e9fSkrw "OpenBSD portion of\nthe disk. " 207340e98e9fSkrw "The 'b' command can change this limit.\n", 207440e98e9fSkrw ending_sector - DL_GETPOFFSET(pp), ending_sector); 207514192793Skrw else if (ui > maxsize) 207614192793Skrw fprintf(stderr,"Sorry, there are only %llu sectors left\n", 207714192793Skrw maxsize); 207859ccf790Skrw else { 207959ccf790Skrw DL_SETPSIZE(pp, ui); 208024a2c1a4Smillert return (0); 208124a2c1a4Smillert } 2082e9ff19beSkrw 2083e9ff19beSkrw /* Partition size was not set. */ 2084e9ff19beSkrw return (1); 2085e9ff19beSkrw } 208624a2c1a4Smillert 208724a2c1a4Smillert int 20888809fabbSderaadt get_fsize(struct disklabel *lp, int partno) 208924a2c1a4Smillert { 20901e0ad43cSotto u_int64_t ui, fsize, frag; 209124a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 209224a2c1a4Smillert 2093a4c87e64Skrw if (!expert || pp->p_fstype != FS_BSDFFS) 2094a4c87e64Skrw return (0); 2095a4c87e64Skrw 2096ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 2097ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 2098ddfcbf38Sotto if (fsize == 0) 2099ddfcbf38Sotto frag = 8; 2100ddfcbf38Sotto 210124a2c1a4Smillert for (;;) { 2102dea75673Skrw ui = getuint(lp, "fragment size", 21033c92d7f2Stedu "Size of fs block fragments. Usually 2048 or 512.", 2104ddfcbf38Sotto fsize, fsize, 0, 0); 21051e0ad43cSotto if (ui == ULLONG_MAX - 1) { 210624a2c1a4Smillert fputs("Command aborted\n", stderr); 210724a2c1a4Smillert return(1); 21081e0ad43cSotto } else if (ui == ULLONG_MAX) 210924a2c1a4Smillert fputs("Invalid entry\n", stderr); 211024a2c1a4Smillert else 211124a2c1a4Smillert break; 211224a2c1a4Smillert } 211324a2c1a4Smillert if (ui == 0) 211424a2c1a4Smillert puts("Zero fragment size implies zero block size"); 2115ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag); 211624a2c1a4Smillert return(0); 211724a2c1a4Smillert } 211824a2c1a4Smillert 211924a2c1a4Smillert int 21208809fabbSderaadt get_bsize(struct disklabel *lp, int partno) 212124a2c1a4Smillert { 21221e0ad43cSotto u_int64_t ui, bsize, frag, fsize; 212324a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 212424a2c1a4Smillert 2125a4c87e64Skrw if (!expert || pp->p_fstype != FS_BSDFFS) 2126a4c87e64Skrw return (0); 2127a4c87e64Skrw 212824a2c1a4Smillert /* Avoid dividing by zero... */ 2129ddfcbf38Sotto if (pp->p_fragblock == 0) 213024a2c1a4Smillert return(1); 2131ddfcbf38Sotto 2132ddfcbf38Sotto bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock); 2133ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 2134ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 213524a2c1a4Smillert 213624a2c1a4Smillert for (;;) { 2137dea75673Skrw ui = getuint(lp, "block size", 21383c92d7f2Stedu "Size of filesystem blocks. Usually 16384 or 4096.", 2139ddfcbf38Sotto fsize * frag, fsize * frag, 214024a2c1a4Smillert 0, 0); 214124a2c1a4Smillert 214224a2c1a4Smillert /* sanity checks */ 21431e0ad43cSotto if (ui == ULLONG_MAX - 1) { 214424a2c1a4Smillert fputs("Command aborted\n", stderr); 214524a2c1a4Smillert return(1); 21461e0ad43cSotto } else if (ui == ULLONG_MAX) 214724a2c1a4Smillert fputs("Invalid entry\n", stderr); 214824a2c1a4Smillert else if (ui < getpagesize()) 214924a2c1a4Smillert fprintf(stderr, 215024a2c1a4Smillert "Error: block size must be at least as big " 215124a2c1a4Smillert "as page size (%d).\n", getpagesize()); 2152ddfcbf38Sotto else if (ui % fsize != 0) 215324a2c1a4Smillert fputs("Error: block size must be a multiple of the " 215424a2c1a4Smillert "fragment size.\n", stderr); 2155ddfcbf38Sotto else if (ui / fsize < 1) 215624a2c1a4Smillert fputs("Error: block size must be at least as big as " 215724a2c1a4Smillert "fragment size.\n", stderr); 215824a2c1a4Smillert else 215924a2c1a4Smillert break; 216024a2c1a4Smillert } 2161ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui / frag, frag); 216224a2c1a4Smillert return(0); 216324a2c1a4Smillert } 216424a2c1a4Smillert 216524a2c1a4Smillert int 21668809fabbSderaadt get_fstype(struct disklabel *lp, int partno) 216724a2c1a4Smillert { 216824a2c1a4Smillert char *p; 21691e0ad43cSotto u_int64_t ui; 217024a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 217124a2c1a4Smillert 217224a2c1a4Smillert if (pp->p_fstype < FSMAXTYPES) { 2173c33fcabaSmillert p = getstring("FS type", 217424a2c1a4Smillert "Filesystem type (usually 4.2BSD or swap)", 217524a2c1a4Smillert fstypenames[pp->p_fstype]); 217624a2c1a4Smillert if (p == NULL) { 217724a2c1a4Smillert fputs("Command aborted\n", stderr); 217824a2c1a4Smillert return(1); 217924a2c1a4Smillert } 218024a2c1a4Smillert for (ui = 0; ui < FSMAXTYPES; ui++) { 218124a2c1a4Smillert if (!strcasecmp(p, fstypenames[ui])) { 218224a2c1a4Smillert pp->p_fstype = ui; 218324a2c1a4Smillert break; 218424a2c1a4Smillert } 218524a2c1a4Smillert } 218624a2c1a4Smillert if (ui >= FSMAXTYPES) { 218724a2c1a4Smillert printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p); 218824a2c1a4Smillert pp->p_fstype = FS_OTHER; 218924a2c1a4Smillert } 219024a2c1a4Smillert } else { 219124a2c1a4Smillert for (;;) { 2192dea75673Skrw ui = getuint(lp, "FS type (decimal)", 219324a2c1a4Smillert "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", 219424a2c1a4Smillert pp->p_fstype, pp->p_fstype, 0, 0); 21951e0ad43cSotto if (ui == ULLONG_MAX - 1) { 219624a2c1a4Smillert fputs("Command aborted\n", stderr); 219724a2c1a4Smillert return(1); 21981e0ad43cSotto } if (ui == ULLONG_MAX) 219924a2c1a4Smillert fputs("Invalid entry\n", stderr); 220024a2c1a4Smillert else 220124a2c1a4Smillert break; 220224a2c1a4Smillert } 220324a2c1a4Smillert pp->p_fstype = ui; 220424a2c1a4Smillert } 220524a2c1a4Smillert return(0); 220624a2c1a4Smillert } 220724a2c1a4Smillert 220824a2c1a4Smillert int 220934ae4198Skrw get_mp(struct disklabel *lp, int partno) 221024a2c1a4Smillert { 221124a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 2212ec9fde5fSkrw char *p; 2213ec9fde5fSkrw int i; 221424a2c1a4Smillert 221534ae4198Skrw if (fstabfile && pp->p_fstype != FS_UNUSED && 221624a2c1a4Smillert pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT && 221724a2c1a4Smillert pp->p_fstype != FS_OTHER) { 2218ddaff619Smillert for (;;) { 2219c33fcabaSmillert p = getstring("mount point", 222024a2c1a4Smillert "Where to mount this filesystem (ie: / /var /usr)", 222134ae4198Skrw mountpoints[partno] ? mountpoints[partno] : "none"); 222224a2c1a4Smillert if (p == NULL) { 222324a2c1a4Smillert fputs("Command aborted\n", stderr); 222424a2c1a4Smillert return(1); 222524a2c1a4Smillert } 2226ddaff619Smillert if (strcasecmp(p, "none") == 0) { 222734ae4198Skrw free(mountpoints[partno]); 222834ae4198Skrw mountpoints[partno] = NULL; 2229ddaff619Smillert break; 2230ddaff619Smillert } 2231ec9fde5fSkrw for (i = 0; i < MAXPARTITIONS; i++) 223293160b9bSkrw if (mountpoints[i] != NULL && i != partno && 2233ec9fde5fSkrw strcmp(p, mountpoints[i]) == 0) 2234ec9fde5fSkrw break; 2235ec9fde5fSkrw if (i < MAXPARTITIONS) { 223693160b9bSkrw fprintf(stderr, "'%c' already being mounted at " 223793160b9bSkrw "'%s'\n", 'a'+i, p); 2238ec9fde5fSkrw break; 2239ec9fde5fSkrw } 2240ddaff619Smillert if (*p == '/') { 2241ddaff619Smillert /* XXX - might as well realloc */ 224234ae4198Skrw free(mountpoints[partno]); 224334ae4198Skrw if ((mountpoints[partno] = strdup(p)) == NULL) 224424a2c1a4Smillert errx(4, "out of memory"); 2245ddaff619Smillert break; 2246ddaff619Smillert } 2247ddaff619Smillert fputs("Mount points must start with '/'\n", stderr); 224824a2c1a4Smillert } 224924a2c1a4Smillert } 225024a2c1a4Smillert return(0); 225124a2c1a4Smillert } 22523f843443Smillert 22533f843443Smillert int 22548809fabbSderaadt micmp(const void *a1, const void *a2) 22553f843443Smillert { 22563f843443Smillert struct mountinfo *mi1 = (struct mountinfo *)a1; 22573f843443Smillert struct mountinfo *mi2 = (struct mountinfo *)a2; 22583f843443Smillert 22593f843443Smillert /* We want all the NULLs at the end... */ 22603f843443Smillert if (mi1->mountpoint == NULL && mi2->mountpoint == NULL) 22613f843443Smillert return(0); 22623f843443Smillert else if (mi1->mountpoint == NULL) 22633f843443Smillert return(1); 22643f843443Smillert else if (mi2->mountpoint == NULL) 22653f843443Smillert return(-1); 22663f843443Smillert else 22673f843443Smillert return(strcmp(mi1->mountpoint, mi2->mountpoint)); 22683f843443Smillert } 2269c33fcabaSmillert 2270c33fcabaSmillert void 227187023ed9Skrw get_geometry(int f, struct disklabel **dgpp) 2272c33fcabaSmillert { 2273c33fcabaSmillert struct stat st; 2274c33fcabaSmillert struct disklabel *disk_geop; 227587023ed9Skrw 2276c33fcabaSmillert if (fstat(f, &st) == -1) 2277c33fcabaSmillert err(4, "Can't stat device"); 2278c33fcabaSmillert 2279c33fcabaSmillert /* Get disk geometry */ 2280c33fcabaSmillert if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL) 2281c33fcabaSmillert errx(4, "out of memory"); 2282c33fcabaSmillert if (ioctl(f, DIOCGPDINFO, disk_geop) < 0 && 2283c33fcabaSmillert ioctl(f, DIOCGDINFO, disk_geop) < 0) 2284c33fcabaSmillert err(4, "ioctl DIOCGDINFO"); 2285c33fcabaSmillert *dgpp = disk_geop; 2286c33fcabaSmillert } 2287c33fcabaSmillert 2288c33fcabaSmillert void 22898809fabbSderaadt set_geometry(struct disklabel *lp, struct disklabel *dgp, 229087023ed9Skrw struct disklabel *ugp, char *p) 2291c33fcabaSmillert { 2292c33fcabaSmillert if (p == NULL) { 22939a36aa41Ssthen p = getstring("[d]isk or [u]ser geometry", 2294c33fcabaSmillert "Enter 'd' to use the geometry based on what the disk " 22959a36aa41Ssthen "itself thinks it is, or 'u' to use the geometry that " 22969a36aa41Ssthen "was found in the label.", 2297c33fcabaSmillert "d"); 2298c33fcabaSmillert } 2299c33fcabaSmillert if (p == NULL) { 2300c33fcabaSmillert fputs("Command aborted\n", stderr); 2301c33fcabaSmillert return; 2302c33fcabaSmillert } 2303c33fcabaSmillert switch (*p) { 2304c33fcabaSmillert case 'd': 2305c33fcabaSmillert case 'D': 2306c33fcabaSmillert if (dgp == NULL) 2307c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2308c33fcabaSmillert else { 2309c33fcabaSmillert lp->d_secsize = dgp->d_secsize; 2310c33fcabaSmillert lp->d_nsectors = dgp->d_nsectors; 2311c33fcabaSmillert lp->d_ntracks = dgp->d_ntracks; 2312c33fcabaSmillert lp->d_ncylinders = dgp->d_ncylinders; 2313c33fcabaSmillert lp->d_secpercyl = dgp->d_secpercyl; 231434af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(dgp)); 2315c33fcabaSmillert } 2316c33fcabaSmillert break; 2317c33fcabaSmillert case 'u': 2318c33fcabaSmillert case 'U': 2319c33fcabaSmillert if (ugp == NULL) 2320c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2321c33fcabaSmillert else { 2322c33fcabaSmillert lp->d_secsize = ugp->d_secsize; 2323c33fcabaSmillert lp->d_nsectors = ugp->d_nsectors; 2324c33fcabaSmillert lp->d_ntracks = ugp->d_ntracks; 2325c33fcabaSmillert lp->d_ncylinders = ugp->d_ncylinders; 2326c33fcabaSmillert lp->d_secpercyl = ugp->d_secpercyl; 232734af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(ugp)); 2328c33fcabaSmillert if (dgp != NULL && ugp->d_secsize == dgp->d_secsize && 2329c33fcabaSmillert ugp->d_nsectors == dgp->d_nsectors && 2330c33fcabaSmillert ugp->d_ntracks == dgp->d_ntracks && 2331c33fcabaSmillert ugp->d_ncylinders == dgp->d_ncylinders && 2332c33fcabaSmillert ugp->d_secpercyl == dgp->d_secpercyl && 233334af67a3Sotto DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp)) 2334c33fcabaSmillert fputs("Note: user geometry is the same as disk " 2335c33fcabaSmillert "geometry.\n", stderr); 2336c33fcabaSmillert } 2337c33fcabaSmillert break; 2338c33fcabaSmillert default: 23399a36aa41Ssthen fputs("You must enter either 'd' or 'u'.\n", stderr); 2340c33fcabaSmillert break; 2341c33fcabaSmillert } 2342c33fcabaSmillert } 23439afbe9eeSmillert 23449afbe9eeSmillert void 23459fdcb4d6Skrw zero_partitions(struct disklabel *lp) 23469afbe9eeSmillert { 23479afbe9eeSmillert int i; 23489afbe9eeSmillert 2349b4ed6301Skrw for (i = 0; i < MAXPARTITIONS; i++) { 23509afbe9eeSmillert memset(&lp->d_partitions[i], 0, sizeof(struct partition)); 2351b4ed6301Skrw free(mountpoints[i]); 2352b4ed6301Skrw mountpoints[i] = NULL; 2353b4ed6301Skrw } 2354b4ed6301Skrw 235534af67a3Sotto DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); 23569afbe9eeSmillert } 235714192793Skrw 235814192793Skrw u_int64_t 235914192793Skrw max_partition_size(struct disklabel *lp, int partno) 236014192793Skrw { 236114192793Skrw struct partition *pp = &lp->d_partitions[partno]; 236214192793Skrw struct diskchunk *chunks; 236344ffe03bSotto u_int64_t maxsize = 0, offset; 236414192793Skrw int fstype, i; 236514192793Skrw 236614192793Skrw fstype = pp->p_fstype; 236714192793Skrw pp->p_fstype = FS_UNUSED; 236814192793Skrw chunks = free_chunks(lp); 236914192793Skrw pp->p_fstype = fstype; 237014192793Skrw 237114192793Skrw offset = DL_GETPOFFSET(pp); 237214192793Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 237314192793Skrw if (offset < chunks[i].start || offset >= chunks[i].stop) 237414192793Skrw continue; 237514192793Skrw maxsize = chunks[i].stop - offset; 237614192793Skrw break; 237714192793Skrw } 237814192793Skrw return (maxsize); 237914192793Skrw } 2380aff3f969Sotto 2381aff3f969Sotto void 2382aff3f969Sotto psize(daddr64_t sz, char unit, struct disklabel *lp) 2383aff3f969Sotto { 2384aff3f969Sotto double d = scale(sz, unit, lp); 2385aff3f969Sotto if (d < 0) 2386aff3f969Sotto printf("%llu", sz); 2387aff3f969Sotto else 2388aff3f969Sotto printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit); 2389aff3f969Sotto } 2390aff3f969Sotto 2391aff3f969Sotto void 239234ae4198Skrw display_edit(struct disklabel *lp, char unit, u_int64_t fr) 2393aff3f969Sotto { 2394aff3f969Sotto int i; 2395aff3f969Sotto 2396352d199bSkrw unit = canonical_unit(lp, unit); 2397aff3f969Sotto 2398aff3f969Sotto printf("OpenBSD area: "); 239959882f1dSkrw psize(starting_sector, 0, lp); 2400aff3f969Sotto printf("-"); 240159882f1dSkrw psize(ending_sector, 0, lp); 2402aff3f969Sotto printf("; size: "); 2403aff3f969Sotto psize(ending_sector - starting_sector, unit, lp); 2404aff3f969Sotto printf("; free: "); 2405aff3f969Sotto psize(fr, unit, lp); 2406aff3f969Sotto 2407aff3f969Sotto printf("\n# %16.16s %16.16s fstype [fsize bsize cpg]\n", 2408aff3f969Sotto "size", "offset"); 2409aff3f969Sotto for (i = 0; i < lp->d_npartitions; i++) 241034ae4198Skrw display_partition(stdout, lp, i, unit); 2411aff3f969Sotto } 2412aff3f969Sotto 2413