1*44ffe03bSotto /* $OpenBSD: editor.c,v 1.228 2010/03/23 14:59:30 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; 1526aaa4aabSotto static int spoofed; 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': 3756aaa4aabSotto if (aflag && !spoofed) 3766aaa4aabSotto editor_resize(&label, arg); 3776aaa4aabSotto else 3786aaa4aabSotto fputs("Resize only implemented for auto " 3796aaa4aabSotto "allocated labels without spoofed " 3806aaa4aabSotto "partitions\n", stderr); 3816aaa4aabSotto break; 3826aaa4aabSotto 38325f9c360Skrw case 'r': { 38425f9c360Skrw struct diskchunk *chunks; 38525f9c360Skrw int i; 3869fdcb4d6Skrw /* Display free space. */ 38725f9c360Skrw chunks = free_chunks(&label); 38825f9c360Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; 38925f9c360Skrw i++) 39025f9c360Skrw fprintf(stderr, "Free sectors: %16llu - %16llu " 39125f9c360Skrw "(%16llu)\n", 39225f9c360Skrw chunks[i].start, chunks[i].stop - 1, 39325f9c360Skrw chunks[i].stop - chunks[i].start); 39425f9c360Skrw fprintf(stderr, "Total free sectors: %llu.\n", 3959fdcb4d6Skrw editor_countfree(&label)); 396c0bdc608Smillert break; 39725f9c360Skrw } 398c0bdc608Smillert 3996fe57b42Smillert case 's': 4006fe57b42Smillert if (arg == NULL) { 401c33fcabaSmillert arg = getstring("Filename", 4026fe57b42Smillert "Name of the file to save label into.", 4036fe57b42Smillert NULL); 404e97229a3Scnst if (arg == NULL || *arg == '\0') 4056fe57b42Smillert break; 4066fe57b42Smillert } 4076fe57b42Smillert if ((fp = fopen(arg, "w")) == NULL) { 4086fe57b42Smillert warn("cannot open %s", arg); 4096fe57b42Smillert } else { 41034ae4198Skrw display(fp, &label, 0, 1); 4116fe57b42Smillert (void)fclose(fp); 4126fe57b42Smillert } 4136fe57b42Smillert break; 4146fe57b42Smillert 4154f3bbbf0Skrw case 'U': 41693160b9bSkrw /* 41793160b9bSkrw * If we allow 'U' repeatedly, information would be lost. This way 41893160b9bSkrw * multiple 'U's followed by 'u' would undo the 'U's. 41993160b9bSkrw */ 42093160b9bSkrw if (memcmp(&label, &origlabel, sizeof(label)) || 42193160b9bSkrw !mpequal(mountpoints, origmountpoints)) { 4224f3bbbf0Skrw tmplabel = label; 4234f3bbbf0Skrw label = origlabel; 4244f3bbbf0Skrw lastlabel = tmplabel; 4254f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 4264f3bbbf0Skrw mpcopy(mountpoints, origmountpoints); 4274f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4284f3bbbf0Skrw } 42993160b9bSkrw puts("Original label and mount points restored."); 4304f3bbbf0Skrw break; 4314f3bbbf0Skrw 4326fe57b42Smillert case 'u': 4336fe57b42Smillert tmplabel = label; 4346fe57b42Smillert label = lastlabel; 4356fe57b42Smillert lastlabel = tmplabel; 4364f3bbbf0Skrw mpcopy(tmpmountpoints, mountpoints); 437bd6726faSmillert mpcopy(mountpoints, omountpoints); 4384f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4396fe57b42Smillert puts("Last change undone."); 4406fe57b42Smillert break; 4416fe57b42Smillert 442040947cfSmillert case 'w': 443bd6726faSmillert if (donothing) { 444040947cfSmillert puts("In no change mode, not writing label."); 445bd6726faSmillert break; 446bd6726faSmillert } 44793160b9bSkrw 44841f684b9Skrw /* Write label to disk. */ 44941f684b9Skrw if (writelabel(f, bootarea, &label) != 0) 450040947cfSmillert warnx("unable to write label"); 45171bba4ecSkrw else { 452ab20a3eaSkrw dflag = aflag = 0; 4535af08e9cSmillert *lp = label; 45471bba4ecSkrw } 455040947cfSmillert break; 456040947cfSmillert 4572d8451b0Smillert case 'X': 4582d8451b0Smillert expert = !expert; 4592d8451b0Smillert printf("%s expert mode\n", expert ? "Entering" : 4602d8451b0Smillert "Exiting"); 4612d8451b0Smillert break; 4622d8451b0Smillert 4636fe57b42Smillert case 'x': 4647e28fb0fSderaadt goto done; 4656fe57b42Smillert break; 4666fe57b42Smillert 4679afbe9eeSmillert case 'z': 4689fdcb4d6Skrw zero_partitions(&label); 4696fe57b42Smillert break; 4706fe57b42Smillert 4719afbe9eeSmillert case '\n': 4726fe57b42Smillert break; 4736fe57b42Smillert 4746fe57b42Smillert default: 4756fe57b42Smillert printf("Unknown option: %c ('?' for help)\n", *cmd); 4766fe57b42Smillert break; 4776fe57b42Smillert } 4784f3bbbf0Skrw 4794f3bbbf0Skrw /* 4804f3bbbf0Skrw * If no changes were made to label or mountpoints, then 4814f3bbbf0Skrw * restore undo info. 4824f3bbbf0Skrw */ 4834f3bbbf0Skrw if (memcmp(&label, &lastlabel, sizeof(label)) == 0 && 48493160b9bSkrw (mpequal(mountpoints, omountpoints))) { 4854f3bbbf0Skrw lastlabel = tmplabel; 4864f3bbbf0Skrw mpcopy(omountpoints, tmpmountpoints); 4874f3bbbf0Skrw } 4886fe57b42Smillert } 4897e28fb0fSderaadt done: 4907e28fb0fSderaadt free(omountpoints); 4917e28fb0fSderaadt free(origmountpoints); 4927e28fb0fSderaadt free(tmpmountpoints); 4937e28fb0fSderaadt if (disk_geop) 4947e28fb0fSderaadt free(disk_geop); 4957e28fb0fSderaadt return(error); 4966fe57b42Smillert } 4976fe57b42Smillert 4988dde8bb6Sotto int64_t 4998dde8bb6Sotto getphysmem(void) 5008dde8bb6Sotto { 5018dde8bb6Sotto int64_t physmem; 5028dde8bb6Sotto size_t sz = sizeof(physmem); 5038dde8bb6Sotto int mib[] = { CTL_HW, HW_PHYSMEM64 }; 5048dde8bb6Sotto if (sysctl(mib, 2, &physmem, &sz, NULL, (size_t)0) == -1) 5058dde8bb6Sotto errx(4, "can't get mem size"); 5068dde8bb6Sotto return physmem; 5078dde8bb6Sotto } 5088dde8bb6Sotto 5096fe57b42Smillert /* 510557f712bSkrw * Allocate all disk space according to standard recommendations for a 511557f712bSkrw * root disk. 512557f712bSkrw */ 513557f712bSkrw void 5148dde8bb6Sotto editor_allocspace(struct disklabel *lp_org) 515557f712bSkrw { 5168dde8bb6Sotto struct disklabel *lp, label; 5178dde8bb6Sotto struct space_allocation *alloc; 51834ae4198Skrw struct space_allocation *ap; 519557f712bSkrw struct partition *pp; 52034ae4198Skrw struct diskchunk *chunks; 52134ae4198Skrw daddr64_t secs, chunkstart, chunksize, cylsecs, totsecs, xtrasecs; 52234ae4198Skrw char **partmp; 5236e312d52Sotto int i, j, lastalloc, index = 0, fragsize; 5248dde8bb6Sotto int64_t physmem; 5258dde8bb6Sotto 5266aaa4aabSotto spoofed = 0; 5276aaa4aabSotto for (i = 0; i < MAXPARTITIONS; i++) 5286aaa4aabSotto if (i != RAW_PART && DL_GETPSIZE(&lp_org->d_partitions[i]) != 0) 5296aaa4aabSotto spoofed = 1; 5306aaa4aabSotto 5318dde8bb6Sotto physmem = getphysmem() / lp_org->d_secsize; 53234ae4198Skrw 53334ae4198Skrw /* How big is the OpenBSD portion of the disk? */ 5348dde8bb6Sotto find_bounds(lp_org); 535557f712bSkrw 5368dde8bb6Sotto cylsecs = lp_org->d_secpercyl; 5378dde8bb6Sotto again: 5388dde8bb6Sotto lp = &label; 5393d98fc8cSkrw for (i=0; i<MAXPARTITIONS; i++) { 5403d98fc8cSkrw free(mountpoints[i]); 5413d98fc8cSkrw mountpoints[i] = NULL; 5423d98fc8cSkrw } 5438dde8bb6Sotto memcpy(lp, lp_org, sizeof(struct disklabel)); 5440a7398ceSderaadt lp->d_npartitions = MAXPARTITIONS; 5458dde8bb6Sotto lastalloc = alloc_table[index].sz; 5468dde8bb6Sotto alloc = malloc(lastalloc * sizeof(struct space_allocation)); 5478dde8bb6Sotto if (alloc == NULL) 5488dde8bb6Sotto errx(4, "out of memory"); 5498dde8bb6Sotto memcpy(alloc, alloc_table[index].table, 5508dde8bb6Sotto lastalloc * sizeof(struct space_allocation)); 5518dde8bb6Sotto 5528dde8bb6Sotto /* bump max swap based on phys mem, little physmem gets 2x swap */ 5538dde8bb6Sotto if (index == 0) { 5548dde8bb6Sotto if (physmem < 256LL * 1024 * 1024 / lp->d_secsize) 5558dde8bb6Sotto alloc[1].maxsz = 2 * physmem; 5568dde8bb6Sotto else 5578dde8bb6Sotto alloc[1].maxsz += physmem; 5588dde8bb6Sotto /* bump max /var to make room for 2 crash dumps */ 5598dde8bb6Sotto alloc[3].maxsz += 2 * physmem; 5608dde8bb6Sotto } 5618dde8bb6Sotto 56234ae4198Skrw xtrasecs = totsecs = editor_countfree(lp); 563557f712bSkrw 56434ae4198Skrw for (i = 0; i < lastalloc; i++) { 5655f3e1104Skrw alloc[i].minsz = DL_BLKTOSEC(lp, alloc[i].minsz); 5665f3e1104Skrw alloc[i].maxsz = DL_BLKTOSEC(lp, alloc[i].maxsz); 56734ae4198Skrw if (xtrasecs > alloc[i].minsz) 56834ae4198Skrw xtrasecs -= alloc[i].minsz; 56934ae4198Skrw else 57034ae4198Skrw xtrasecs = 0; 571557f712bSkrw } 572557f712bSkrw 57334ae4198Skrw for (i = 0; i < lastalloc; i++) { 57434ae4198Skrw /* Find next available partition. */ 57534ae4198Skrw for (j = 0; j < MAXPARTITIONS; j++) 57634ae4198Skrw if (DL_GETPSIZE(&lp->d_partitions[j]) == 0) 57734ae4198Skrw break; 57834ae4198Skrw if (j == MAXPARTITIONS) 57934ae4198Skrw return; 58034ae4198Skrw pp = &lp->d_partitions[j]; 58134ae4198Skrw partmp = &mountpoints[j]; 58234ae4198Skrw ap = &alloc[i]; 583557f712bSkrw 58434ae4198Skrw /* Figure out the size of the partition. */ 58534ae4198Skrw if (i == lastalloc - 1) { 58634ae4198Skrw if (totsecs > ap->maxsz) 58734ae4198Skrw secs = ap->maxsz; 588557f712bSkrw else 5895f3e1104Skrw secs = totsecs; 5901f5ea549Skrw #ifdef SUN_CYLCHECK 5911f5ea549Skrw goto cylinderalign; 5921f5ea549Skrw #endif 593557f712bSkrw } else { 59434ae4198Skrw secs = ap->minsz; 5955f3e1104Skrw if (xtrasecs > 0) 59634ae4198Skrw secs += (xtrasecs / 100) * ap->rate; 59734ae4198Skrw if (secs > ap->maxsz) 59834ae4198Skrw secs = ap->maxsz; 5991f5ea549Skrw #ifdef SUN_CYLCHECK 6001f5ea549Skrw cylinderalign: 6015f3e1104Skrw secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; 6021f5ea549Skrw #endif 6035f3e1104Skrw totsecs -= secs; 6041f5ea549Skrw #ifdef SUN_CYLCHECK 6055f3e1104Skrw while (totsecs < 0) { 6065f3e1104Skrw secs -= cylsecs; 6075f3e1104Skrw totsecs += cylsecs; 608557f712bSkrw } 6091f5ea549Skrw #endif 610557f712bSkrw } 61134ae4198Skrw 61234ae4198Skrw /* Find largest chunk of free space. */ 61334ae4198Skrw chunks = free_chunks(lp); 61434ae4198Skrw chunkstart = 0; 61534ae4198Skrw chunksize = 0; 61634ae4198Skrw for (j = 0; chunks[j].start != 0 || chunks[j].stop != 0; j++) 61734ae4198Skrw if ((chunks[j].stop - chunks[j].start) > chunksize) { 61834ae4198Skrw chunkstart = chunks[j].start; 61934ae4198Skrw chunksize = chunks[j].stop - chunks[j].start; 620557f712bSkrw } 62134ae4198Skrw #ifdef SUN_CYLCHECK 62234ae4198Skrw if (lp->d_flags & D_VENDOR) { 62334ae4198Skrw /* Align chunk to cylinder boundaries. */ 62434ae4198Skrw chunksize -= chunksize % cylsecs; 6256ab0bb66Skrw chunkstart = ((chunkstart + cylsecs - 1) / cylsecs) * 6266ab0bb66Skrw cylsecs; 62734ae4198Skrw } 62834ae4198Skrw #endif 62934ae4198Skrw /* See if partition can fit into chunk. */ 63034ae4198Skrw if (secs > chunksize) { 63134ae4198Skrw totsecs += secs - chunksize; 63234ae4198Skrw secs = chunksize; 63334ae4198Skrw } 63434ae4198Skrw if (secs < ap->minsz) { 6358dde8bb6Sotto /* It did not work out, try next strategy */ 6368dde8bb6Sotto free(alloc); 6378dde8bb6Sotto if (++index < nitems(alloc_table)) 6388dde8bb6Sotto goto again; 6398dde8bb6Sotto else 6408dde8bb6Sotto return; 641557f712bSkrw } 64234ae4198Skrw 64334ae4198Skrw /* Everything seems ok so configure the partition. */ 6445f3e1104Skrw DL_SETPSIZE(pp, secs); 64534ae4198Skrw DL_SETPOFFSET(pp, chunkstart); 6466e312d52Sotto fragsize = 2048; 6476e312d52Sotto if (secs > 512ULL * 1024 * 1024 * 1024 / lp->d_secsize) 6486e312d52Sotto fragsize *= 4; 649557f712bSkrw #if defined (__sparc__) && !defined(__sparc64__) 650557f712bSkrw /* can't boot from > 8k boot blocks */ 651557f712bSkrw pp->p_fragblock = 6526e312d52Sotto DISKLABELV1_FFS_FRAGBLOCK(i == 0 ? 1024 : fragsize, 8); 653557f712bSkrw #else 6546e312d52Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8); 655557f712bSkrw #endif 656557f712bSkrw pp->p_cpg = 1; 65734ae4198Skrw if (ap->mp[0] != '/') 65834ae4198Skrw pp->p_fstype = FS_SWAP; 65934ae4198Skrw else { 66034ae4198Skrw pp->p_fstype = FS_BSDFFS; 66134ae4198Skrw free(*partmp); 66234ae4198Skrw if ((*partmp = strdup(ap->mp)) == NULL) 663557f712bSkrw errx(4, "out of memory"); 664557f712bSkrw } 665557f712bSkrw } 666557f712bSkrw 6678dde8bb6Sotto free(alloc); 6688dde8bb6Sotto memcpy(lp_org, lp, sizeof(struct disklabel)); 669557f712bSkrw } 670557f712bSkrw 671557f712bSkrw /* 6726aaa4aabSotto * Resize a partition, moving all subsequent partitions 6736aaa4aabSotto */ 6746aaa4aabSotto void 6756aaa4aabSotto editor_resize(struct disklabel *lp, char *p) 6766aaa4aabSotto { 6776aaa4aabSotto struct disklabel label; 6786aaa4aabSotto struct partition *pp, *prev; 6796aaa4aabSotto daddr64_t secs, sz, off; 6806aaa4aabSotto #ifdef SUN_CYLCHECK 6816aaa4aabSotto daddr64_t cylsecs; 6826aaa4aabSotto #endif 6836aaa4aabSotto int partno, i; 6846aaa4aabSotto 6856aaa4aabSotto label = *lp; 6866aaa4aabSotto 6876aaa4aabSotto /* Change which partition? */ 6886aaa4aabSotto if (p == NULL) { 6896aaa4aabSotto p = getstring("partition to resize", 6906aaa4aabSotto "The letter of the partition to name, a - p.", NULL); 6916aaa4aabSotto } 6926aaa4aabSotto if (p == NULL) { 6936aaa4aabSotto fputs("Command aborted\n", stderr); 6946aaa4aabSotto return; 6956aaa4aabSotto } 6966aaa4aabSotto partno = p[0] - 'a'; 6976aaa4aabSotto if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 6986aaa4aabSotto fprintf(stderr, "Partition must be between 'a' and '%c' " 6996aaa4aabSotto "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 7006aaa4aabSotto return; 7016aaa4aabSotto } 7026aaa4aabSotto 7036aaa4aabSotto pp = &label.d_partitions[partno]; 7046aaa4aabSotto sz = editor_countfree(lp); 7056aaa4aabSotto secs = getuint(lp, "resize", "amount to grow (+) or shrink (-)", 7066aaa4aabSotto 0, sz, 0, DO_CONVERSIONS); 7076aaa4aabSotto 7086aaa4aabSotto if (secs == 0) { 7096aaa4aabSotto fputs("Command aborted\n", stderr); 7106aaa4aabSotto return; 7116aaa4aabSotto } 7126aaa4aabSotto 7136aaa4aabSotto #ifdef SUN_CYLCHECK 7146aaa4aabSotto cylsecs = lp->d_secpercyl; 7156aaa4aabSotto if (secs > 0) 7166aaa4aabSotto secs = ((secs + cylsecs - 1) / cylsecs) * cylsecs; 7176aaa4aabSotto else 7186aaa4aabSotto secs = ((secs - cylsecs + 1) / cylsecs) * cylsecs; 7196aaa4aabSotto #endif 7206aaa4aabSotto 7216aaa4aabSotto sz = DL_GETPSIZE(pp); 7226aaa4aabSotto if (sz == 0) { 7236aaa4aabSotto fputs("No such parititon\n", stderr); 7246aaa4aabSotto return; 7256aaa4aabSotto } 7266aaa4aabSotto if (DL_GETPOFFSET(pp) + sz + secs > ending_sector) { 7276aaa4aabSotto fputs("Amount too big\n", stderr); 7286aaa4aabSotto return; 7296aaa4aabSotto } 7306aaa4aabSotto if (sz + secs < 0) { 7316aaa4aabSotto fputs("Amount too small\n", stderr); 7326aaa4aabSotto return; 7336aaa4aabSotto } 7346aaa4aabSotto 7356aaa4aabSotto DL_SETPSIZE(pp, sz + secs); 7366aaa4aabSotto 7376aaa4aabSotto /* 7386aaa4aabSotto * Pack partitions above the resized partition, leaving unused 7396aaa4aabSotto * partions alone. 7406aaa4aabSotto */ 7416aaa4aabSotto prev = pp; 7426aaa4aabSotto for (i = partno + 1; i < MAXPARTITIONS; i++) { 7436aaa4aabSotto if (i == RAW_PART) 7446aaa4aabSotto continue; 7456aaa4aabSotto sz = DL_GETPSIZE(&label.d_partitions[i]); 7466aaa4aabSotto if (sz == 0) 7476aaa4aabSotto continue; 7486aaa4aabSotto 7496aaa4aabSotto pp = &label.d_partitions[i]; 7506aaa4aabSotto off = DL_GETPOFFSET(prev) + DL_GETPSIZE(prev); 7516aaa4aabSotto 7526aaa4aabSotto if (off < ending_sector) { 7536aaa4aabSotto DL_SETPOFFSET(pp, off); 7546aaa4aabSotto if (off + DL_GETPSIZE(pp) > ending_sector) { 7556aaa4aabSotto DL_SETPSIZE(pp, ending_sector - off); 7566aaa4aabSotto fprintf(stderr, 7576aaa4aabSotto "Partition %c shrunk to make room\n", 7586aaa4aabSotto i + 'a'); 7596aaa4aabSotto } 7606aaa4aabSotto } else { 7616aaa4aabSotto fputs("No room left for all partitions\n", stderr); 7626aaa4aabSotto return; 7636aaa4aabSotto } 7646aaa4aabSotto prev = pp; 7656aaa4aabSotto } 7666aaa4aabSotto *lp = label; 7676aaa4aabSotto } 7686aaa4aabSotto 7696aaa4aabSotto /* 7706fe57b42Smillert * Add a new partition. 7716fe57b42Smillert */ 7726fe57b42Smillert void 77334ae4198Skrw editor_add(struct disklabel *lp, char *p) 7746fe57b42Smillert { 77596a888c6Smillert struct partition *pp; 77696a888c6Smillert struct diskchunk *chunks; 7775caa08b2Skrw char buf[2]; 7786e312d52Sotto int i, partno, fragsize; 779f8ab7229Schl u_int64_t freesectors, new_offset, new_size; 7809fdcb4d6Skrw 7819fdcb4d6Skrw freesectors = editor_countfree(lp); 7826fe57b42Smillert 7836fe57b42Smillert /* XXX - prompt user to steal space from another partition instead */ 784fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 7859fdcb4d6Skrw if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) { 786fc1a4cc6Sderaadt fputs("No space left, you need to shrink a partition " 787fc1a4cc6Sderaadt "(need at least one full cylinder)\n", 788fc1a4cc6Sderaadt stderr); 789fc1a4cc6Sderaadt return; 790fc1a4cc6Sderaadt } 7918390cf28Smillert #endif 7929fdcb4d6Skrw if (freesectors == 0) { 7936fe57b42Smillert fputs("No space left, you need to shrink a partition\n", 7946fe57b42Smillert stderr); 7956fe57b42Smillert return; 7966fe57b42Smillert } 7976fe57b42Smillert 7985caa08b2Skrw if (p == NULL) { 7995caa08b2Skrw /* 8005caa08b2Skrw * Use the first unused partition that is not 'c' as the 8015caa08b2Skrw * default partition in the prompt string. 8025caa08b2Skrw */ 8035caa08b2Skrw pp = &lp->d_partitions[0]; 8045caa08b2Skrw buf[0] = buf[1] = '\0'; 8055caa08b2Skrw for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) { 8065caa08b2Skrw if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) { 8075caa08b2Skrw buf[0] = partno + 'a'; 8085caa08b2Skrw p = &buf[0]; 8096fe57b42Smillert break; 8106fe57b42Smillert } 8115caa08b2Skrw } 812c33fcabaSmillert p = getstring("partition", 8136fe57b42Smillert "The letter of the new partition, a - p.", p); 8146fe57b42Smillert } 8155caa08b2Skrw if (p == NULL) { 8165caa08b2Skrw fputs("Command aborted\n", stderr); 8175caa08b2Skrw return; 8185caa08b2Skrw } 8195caa08b2Skrw partno = p[0] - 'a'; 8205caa08b2Skrw if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) { 8215caa08b2Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 8225caa08b2Skrw "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1); 8235caa08b2Skrw return; 8245caa08b2Skrw } 8255caa08b2Skrw pp = &lp->d_partitions[partno]; 8265caa08b2Skrw 8275caa08b2Skrw if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) { 8285caa08b2Skrw fprintf(stderr, "Partition '%c' exists. Delete it first.\n", 8295caa08b2Skrw p[0]); 8305caa08b2Skrw return; 8316fe57b42Smillert } 83296a888c6Smillert 833caf41f96Skrw /* 834caf41f96Skrw * Increase d_npartitions if necessary. Ensure all new partitions are 835855d4e83Ssobrado * zero'ed to avoid inadvertent overlaps. 836caf41f96Skrw */ 837caf41f96Skrw for(; lp->d_npartitions <= partno; lp->d_npartitions++) 838caf41f96Skrw memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp)); 83996a888c6Smillert 84089f4601dSkrw /* Make sure selected partition is zero'd too. */ 84189f4601dSkrw memset(pp, 0, sizeof(*pp)); 84215c15d8aSkrw chunks = free_chunks(lp); 84315c15d8aSkrw 84415c15d8aSkrw /* 84515c15d8aSkrw * Since we know there's free space, there must be at least one 84615c15d8aSkrw * chunk. So find the largest chunk and assume we want to add the 84715c15d8aSkrw * partition in that free space. 84815c15d8aSkrw */ 84915c15d8aSkrw new_size = new_offset = 0; 85015c15d8aSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 85115c15d8aSkrw if (chunks[i].stop - chunks[i].start > new_size) { 85215c15d8aSkrw new_size = chunks[i].stop - chunks[i].start; 85315c15d8aSkrw new_offset = chunks[i].start; 85415c15d8aSkrw } 85515c15d8aSkrw } 8561e0ad43cSotto DL_SETPSIZE(pp, new_size); 8571e0ad43cSotto DL_SETPOFFSET(pp, new_offset); 85896a888c6Smillert pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS; 8596e312d52Sotto fragsize = 2048; 8606e312d52Sotto if (new_size > 512ULL * 1024 * 1024 * 1024 / lp->d_secsize) 8616e312d52Sotto fragsize *= 4; 8624a8b9208Stedu #if defined (__sparc__) && !defined(__sparc64__) 863d98d4df7Stedu /* can't boot from > 8k boot blocks */ 864ddfcbf38Sotto pp->p_fragblock = 8656e312d52Sotto DISKLABELV1_FFS_FRAGBLOCK(partno == 0 ? 1024 : fragsize, 8); 866d98d4df7Stedu #else 8676e312d52Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(fragsize, 8); 868d98d4df7Stedu #endif 8699b972314Skrw pp->p_cpg = 1; 87096a888c6Smillert 871a4c87e64Skrw if (get_offset(lp, partno) == 0 && 872a4c87e64Skrw get_size(lp, partno) == 0 && 873a4c87e64Skrw get_fstype(lp, partno) == 0 && 87434ae4198Skrw get_mp(lp, partno) == 0 && 875a4c87e64Skrw get_fsize(lp, partno) == 0 && 876a4c87e64Skrw get_bsize(lp, partno) == 0) 87796a888c6Smillert return; 87896a888c6Smillert 879a4c87e64Skrw /* Bailed out at some point, so effectively delete the partition. */ 880a4c87e64Skrw DL_SETPSIZE(pp, 0); 8816fe57b42Smillert } 8826fe57b42Smillert 8836fe57b42Smillert /* 884bd6726faSmillert * Set the mountpoint of an existing partition ('name'). 885bd6726faSmillert */ 886bd6726faSmillert void 88734ae4198Skrw editor_name(struct disklabel *lp, char *p) 888bd6726faSmillert { 889bd6726faSmillert struct partition *pp; 890bd6726faSmillert int partno; 891bd6726faSmillert 892bd6726faSmillert /* Change which partition? */ 893bd6726faSmillert if (p == NULL) { 894c33fcabaSmillert p = getstring("partition to name", 895bd6726faSmillert "The letter of the partition to name, a - p.", NULL); 896bd6726faSmillert } 897bd6726faSmillert if (p == NULL) { 898bd6726faSmillert fputs("Command aborted\n", stderr); 899bd6726faSmillert return; 900bd6726faSmillert } 901bd6726faSmillert partno = p[0] - 'a'; 9026c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9036c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9046c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 905bd6726faSmillert return; 90666df1f0cSkrw } 90766df1f0cSkrw pp = &lp->d_partitions[partno]; 90866df1f0cSkrw 90966df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 91066df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 911bd6726faSmillert return; 912bd6726faSmillert } 913bd6726faSmillert 914bd6726faSmillert /* Not all fstypes can be named */ 915bd6726faSmillert if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP || 916bd387921Stodd pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER || 917bd387921Stodd pp->p_fstype == FS_RAID) { 918bd6726faSmillert fprintf(stderr, "You cannot name a filesystem of type %s.\n", 919baa55472Smillert fstypenames[lp->d_partitions[partno].p_fstype]); 920bd6726faSmillert return; 921bd6726faSmillert } 922bd6726faSmillert 92334ae4198Skrw get_mp(lp, partno); 924bd6726faSmillert } 925bd6726faSmillert 926bd6726faSmillert /* 9276fe57b42Smillert * Change an existing partition. 9286fe57b42Smillert */ 9296fe57b42Smillert void 93034ae4198Skrw editor_modify(struct disklabel *lp, char *p) 9316fe57b42Smillert { 9326fe57b42Smillert struct partition origpart, *pp; 933f8ab7229Schl int partno; 9346fe57b42Smillert 9356fe57b42Smillert /* Change which partition? */ 9366fe57b42Smillert if (p == NULL) { 937c33fcabaSmillert p = getstring("partition to modify", 9386fe57b42Smillert "The letter of the partition to modify, a - p.", NULL); 9396fe57b42Smillert } 94096a888c6Smillert if (p == NULL) { 94196a888c6Smillert fputs("Command aborted\n", stderr); 94296a888c6Smillert return; 94396a888c6Smillert } 9446fe57b42Smillert partno = p[0] - 'a'; 9456c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9466c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9476c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 9486fe57b42Smillert return; 94966df1f0cSkrw } 95066df1f0cSkrw pp = &lp->d_partitions[partno]; 95166df1f0cSkrw 95266df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 95366df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 9546fe57b42Smillert return; 9556fe57b42Smillert } 9566fe57b42Smillert 95766df1f0cSkrw origpart = *pp; 95866df1f0cSkrw 959a4c87e64Skrw if (get_offset(lp, partno) == 0 && 960a4c87e64Skrw get_size(lp, partno) == 0 && 961a4c87e64Skrw get_fstype(lp, partno) == 0 && 96234ae4198Skrw get_mp(lp, partno) == 0 && 963a4c87e64Skrw get_fsize(lp, partno) == 0 && 964a4c87e64Skrw get_bsize(lp, partno) == 0) 96596a888c6Smillert return; 9666fe57b42Smillert 967a4c87e64Skrw /* Bailed out at some point, so undo any changes. */ 968a4c87e64Skrw *pp = origpart; 9696fe57b42Smillert } 9706fe57b42Smillert 9716fe57b42Smillert /* 9726fe57b42Smillert * Delete an existing partition. 9736fe57b42Smillert */ 9746fe57b42Smillert void 97534ae4198Skrw editor_delete(struct disklabel *lp, char *p) 9766fe57b42Smillert { 97766df1f0cSkrw struct partition *pp; 978135c90d1Skrw int partno; 9796fe57b42Smillert 9806fe57b42Smillert if (p == NULL) { 981c33fcabaSmillert p = getstring("partition to delete", 982945ae268Smillert "The letter of the partition to delete, a - p, or '*'.", 983945ae268Smillert NULL); 9846fe57b42Smillert } 98596a888c6Smillert if (p == NULL) { 98696a888c6Smillert fputs("Command aborted\n", stderr); 98796a888c6Smillert return; 98896a888c6Smillert } 989945ae268Smillert if (p[0] == '*') { 9909fdcb4d6Skrw zero_partitions(lp); 991945ae268Smillert return; 992945ae268Smillert } 993135c90d1Skrw partno = p[0] - 'a'; 994135c90d1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 9956c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 9966c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 99733262abfSmiod return; 99866df1f0cSkrw } 999135c90d1Skrw pp = &lp->d_partitions[partno]; 100066df1f0cSkrw 100166df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 100266df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 100333262abfSmiod return; 100466df1f0cSkrw } 100566df1f0cSkrw 10066fe57b42Smillert /* Really delete it (as opposed to just setting to "unused") */ 1007135c90d1Skrw memset(pp, 0, sizeof(*pp)); 100834ae4198Skrw free(mountpoints[partno]); 100934ae4198Skrw mountpoints[partno] = NULL; 10106fe57b42Smillert } 10116fe57b42Smillert 10126fe57b42Smillert /* 10136fe57b42Smillert * Change the size of an existing partition. 10146fe57b42Smillert */ 10156fe57b42Smillert void 10169fdcb4d6Skrw editor_change(struct disklabel *lp, char *p) 10176fe57b42Smillert { 10184b9a3bdaSmillert struct partition *pp; 101966df1f0cSkrw int partno; 10206fe57b42Smillert 10216fe57b42Smillert if (p == NULL) { 1022c33fcabaSmillert p = getstring("partition to change size", 10236fe57b42Smillert "The letter of the partition to change size, a - p.", NULL); 10246fe57b42Smillert } 102596a888c6Smillert if (p == NULL) { 102696a888c6Smillert fputs("Command aborted\n", stderr); 102796a888c6Smillert return; 102896a888c6Smillert } 10296fe57b42Smillert partno = p[0] - 'a'; 10306c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 10316c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 10326c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 10336fe57b42Smillert return; 10346fe57b42Smillert } 10354b9a3bdaSmillert pp = &lp->d_partitions[partno]; 10366fe57b42Smillert 103766df1f0cSkrw if (DL_GETPSIZE(pp) == 0) { 103866df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 103966df1f0cSkrw return; 104066df1f0cSkrw } 104166df1f0cSkrw 104214192793Skrw printf("Partition %c is currently %llu sectors in size, and can have " 104314192793Skrw "a maximum\nsize of %llu sectors.\n", 104414192793Skrw p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno)); 10457da73705Skrw 104659ccf790Skrw /* Get new size */ 10479fdcb4d6Skrw get_size(lp, partno); 10486fe57b42Smillert } 10496fe57b42Smillert 10506fe57b42Smillert /* 10516fe57b42Smillert * Sort the partitions based on starting offset. 10526fe57b42Smillert * This assumes there can be no overlap. 10536fe57b42Smillert */ 10546fe57b42Smillert int 10558809fabbSderaadt partition_cmp(const void *e1, const void *e2) 10566fe57b42Smillert { 10576fe57b42Smillert struct partition *p1 = *(struct partition **)e1; 10586fe57b42Smillert struct partition *p2 = *(struct partition **)e2; 10591e0ad43cSotto u_int64_t o1 = DL_GETPOFFSET(p1); 10601e0ad43cSotto u_int64_t o2 = DL_GETPOFFSET(p2); 10616fe57b42Smillert 10621e0ad43cSotto if (o1 < o2) 1063651d5bd9Sotto return -1; 10641e0ad43cSotto else if (o1 > o2) 1065651d5bd9Sotto return 1; 1066651d5bd9Sotto else 1067651d5bd9Sotto return 0; 10686fe57b42Smillert } 10696fe57b42Smillert 10706fe57b42Smillert char * 10718809fabbSderaadt getstring(char *prompt, char *helpstring, char *oval) 10726fe57b42Smillert { 10736fe57b42Smillert static char buf[BUFSIZ]; 10746fe57b42Smillert int n; 10756fe57b42Smillert 10766fe57b42Smillert buf[0] = '\0'; 10776fe57b42Smillert do { 10786fe57b42Smillert printf("%s: [%s] ", prompt, oval ? oval : ""); 10796e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1080260513deSmillert buf[0] = '\0'; 108196a888c6Smillert if (feof(stdin)) { 108224c6582eSmillert clearerr(stdin); 108396a888c6Smillert putchar('\n'); 108496a888c6Smillert return(NULL); 108596a888c6Smillert } 10866e0becc5Smillert } 10876fe57b42Smillert n = strlen(buf); 10886fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 10896fe57b42Smillert buf[--n] = '\0'; 10906fe57b42Smillert if (buf[0] == '?') 10916fe57b42Smillert puts(helpstring); 10924fb6ab7cSmillert else if (oval != NULL && buf[0] == '\0') 10934fb6ab7cSmillert strlcpy(buf, oval, sizeof(buf)); 10946fe57b42Smillert } while (buf[0] == '?'); 10956fe57b42Smillert 10966fe57b42Smillert return(&buf[0]); 10976fe57b42Smillert } 10986fe57b42Smillert 10996fe57b42Smillert /* 11001e0ad43cSotto * Returns ULLONG_MAX on error 110124a2c1a4Smillert * Usually only called by helper functions. 11026fe57b42Smillert */ 11031e0ad43cSotto u_int64_t 1104dea75673Skrw getuint(struct disklabel *lp, char *prompt, char *helpstring, 11051e0ad43cSotto u_int64_t oval, u_int64_t maxval, u_int64_t offset, int flags) 11066fe57b42Smillert { 11076fe57b42Smillert char buf[BUFSIZ], *endptr, *p, operator = '\0'; 11081e0ad43cSotto u_int64_t rval = oval; 11096fe57b42Smillert size_t n; 11106fe57b42Smillert int mult = 1; 111114cc915fSmillert double d, percent = 1.0; 11126fe57b42Smillert 11134b9a3bdaSmillert /* We only care about the remainder */ 11144b9a3bdaSmillert offset = offset % lp->d_secpercyl; 11154b9a3bdaSmillert 11166fe57b42Smillert buf[0] = '\0'; 11176fe57b42Smillert do { 11181e0ad43cSotto printf("%s: [%llu] ", prompt, oval); 11196e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 11206e0becc5Smillert buf[0] = '\0'; 112196a888c6Smillert if (feof(stdin)) { 112224c6582eSmillert clearerr(stdin); 112396a888c6Smillert putchar('\n'); 11241e0ad43cSotto return(ULLONG_MAX - 1); 112596a888c6Smillert } 11266e0becc5Smillert } 11276fe57b42Smillert n = strlen(buf); 11286fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 11296fe57b42Smillert buf[--n] = '\0'; 11306fe57b42Smillert if (buf[0] == '?') 11316fe57b42Smillert puts(helpstring); 11326fe57b42Smillert } while (buf[0] == '?'); 11336fe57b42Smillert 11346fe57b42Smillert if (buf[0] == '*' && buf[1] == '\0') { 11356fe57b42Smillert rval = maxval; 11366fe57b42Smillert } else { 11376fe57b42Smillert /* deal with units */ 11386fe57b42Smillert if (buf[0] != '\0' && n > 0) { 11396fe57b42Smillert if ((flags & DO_CONVERSIONS)) { 114096a888c6Smillert switch (tolower(buf[n-1])) { 11416fe57b42Smillert 11426fe57b42Smillert case 'c': 11436fe57b42Smillert mult = lp->d_secpercyl; 11446fe57b42Smillert buf[--n] = '\0'; 11456fe57b42Smillert break; 11466fe57b42Smillert case 'b': 11476fe57b42Smillert mult = -lp->d_secsize; 11486fe57b42Smillert buf[--n] = '\0'; 11496fe57b42Smillert break; 11506fe57b42Smillert case 'k': 115150c0f47aSkrw if (lp->d_secsize > 1024) 115250c0f47aSkrw mult = -lp->d_secsize / 1024; 115350c0f47aSkrw else 11546fe57b42Smillert mult = 1024 / lp->d_secsize; 11556fe57b42Smillert buf[--n] = '\0'; 11566fe57b42Smillert break; 11576fe57b42Smillert case 'm': 11586fe57b42Smillert mult = 1048576 / lp->d_secsize; 11596fe57b42Smillert buf[--n] = '\0'; 11606fe57b42Smillert break; 11611a51a1eeSmillert case 'g': 11621a51a1eeSmillert mult = 1073741824 / lp->d_secsize; 11631a51a1eeSmillert buf[--n] = '\0'; 11641a51a1eeSmillert break; 116514cc915fSmillert case '%': 116614cc915fSmillert buf[--n] = '\0'; 116714cc915fSmillert percent = strtod(buf, NULL) / 100.0; 11681e0ad43cSotto snprintf(buf, sizeof(buf), "%lld", 11691e0ad43cSotto DL_GETDSIZE(lp)); 117014cc915fSmillert break; 117114cc915fSmillert case '&': 117214cc915fSmillert buf[--n] = '\0'; 117314cc915fSmillert percent = strtod(buf, NULL) / 100.0; 11741e0ad43cSotto snprintf(buf, sizeof(buf), "%lld", 117514cc915fSmillert maxval); 117614cc915fSmillert break; 11776fe57b42Smillert } 117896a888c6Smillert } 11796fe57b42Smillert 11806fe57b42Smillert /* Did they give us an operator? */ 11816fe57b42Smillert p = &buf[0]; 11826fe57b42Smillert if (*p == '+' || *p == '-') 11836fe57b42Smillert operator = *p++; 11846fe57b42Smillert 11856fe57b42Smillert endptr = p; 118696a888c6Smillert errno = 0; 118796a888c6Smillert d = strtod(p, &endptr); 118896a888c6Smillert if (errno == ERANGE) 11891e0ad43cSotto rval = ULLONG_MAX; /* too big/small */ 119096a888c6Smillert else if (*endptr != '\0') { 11916fe57b42Smillert errno = EINVAL; /* non-numbers in str */ 11921e0ad43cSotto rval = ULLONG_MAX; 11936fe57b42Smillert } else { 119496a888c6Smillert /* XXX - should check for overflow */ 119596a888c6Smillert if (mult > 0) 119614cc915fSmillert rval = d * mult * percent; 119796a888c6Smillert else 119896a888c6Smillert /* Negative mult means divide (fancy) */ 119914cc915fSmillert rval = d / (-mult) * percent; 12006fe57b42Smillert 120196a888c6Smillert /* Apply the operator */ 12026fe57b42Smillert if (operator == '+') 12036fe57b42Smillert rval += oval; 12046fe57b42Smillert else if (operator == '-') 12056fe57b42Smillert rval = oval - rval; 12066fe57b42Smillert } 12076fe57b42Smillert } 12086fe57b42Smillert } 12098390cf28Smillert if ((flags & DO_ROUNDING) && rval != ULLONG_MAX) { 121096a888c6Smillert /* Round to nearest cylinder unless given in sectors */ 12118390cf28Smillert if ( 1212fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 1213fc1a4cc6Sderaadt ((lp->d_flags & D_VENDOR) || mult != 1) && 1214fc1a4cc6Sderaadt #else 12158390cf28Smillert mult != 1 && 1216dbffb156Smillert #endif 12178390cf28Smillert (rval + offset) % lp->d_secpercyl != 0) { 12181e0ad43cSotto u_int64_t cyls; 1219dbffb156Smillert 12208390cf28Smillert /* Round to higher cylinder but no more than maxval */ 12218390cf28Smillert cyls = (rval / lp->d_secpercyl) + 1; 12228390cf28Smillert if ((cyls * lp->d_secpercyl) - offset > maxval) 1223dbffb156Smillert cyls--; 12244b9a3bdaSmillert rval = (cyls * lp->d_secpercyl) - offset; 12258390cf28Smillert printf("Rounding to cylinder: %llu\n", rval); 12266fe57b42Smillert } 12274b9a3bdaSmillert } 12286fe57b42Smillert 12296fe57b42Smillert return(rval); 12306fe57b42Smillert } 12316fe57b42Smillert 12326fe57b42Smillert /* 12331f0f871dSkrw * Check for partition overlap in lp and prompt the user to resolve the overlap 12341f0f871dSkrw * if any is found. Returns 1 if unable to resolve, else 0. 12356fe57b42Smillert */ 12366fe57b42Smillert int 12371f0f871dSkrw has_overlap(struct disklabel *lp) 12386fe57b42Smillert { 12396fe57b42Smillert struct partition **spp; 1240e6aa8bafSmillert int c, i, j; 1241e6aa8bafSmillert char buf[BUFSIZ]; 12426fe57b42Smillert 12430fbd3c97Skrw /* Get a sorted list of the in-use partitions. */ 12440fbd3c97Skrw spp = sort_partitions(lp); 12456fe57b42Smillert 12460fbd3c97Skrw /* If there are less than two partitions in use, there is no overlap. */ 12470fbd3c97Skrw if (spp[1] == NULL) 12480fbd3c97Skrw return(0); 12496fe57b42Smillert 12506fe57b42Smillert /* Now that we have things sorted by starting sector check overlap */ 12510fbd3c97Skrw for (i = 0; spp[i] != NULL; i++) { 12520fbd3c97Skrw for (j = i + 1; spp[j] != NULL; j++) { 12536fe57b42Smillert /* `if last_sec_in_part + 1 > first_sec_in_next_part' */ 12541e0ad43cSotto if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) > DL_GETPOFFSET(spp[j])) { 12556fe57b42Smillert /* Overlap! Convert to real part numbers. */ 12566fe57b42Smillert i = ((char *)spp[i] - (char *)lp->d_partitions) 12576fe57b42Smillert / sizeof(**spp); 12586fe57b42Smillert j = ((char *)spp[j] - (char *)lp->d_partitions) 12596fe57b42Smillert / sizeof(**spp); 12606fe57b42Smillert printf("\nError, partitions %c and %c overlap:\n", 12616fe57b42Smillert 'a' + i, 'a' + j); 1262366bf641Skrw printf("# %16.16s %16.16s fstype " 1263651d5bd9Sotto "[fsize bsize cpg]\n", "size", "offset"); 126434ae4198Skrw display_partition(stdout, lp, i, 0); 126534ae4198Skrw display_partition(stdout, lp, j, 0); 12666fe57b42Smillert 1267e6aa8bafSmillert /* Get partition to disable or ^D */ 1268e6aa8bafSmillert do { 1269616cd1c4Smillert printf("Disable which one? (^D to abort) [%c %c] ", 12706fe57b42Smillert 'a' + i, 'a' + j); 1271e6aa8bafSmillert buf[0] = '\0'; 1272616cd1c4Smillert if (!fgets(buf, sizeof(buf), stdin)) { 1273616cd1c4Smillert putchar('\n'); 1274e6aa8bafSmillert return(1); /* ^D */ 1275616cd1c4Smillert } 1276e6aa8bafSmillert c = buf[0] - 'a'; 1277e6aa8bafSmillert } while (buf[1] != '\n' && buf[1] != '\0' && 1278e6aa8bafSmillert c != i && c != j); 1279e6aa8bafSmillert 1280e6aa8bafSmillert /* Mark the selected one as unused */ 12816fe57b42Smillert lp->d_partitions[c].p_fstype = FS_UNUSED; 12821f0f871dSkrw return (has_overlap(lp)); 12836fe57b42Smillert } 12846fe57b42Smillert } 12856fe57b42Smillert } 1286f0b4d0a9Smillert 1287e6aa8bafSmillert return(0); 12886fe57b42Smillert } 12896fe57b42Smillert 12906fe57b42Smillert void 12919fdcb4d6Skrw edit_parms(struct disklabel *lp) 12926fe57b42Smillert { 12936fe57b42Smillert char *p; 12949fdcb4d6Skrw u_int64_t freesectors, ui; 129596a888c6Smillert struct disklabel oldlabel = *lp; 12966fe57b42Smillert 1297ea37abd3Sderaadt printf("Changing device parameters for %s:\n", specname); 12986fe57b42Smillert 12990f820bbbSmillert /* disk type */ 13000f820bbbSmillert for (;;) { 1301c33fcabaSmillert p = getstring("disk type", 130241282a2aSmillert "What kind of disk is this? Usually SCSI, ESDI, ST506, or " 130341282a2aSmillert "floppy (use ESDI for IDE).", dktypenames[lp->d_type]); 130496a888c6Smillert if (p == NULL) { 130596a888c6Smillert fputs("Command aborted\n", stderr); 130696a888c6Smillert return; 130796a888c6Smillert } 130841282a2aSmillert if (strcasecmp(p, "IDE") == 0) 130941282a2aSmillert ui = DTYPE_ESDI; 131041282a2aSmillert else 131141282a2aSmillert for (ui = 1; ui < DKMAXTYPES && 131241282a2aSmillert strcasecmp(p, dktypenames[ui]); ui++) 13130f820bbbSmillert ; 13140f820bbbSmillert if (ui < DKMAXTYPES) { 13150f820bbbSmillert break; 13160f820bbbSmillert } else { 13170f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", p); 13180f820bbbSmillert fputs("Valid types are: ", stdout); 13190f820bbbSmillert for (ui = 1; ui < DKMAXTYPES; ui++) { 13200f820bbbSmillert printf("\"%s\"", dktypenames[ui]); 13210f820bbbSmillert if (ui < DKMAXTYPES - 1) 13220f820bbbSmillert fputs(", ", stdout); 13230f820bbbSmillert } 13240f820bbbSmillert putchar('\n'); 13250f820bbbSmillert } 13260f820bbbSmillert } 13270f820bbbSmillert lp->d_type = ui; 13280f820bbbSmillert 13296fe57b42Smillert /* pack/label id */ 1330c33fcabaSmillert p = getstring("label name", 13316fe57b42Smillert "15 char string that describes this label, usually the disk name.", 13326fe57b42Smillert lp->d_packname); 133396a888c6Smillert if (p == NULL) { 133496a888c6Smillert fputs("Command aborted\n", stderr); 133596a888c6Smillert *lp = oldlabel; /* undo damage */ 133696a888c6Smillert return; 133796a888c6Smillert } 13384fb6ab7cSmillert strncpy(lp->d_packname, p, sizeof(lp->d_packname)); /* checked */ 13396fe57b42Smillert 13406fe57b42Smillert /* sectors/track */ 13416fe57b42Smillert for (;;) { 1342dea75673Skrw ui = getuint(lp, "sectors/track", 1343cfd24250Skrw "The Number of sectors per track.", lp->d_nsectors, 13444b9a3bdaSmillert lp->d_nsectors, 0, 0); 13451e0ad43cSotto if (ui == ULLONG_MAX - 1) { 134696a888c6Smillert fputs("Command aborted\n", stderr); 134796a888c6Smillert *lp = oldlabel; /* undo damage */ 134896a888c6Smillert return; 13491e0ad43cSotto } if (ui == ULLONG_MAX) 13506fe57b42Smillert fputs("Invalid entry\n", stderr); 13516fe57b42Smillert else 13526fe57b42Smillert break; 13536fe57b42Smillert } 13546fe57b42Smillert lp->d_nsectors = ui; 13556fe57b42Smillert 13566fe57b42Smillert /* tracks/cylinder */ 13576fe57b42Smillert for (;;) { 1358dea75673Skrw ui = getuint(lp, "tracks/cylinder", 13596fe57b42Smillert "The number of tracks per cylinder.", lp->d_ntracks, 13604b9a3bdaSmillert lp->d_ntracks, 0, 0); 13611e0ad43cSotto if (ui == ULLONG_MAX - 1) { 136296a888c6Smillert fputs("Command aborted\n", stderr); 136396a888c6Smillert *lp = oldlabel; /* undo damage */ 136496a888c6Smillert return; 13651e0ad43cSotto } else if (ui == ULLONG_MAX) 13666fe57b42Smillert fputs("Invalid entry\n", stderr); 13676fe57b42Smillert else 13686fe57b42Smillert break; 13696fe57b42Smillert } 13706fe57b42Smillert lp->d_ntracks = ui; 13716fe57b42Smillert 13726fe57b42Smillert /* sectors/cylinder */ 1373148b6188Smillert for (;;) { 1374dea75673Skrw ui = getuint(lp, "sectors/cylinder", 1375148b6188Smillert "The number of sectors per cylinder (Usually sectors/track " 13764b9a3bdaSmillert "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl, 13774b9a3bdaSmillert 0, 0); 13781e0ad43cSotto if (ui == ULLONG_MAX - 1) { 137996a888c6Smillert fputs("Command aborted\n", stderr); 138096a888c6Smillert *lp = oldlabel; /* undo damage */ 138196a888c6Smillert return; 13821e0ad43cSotto } else if (ui == ULLONG_MAX) 1383148b6188Smillert fputs("Invalid entry\n", stderr); 1384148b6188Smillert else 1385148b6188Smillert break; 1386148b6188Smillert } 1387148b6188Smillert lp->d_secpercyl = ui; 13886fe57b42Smillert 13896fe57b42Smillert /* number of cylinders */ 13906fe57b42Smillert for (;;) { 1391dea75673Skrw ui = getuint(lp, "number of cylinders", 13926fe57b42Smillert "The total number of cylinders on the disk.", 13934b9a3bdaSmillert lp->d_ncylinders, lp->d_ncylinders, 0, 0); 13941e0ad43cSotto if (ui == ULLONG_MAX - 1) { 139596a888c6Smillert fputs("Command aborted\n", stderr); 139696a888c6Smillert *lp = oldlabel; /* undo damage */ 139796a888c6Smillert return; 13981e0ad43cSotto } else if (ui == ULLONG_MAX) 13996fe57b42Smillert fputs("Invalid entry\n", stderr); 14006fe57b42Smillert else 14016fe57b42Smillert break; 14026fe57b42Smillert } 14036fe57b42Smillert lp->d_ncylinders = ui; 14046fe57b42Smillert 14056fe57b42Smillert /* total sectors */ 14066fe57b42Smillert for (;;) { 140734af67a3Sotto u_int64_t nsec = MAX(DL_GETDSIZE(lp), 140834af67a3Sotto (u_int64_t)lp->d_ncylinders * lp->d_secpercyl); 1409dea75673Skrw ui = getuint(lp, "total sectors", 14106fe57b42Smillert "The total number of sectors on the disk.", 1411baaa8969Smillert nsec, nsec, 0, 0); 14121e0ad43cSotto if (ui == ULLONG_MAX - 1) { 141396a888c6Smillert fputs("Command aborted\n", stderr); 141496a888c6Smillert *lp = oldlabel; /* undo damage */ 141596a888c6Smillert return; 14161e0ad43cSotto } else if (ui == ULLONG_MAX) 14176fe57b42Smillert fputs("Invalid entry\n", stderr); 14181e0ad43cSotto else if (ui > DL_GETDSIZE(lp) && 14191e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 1420f98aebd4Smillert puts("You may want to increase the size of the 'c' " 1421f98aebd4Smillert "partition."); 14226fe57b42Smillert break; 14231e0ad43cSotto } else if (ui < DL_GETDSIZE(lp) && 14241e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 14256fe57b42Smillert /* shrink free count */ 14269fdcb4d6Skrw freesectors = editor_countfree(lp); 14279fdcb4d6Skrw if (DL_GETDSIZE(lp) - ui > freesectors) 14286fe57b42Smillert fprintf(stderr, 14291e0ad43cSotto "Not enough free space to shrink by %llu " 14301e0ad43cSotto "sectors (only %llu sectors left)\n", 14319fdcb4d6Skrw DL_GETDSIZE(lp) - ui, freesectors); 1432c4f83f03Skrw else 14336fe57b42Smillert break; 14346fe57b42Smillert } else 14356fe57b42Smillert break; 14366fe57b42Smillert } 143741ed49b7Smillert /* Adjust ending_sector if necessary. */ 143896a888c6Smillert if (ending_sector > ui) 143996a888c6Smillert ending_sector = ui; 14401e0ad43cSotto DL_SETDSIZE(lp, ui); 14416fe57b42Smillert 14426fe57b42Smillert /* rpm */ 14436fe57b42Smillert for (;;) { 1444dea75673Skrw ui = getuint(lp, "rpm", 1445a7e61405Smillert "The rotational speed of the disk in revolutions per minute.", 14464b9a3bdaSmillert lp->d_rpm, lp->d_rpm, 0, 0); 14471e0ad43cSotto if (ui == ULLONG_MAX - 1) { 144896a888c6Smillert fputs("Command aborted\n", stderr); 144996a888c6Smillert *lp = oldlabel; /* undo damage */ 145096a888c6Smillert return; 14511e0ad43cSotto } else if (ui == ULLONG_MAX) 14526fe57b42Smillert fputs("Invalid entry\n", stderr); 14536fe57b42Smillert else 14546fe57b42Smillert break; 14556fe57b42Smillert } 14566fe57b42Smillert lp->d_rpm = ui; 1457440b1d70Smillert 1458440b1d70Smillert /* interleave */ 1459440b1d70Smillert for (;;) { 1460dea75673Skrw ui = getuint(lp, "interleave", 1461440b1d70Smillert "The physical sector interleave, set when formatting. Almost always 1.", 14624b9a3bdaSmillert lp->d_interleave, lp->d_interleave, 0, 0); 14631e0ad43cSotto if (ui == ULLONG_MAX - 1) { 1464440b1d70Smillert fputs("Command aborted\n", stderr); 1465440b1d70Smillert *lp = oldlabel; /* undo damage */ 1466440b1d70Smillert return; 14671e0ad43cSotto } else if (ui == ULLONG_MAX || ui == 0) 1468440b1d70Smillert fputs("Invalid entry\n", stderr); 1469440b1d70Smillert else 1470440b1d70Smillert break; 1471440b1d70Smillert } 1472440b1d70Smillert lp->d_interleave = ui; 14736fe57b42Smillert } 1474a7e61405Smillert 1475a7e61405Smillert struct partition ** 14760fbd3c97Skrw sort_partitions(struct disklabel *lp) 1477a7e61405Smillert { 1478d18c2a43Skrw static struct partition *spp[MAXPARTITIONS+2]; 14790fbd3c97Skrw int i, npartitions; 1480a7e61405Smillert 1481d18c2a43Skrw memset(spp, 0, sizeof(spp)); 1482d18c2a43Skrw 1483a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1484a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1485a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 14861e0ad43cSotto DL_GETPSIZE(&lp->d_partitions[i]) != 0) 1487a7e61405Smillert spp[npartitions++] = &lp->d_partitions[i]; 1488a7e61405Smillert } 1489a7e61405Smillert 1490a7e61405Smillert /* 1491a7e61405Smillert * Sort the partitions based on starting offset. 1492a7e61405Smillert * This is safe because we guarantee no overlap. 1493a7e61405Smillert */ 1494a7e61405Smillert if (npartitions > 1) 1495a7e61405Smillert if (heapsort((void *)spp, npartitions, sizeof(spp[0]), 1496a7e61405Smillert partition_cmp)) 1497a7e61405Smillert err(4, "failed to sort partition table"); 1498a7e61405Smillert 1499a7e61405Smillert return(spp); 1500a7e61405Smillert } 15010f820bbbSmillert 15020f820bbbSmillert /* 15030f820bbbSmillert * Get a valid disk type if necessary. 15040f820bbbSmillert */ 15050f820bbbSmillert void 15068809fabbSderaadt getdisktype(struct disklabel *lp, char *banner, char *dev) 15070f820bbbSmillert { 15080f820bbbSmillert int i; 1509803ff7d5Smillert char *s, *def = "SCSI"; 1510803ff7d5Smillert struct dtypes { 1511803ff7d5Smillert char *dev; 1512803ff7d5Smillert char *type; 1513803ff7d5Smillert } dtypes[] = { 1514c33fcabaSmillert { "sd", "SCSI" }, 1515c33fcabaSmillert { "rz", "SCSI" }, 1516c33fcabaSmillert { "wd", "IDE" }, 1517c33fcabaSmillert { "fd", "FLOPPY" }, 1518c33fcabaSmillert { "xd", "SMD" }, 1519c33fcabaSmillert { "xy", "SMD" }, 1520c33fcabaSmillert { "hd", "HP-IB" }, 1521c33fcabaSmillert { "ccd", "CCD" }, 1522c33fcabaSmillert { "vnd", "VND" }, 1523c33fcabaSmillert { "svnd", "VND" }, 1524c33fcabaSmillert { NULL, NULL } 1525803ff7d5Smillert }; 1526803ff7d5Smillert 1527803ff7d5Smillert if ((s = basename(dev)) != NULL) { 1528803ff7d5Smillert if (*s == 'r') 1529803ff7d5Smillert s++; 1530803ff7d5Smillert i = strcspn(s, "0123456789"); 1531803ff7d5Smillert s[i] = '\0'; 1532803ff7d5Smillert dev = s; 1533803ff7d5Smillert for (i = 0; dtypes[i].dev != NULL; i++) { 1534803ff7d5Smillert if (strcmp(dev, dtypes[i].dev) == 0) { 1535803ff7d5Smillert def = dtypes[i].type; 1536803ff7d5Smillert break; 1537803ff7d5Smillert } 1538803ff7d5Smillert } 1539803ff7d5Smillert } 15400f820bbbSmillert 15410f820bbbSmillert if (lp->d_type > DKMAXTYPES || lp->d_type == 0) { 15420f820bbbSmillert puts(banner); 15430f820bbbSmillert puts("Possible values are:"); 1544eb5dd924Sderaadt printf("\"IDE\", "); 15450f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15460f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15470f820bbbSmillert if (i < DKMAXTYPES - 1) 15480f820bbbSmillert fputs(", ", stdout); 15490f820bbbSmillert } 15500f820bbbSmillert putchar('\n'); 15510f820bbbSmillert 15520f820bbbSmillert for (;;) { 1553c33fcabaSmillert s = getstring("Disk type", 1554803ff7d5Smillert "What kind of disk is this? Usually SCSI, IDE, " 1555803ff7d5Smillert "ESDI, CCD, ST506, or floppy.", def); 155696a888c6Smillert if (s == NULL) 155796a888c6Smillert continue; 15585b412421Smillert if (strcasecmp(s, "IDE") == 0) { 15595b412421Smillert lp->d_type = DTYPE_ESDI; 15605b412421Smillert return; 15615b412421Smillert } 15620f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) 15630f820bbbSmillert if (strcasecmp(s, dktypenames[i]) == 0) { 15640f820bbbSmillert lp->d_type = i; 15650f820bbbSmillert return; 15660f820bbbSmillert } 15670f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", s); 15680f820bbbSmillert fputs("Valid types are: ", stdout); 15690f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 15700f820bbbSmillert printf("\"%s\"", dktypenames[i]); 15710f820bbbSmillert if (i < DKMAXTYPES - 1) 15720f820bbbSmillert fputs(", ", stdout); 15730f820bbbSmillert } 15740f820bbbSmillert putchar('\n'); 15750f820bbbSmillert } 15760f820bbbSmillert } 15770f820bbbSmillert } 157896a888c6Smillert 157996a888c6Smillert /* 158096a888c6Smillert * Get beginning and ending sectors of the OpenBSD portion of the disk 158196a888c6Smillert * from the user. 158296a888c6Smillert */ 158396a888c6Smillert void 15849fdcb4d6Skrw set_bounds(struct disklabel *lp) 158596a888c6Smillert { 15861e0ad43cSotto u_int64_t ui, start_temp; 158796a888c6Smillert 158896a888c6Smillert /* Starting sector */ 158996a888c6Smillert do { 1590dea75673Skrw ui = getuint(lp, "Starting sector", 159196a888c6Smillert "The start of the OpenBSD portion of the disk.", 15921e0ad43cSotto starting_sector, DL_GETDSIZE(lp), 0, 0); 15931e0ad43cSotto if (ui == ULLONG_MAX - 1) { 159496a888c6Smillert fputs("Command aborted\n", stderr); 159596a888c6Smillert return; 159696a888c6Smillert } 15971e0ad43cSotto } while (ui >= DL_GETDSIZE(lp)); 159896a888c6Smillert start_temp = ui; 159996a888c6Smillert 16004793b14cSmillert /* Size */ 160196a888c6Smillert do { 1602dea75673Skrw ui = getuint(lp, "Size ('*' for entire disk)", 1603f98aebd4Smillert "The size of the OpenBSD portion of the disk ('*' for the " 1604f98aebd4Smillert "entire disk).", ending_sector - starting_sector, 16051e0ad43cSotto DL_GETDSIZE(lp) - start_temp, 0, 0); 16061e0ad43cSotto if (ui == ULLONG_MAX - 1) { 160796a888c6Smillert fputs("Command aborted\n", stderr); 160896a888c6Smillert return; 160996a888c6Smillert } 16101e0ad43cSotto } while (ui > DL_GETDSIZE(lp) - start_temp); 16114793b14cSmillert ending_sector = start_temp + ui; 161296a888c6Smillert starting_sector = start_temp; 161396a888c6Smillert } 161496a888c6Smillert 161596a888c6Smillert /* 161696a888c6Smillert * Return a list of the "chunks" of free space available 161796a888c6Smillert */ 161896a888c6Smillert struct diskchunk * 16198809fabbSderaadt free_chunks(struct disklabel *lp) 162096a888c6Smillert { 162196a888c6Smillert struct partition **spp; 162296a888c6Smillert static struct diskchunk chunks[MAXPARTITIONS + 2]; 162399bd27d2Skrw u_int64_t start, stop; 162496a888c6Smillert int i, numchunks; 162596a888c6Smillert 16260fbd3c97Skrw /* Sort the in-use partitions based on offset */ 16270fbd3c97Skrw spp = sort_partitions(lp); 162896a888c6Smillert 162996a888c6Smillert /* If there are no partitions, it's all free. */ 16300fbd3c97Skrw if (spp[0] == NULL) { 16312d8451b0Smillert chunks[0].start = starting_sector; 163296a888c6Smillert chunks[0].stop = ending_sector; 163396a888c6Smillert chunks[1].start = chunks[1].stop = 0; 163496a888c6Smillert return(chunks); 163596a888c6Smillert } 163696a888c6Smillert 163796a888c6Smillert /* Find chunks of free space */ 163896a888c6Smillert numchunks = 0; 16390fbd3c97Skrw if (DL_GETPOFFSET(spp[0]) > starting_sector) { 16402d8451b0Smillert chunks[0].start = starting_sector; 16411e0ad43cSotto chunks[0].stop = DL_GETPOFFSET(spp[0]); 164296a888c6Smillert numchunks++; 164396a888c6Smillert } 16440fbd3c97Skrw for (i = 0; spp[i] != NULL; i++) { 164599bd27d2Skrw start = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]); 1646aff3f969Sotto if (start < starting_sector) 1647aff3f969Sotto start = starting_sector; 1648aff3f969Sotto else if (start > ending_sector) 1649aff3f969Sotto start = ending_sector; 165099bd27d2Skrw if (spp[i + 1] != NULL) 165199bd27d2Skrw stop = DL_GETPOFFSET(spp[i+1]); 165299bd27d2Skrw else 165399bd27d2Skrw stop = ending_sector; 1654aff3f969Sotto if (stop < starting_sector) 1655aff3f969Sotto stop = starting_sector; 1656aff3f969Sotto else if (stop > ending_sector) 1657aff3f969Sotto stop = ending_sector; 165899bd27d2Skrw if (start < stop) { 165999bd27d2Skrw chunks[numchunks].start = start; 166099bd27d2Skrw chunks[numchunks].stop = stop; 166196a888c6Smillert numchunks++; 166296a888c6Smillert } 166396a888c6Smillert } 166496a888c6Smillert 166596a888c6Smillert /* Terminate and return */ 166696a888c6Smillert chunks[numchunks].start = chunks[numchunks].stop = 0; 166796a888c6Smillert return(chunks); 166896a888c6Smillert } 16694793b14cSmillert 16704793b14cSmillert void 167187023ed9Skrw find_bounds(struct disklabel *lp) 16724793b14cSmillert { 16736534e983Sderaadt starting_sector = DL_GETBSTART(lp); 16746534e983Sderaadt ending_sector = DL_GETBEND(lp); 1675b2d4a455Smiod 16766534e983Sderaadt if (ending_sector) { 167734ae4198Skrw if (verbose) 167834ae4198Skrw printf("Treating sectors %llu-%llu as the OpenBSD" 167934ae4198Skrw " portion of the disk.\nYou can use the 'b'" 168034ae4198Skrw " command to change this.\n\n", starting_sector, 168134ae4198Skrw ending_sector); 1682b2d4a455Smiod } else { 1683b2d4a455Smiod #if (NUMBOOT == 1) 1684d3f02056Smillert /* Boot blocks take up the first cylinder */ 1685d3f02056Smillert starting_sector = lp->d_secpercyl; 168634ae4198Skrw if (verbose) 168734ae4198Skrw printf("Reserving the first data cylinder for boot" 168834ae4198Skrw " blocks.\nYou can use the 'b' command to change" 168934ae4198Skrw " this.\n\n"); 16904793b14cSmillert #endif 16914793b14cSmillert } 1692b2d4a455Smiod } 1693c0bdc608Smillert 1694c0bdc608Smillert /* 1695c0bdc608Smillert * Calculate free space. 1696c0bdc608Smillert */ 16979fdcb4d6Skrw u_int64_t 16989fdcb4d6Skrw editor_countfree(struct disklabel *lp) 1699c0bdc608Smillert { 1700d93cb2bbSkrw struct diskchunk *chunks; 17019fdcb4d6Skrw u_int64_t freesectors = 0; 1702c0bdc608Smillert int i; 1703c0bdc608Smillert 1704d93cb2bbSkrw chunks = free_chunks(lp); 1705509930fbSotto 1706d93cb2bbSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) 17079fdcb4d6Skrw freesectors += chunks[i].stop - chunks[i].start; 17089fdcb4d6Skrw 17099fdcb4d6Skrw return (freesectors); 1710c0bdc608Smillert } 1711617e6e4aSmillert 1712617e6e4aSmillert void 17138809fabbSderaadt editor_help(char *arg) 1714617e6e4aSmillert { 1715617e6e4aSmillert 1716617e6e4aSmillert /* XXX - put these strings in a table instead? */ 1717617e6e4aSmillert switch (*arg) { 1718617e6e4aSmillert case 'p': 1719617e6e4aSmillert puts( 1720aff3f969Sotto "The 'p' command prints the current partitions. By default, it prints size\n" 1721aff3f969Sotto "and offset in sectors (a sector is usually 512 bytes). The 'p' command\n" 1722aff3f969Sotto "takes an optional units argument. Possible values are 'b' for bytes, 'c'\n" 1723aff3f969Sotto "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n"); 1724eb176802Sjsg break; 1725aff3f969Sotto case 'l': 1726aff3f969Sotto puts( 1727aff3f969Sotto "The 'l' command prints the header of the disk label. By default, it prints\n" 1728617e6e4aSmillert "size and offset in sectors (a sector is usually 512 bytes). The 'p' command\n" 1729617e6e4aSmillert "takes an optional units argument. Possible values are 'b' for bytes, 'c'\n" 1730617e6e4aSmillert "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n"); 1731617e6e4aSmillert break; 1732617e6e4aSmillert case 'M': 1733617e6e4aSmillert puts( 17349afbe9eeSmillert "The 'M' command pipes the entire OpenBSD manual page for disk label through\n" 1735508086e9Smillert "the pager specified by the PAGER environment variable or 'less' if PAGER is\n" 1736508086e9Smillert "not set. It is especially useful during install when the normal system\n" 1737508086e9Smillert "manual is not available.\n"); 1738617e6e4aSmillert break; 1739617e6e4aSmillert case 'e': 1740617e6e4aSmillert puts( 1741617e6e4aSmillert "The 'e' command is used to edit the disk drive parameters. These include\n" 1742617e6e4aSmillert "the number of sectors/track, tracks/cylinder, sectors/cylinder, number of\n" 1743617e6e4aSmillert "cylinders on the disk , total sectors on the disk, rpm, interleave, disk\n" 1744617e6e4aSmillert "type, and a descriptive label string. You should not change these unless\n" 1745617e6e4aSmillert "you know what you are doing\n"); 1746617e6e4aSmillert break; 1747617e6e4aSmillert case 'a': 1748617e6e4aSmillert puts( 1749617e6e4aSmillert "The 'a' command adds new partitions to the disk. It takes as an optional\n" 1750617e6e4aSmillert "argument the partition letter to add. If you do not specify a partition\n" 1751617e6e4aSmillert "letter, you will be prompted for it; the next available letter will be the\n" 1752617e6e4aSmillert "default answer\n"); 1753617e6e4aSmillert break; 17546aaa4aabSotto case 'A': 17556aaa4aabSotto puts( 17566aaa4aabSotto "The 'A' command clears the existing partitions and creates a new label\n" 17576aaa4aabSotto "based on the size of the disk\n"); 17586aaa4aabSotto break; 1759617e6e4aSmillert case 'b': 1760617e6e4aSmillert puts( 1761617e6e4aSmillert "The 'b' command is used to change the boundaries of the OpenBSD portion of\n" 1762617e6e4aSmillert "the disk. This is only useful on disks with an fdisk partition. By default,\n" 1763617e6e4aSmillert "on a disk with an fdisk partition, the boundaries are set to be the first\n" 1764617e6e4aSmillert "and last sectors of the OpenBSD fdisk partition. You should only change\n" 1765617e6e4aSmillert "these if your fdisk partition table is incorrect or you have a disk larger\n" 1766617e6e4aSmillert "than 8gig, since 8gig is the maximum size an fdisk partition can be. You\n" 1767617e6e4aSmillert "may enter '*' at the 'Size' prompt to indicate the entire size of the disk\n" 1768617e6e4aSmillert "(minus the starting sector). Use this option with care; if you extend the\n" 1769617e6e4aSmillert "boundaries such that they overlap with another operating system you will\n" 1770617e6e4aSmillert "corrupt the other operating system's data.\n"); 1771617e6e4aSmillert break; 1772617e6e4aSmillert case 'c': 1773617e6e4aSmillert puts( 1774617e6e4aSmillert "The 'c' command is used to change the size of an existing partition. It\n" 1775617e6e4aSmillert "takes as an optional argument the partition letter to change. If you do not\n" 1776617e6e4aSmillert "specify a partition letter, you will be prompted for one. You may add a '+'\n" 1777617e6e4aSmillert "or '-' prefix to the new size to increase or decrease the existing value\n" 1778617e6e4aSmillert "instead of entering an absolute value. You may also use a suffix to indicate\n" 1779617e6e4aSmillert "the units the values is in terms of. Possible suffixes are 'b' for bytes,\n" 1780617e6e4aSmillert "'c' for cylinders, 'k' for kilobytes, 'm' for megabytes, 'g' for gigabytes or\n" 1781617e6e4aSmillert "no suffix for sectors (usually 512 bytes). You may also enter '*' to change\n" 1782617e6e4aSmillert "the size to be the total number of free sectors remaining.\n"); 1783617e6e4aSmillert break; 17849afbe9eeSmillert case 'D': 17859afbe9eeSmillert puts( 17869afbe9eeSmillert "The 'D' command will set the disk label to the default values as reported\n" 17879afbe9eeSmillert "by the disk itself. This similates the case where there is no disk label.\n"); 17889afbe9eeSmillert break; 1789617e6e4aSmillert case 'd': 1790617e6e4aSmillert puts( 1791617e6e4aSmillert "The 'd' command is used to delete an existing partition. It takes as an\n" 1792617e6e4aSmillert "optional argument the partition letter to change. If you do not specify a\n" 1793617e6e4aSmillert "partition letter, you will be prompted for one. You may not delete the ``c''\n" 1794617e6e4aSmillert "partition as 'c' must always exist and by default is marked as 'unused' (so\n" 1795617e6e4aSmillert "it does not take up any space).\n"); 1796617e6e4aSmillert break; 1797c33fcabaSmillert case 'g': 1798c33fcabaSmillert puts( 179987023ed9Skrw "The 'g' command is used select which disk geometry to use, the disk or a\n" 180087023ed9Skrw "user geometry. It takes as an optional argument ``d'' or ``u''. If \n" 1801c33fcabaSmillert "you do not specify the type as an argument, you will be prompted for it.\n"); 1802c33fcabaSmillert break; 1803617e6e4aSmillert case 'm': 1804617e6e4aSmillert puts( 180587023ed9Skrw "The 'm' command is used to modify an existing partition. It takes as an\n" 180687023ed9Skrw "optional argument the partition letter to change. If you do not specify a\n" 1807617e6e4aSmillert "partition letter, you will be prompted for one. This option allows the user\n" 1808617e6e4aSmillert "to change the filesystem type, starting offset, partition size, block fragment\n" 1809617e6e4aSmillert "size, block size, and cylinders per group for the specified partition (not all\n" 1810617e6e4aSmillert "parameters are configurable for non-BSD partitions).\n"); 1811617e6e4aSmillert break; 1812bd6726faSmillert case 'n': 1813bd6726faSmillert puts( 1814fb932baaSaaron "The 'n' command is used to set the mount point for a partition (ie: name it).\n" 1815bd6726faSmillert "It takes as an optional argument the partition letter to name. If you do\n" 1816bd6726faSmillert "not specify a partition letter, you will be prompted for one. This option\n" 1817ac7ae62cSderaadt "is only valid if disklabel was invoked with the -f flag.\n"); 1818bd6726faSmillert break; 18196aaa4aabSotto case 'R': 18206aaa4aabSotto puts( 18216aaa4aabSotto "Resize a a partition, compacting unused space between partitions\n" 18226aaa4aabSotto "with a higher offset. The last partition will be shrunk if needed.\n" 18236aaa4aabSotto "Works only for auto allocated labels with no spoofed partitions\n"); 18246aaa4aabSotto break; 1825617e6e4aSmillert case 'r': 1826617e6e4aSmillert puts( 182725f9c360Skrw "The 'r' command is used to recalculate and display details about\n" 182825f9c360Skrw "the available free space.\n"); 1829617e6e4aSmillert break; 1830617e6e4aSmillert case 'u': 1831617e6e4aSmillert puts( 1832617e6e4aSmillert "The 'u' command will undo (or redo) the last change. Entering 'u' once will\n" 1833617e6e4aSmillert "undo your last change. Entering it again will restore the change.\n"); 1834617e6e4aSmillert break; 1835617e6e4aSmillert case 's': 1836617e6e4aSmillert puts( 1837617e6e4aSmillert "The 's' command is used to save a copy of the label to a file in ascii format\n" 1838617e6e4aSmillert "(suitable for loading via disklabel's [-R] option). It takes as an optional\n" 1839617e6e4aSmillert "argument the filename to save the label to. If you do not specify a filename,\n" 1840617e6e4aSmillert "you will be prompted for one.\n"); 1841617e6e4aSmillert break; 1842617e6e4aSmillert case 'w': 1843617e6e4aSmillert puts( 1844617e6e4aSmillert "The 'w' command will write the current label to disk. This option will\n" 1845617e6e4aSmillert "commit any changes to the on-disk label.\n"); 1846617e6e4aSmillert break; 1847617e6e4aSmillert case 'q': 1848617e6e4aSmillert puts( 1849617e6e4aSmillert "The 'q' command quits the label editor. If any changes have been made you\n" 1850617e6e4aSmillert "will be asked whether or not to save the changes to the on-disk label.\n"); 1851617e6e4aSmillert break; 18529afbe9eeSmillert case 'X': 18539afbe9eeSmillert puts( 18549afbe9eeSmillert "The 'X' command toggles disklabel in to/out of 'expert mode'. By default,\n" 18559afbe9eeSmillert "some settings are reserved for experts only (such as the block and fragment\n" 18569afbe9eeSmillert "size on ffs partitions).\n"); 18579afbe9eeSmillert break; 1858617e6e4aSmillert case 'x': 1859617e6e4aSmillert puts( 1860617e6e4aSmillert "The 'x' command exits the label editor without saving any changes to the\n" 1861617e6e4aSmillert "on-disk label.\n"); 1862617e6e4aSmillert break; 18639afbe9eeSmillert case 'z': 18649afbe9eeSmillert puts( 18659afbe9eeSmillert "The 'z' command zeroes out the existing partition table, leaving only the 'c'\n" 18669afbe9eeSmillert "partition. The drive parameters are not changed.\n"); 18679afbe9eeSmillert break; 1868617e6e4aSmillert default: 1869617e6e4aSmillert puts("Available commands:"); 1870617e6e4aSmillert puts( 187149159a67Skrw " ? [cmd] - show help n [part] - set mount point\n" 187249159a67Skrw " A - auto partition all space p [unit] - print partitions\n" 187349159a67Skrw " a [part] - add partition q - quit & save changes\n" 18746aaa4aabSotto " b - set OpenBSD boundaries R [part] - resize a partition\n" 187549159a67Skrw " c [part] - change partition size r - display free space\n" 18766aaa4aabSotto " D - reset label to default s [path] - save label to file\n" 18776aaa4aabSotto " d [part] - delete partition U - undo all changes\n" 18786aaa4aabSotto " e - edit drive parameters u - undo last change\n" 18796aaa4aabSotto " g [d|u] - [d]isk or [u]ser geometry w - write label to disk\n" 18806aaa4aabSotto " l [unit] - print disk label header X - toggle expert mode\n" 18816aaa4aabSotto " M - disklabel(8) man page x - exit & lose changes\n" 18826aaa4aabSotto " m [part] - modify partition z - delete all partitions\n" 1883c4884206Skrw "\n" 1884c4884206Skrw "Suffixes can be used to indicate units other than sectors:\n" 1885c4884206Skrw "\t'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes)\n" 1886c4884206Skrw "\t'c' (cylinders), '%' (% of total disk), '&' (% of free space).\n" 1887c4884206Skrw "Values in non-sector units are truncated to the nearest cylinder boundary."); 1888617e6e4aSmillert break; 1889617e6e4aSmillert } 1890617e6e4aSmillert } 1891bd6726faSmillert 18924f3bbbf0Skrw void 18938809fabbSderaadt mpcopy(char **to, char **from) 1894bd6726faSmillert { 1895bd6726faSmillert int i; 18960612d09dSderaadt char *top; 1897bd6726faSmillert 1898bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1899bd6726faSmillert if (from[i] != NULL) { 1900dcab0d16Sderaadt int len = strlen(from[i]) + 1; 1901dcab0d16Sderaadt 19020612d09dSderaadt top = realloc(to[i], len); 19030612d09dSderaadt if (top == NULL) 1904bd6726faSmillert errx(4, "out of memory"); 19050612d09dSderaadt to[i] = top; 1906dcab0d16Sderaadt (void)strlcpy(to[i], from[i], len); 1907bd6726faSmillert } else if (to[i] != NULL) { 1908bd6726faSmillert free(to[i]); 1909bd6726faSmillert to[i] = NULL; 1910bd6726faSmillert } 1911bd6726faSmillert } 1912bd6726faSmillert } 1913bd6726faSmillert 1914bd6726faSmillert int 19158809fabbSderaadt mpequal(char **mp1, char **mp2) 1916bd6726faSmillert { 1917bd6726faSmillert int i; 1918bd6726faSmillert 1919bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1920bd6726faSmillert if (mp1[i] == NULL && mp2[i] == NULL) 1921bd6726faSmillert continue; 1922bd6726faSmillert 1923bd6726faSmillert if ((mp1[i] != NULL && mp2[i] == NULL) || 1924bd6726faSmillert (mp1[i] == NULL && mp2[i] != NULL) || 1925bd6726faSmillert (strcmp(mp1[i], mp2[i]) != 0)) 1926bd6726faSmillert return(0); 1927bd6726faSmillert } 1928bd6726faSmillert return(1); 1929bd6726faSmillert } 1930bd6726faSmillert 193193160b9bSkrw void 193234ae4198Skrw mpsave(struct disklabel *lp) 1933bd6726faSmillert { 1934d8b446ceSderaadt int i, j; 1935bd6726faSmillert char bdev[MAXPATHLEN], *p; 19363f843443Smillert struct mountinfo mi[MAXPARTITIONS]; 1937bd6726faSmillert FILE *fp; 1938bd6726faSmillert 193993160b9bSkrw if (!fstabfile) 194093160b9bSkrw return; 194193160b9bSkrw 19423f843443Smillert memset(&mi, 0, sizeof(mi)); 19433f843443Smillert 1944d8b446ceSderaadt for (i = 0; i < MAXPARTITIONS; i++) { 194534ae4198Skrw if (mountpoints[i] != NULL) { 194634ae4198Skrw mi[i].mountpoint = mountpoints[i]; 19473f843443Smillert mi[i].partno = i; 1948bd6726faSmillert } 1949bd6726faSmillert } 1950bd6726faSmillert 195134ae4198Skrw /* Convert specname to bdev */ 195234ae4198Skrw if (strncmp(_PATH_DEV, specname, sizeof(_PATH_DEV) - 1) == 0 && 195334ae4198Skrw specname[sizeof(_PATH_DEV) - 1] == 'r') { 1954bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV, 195534ae4198Skrw &specname[sizeof(_PATH_DEV)]); 1956bd6726faSmillert } else { 195734ae4198Skrw if ((p = strrchr(specname, '/')) == NULL || *(++p) != 'r') 195893160b9bSkrw return; 1959bd6726faSmillert *p = '\0'; 196034ae4198Skrw snprintf(bdev, sizeof(bdev), "%s%s", specname, p + 1); 1961bd6726faSmillert *p = 'r'; 1962bd6726faSmillert } 1963bd6726faSmillert bdev[strlen(bdev) - 1] = '\0'; 1964bd6726faSmillert 19653f843443Smillert /* Sort mountpoints so we don't try to mount /usr/local before /usr */ 19663f843443Smillert qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp); 19673f843443Smillert 196893160b9bSkrw if (fp = fopen(fstabfile, "w")) { 196993160b9bSkrw for (i = 0; i < MAXPARTITIONS && mi[i].mountpoint; i++) { 19705fea0b85Smillert j = mi[i].partno; 19715fea0b85Smillert fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 'a' + j, 19723f843443Smillert mi[i].mountpoint, 19735fea0b85Smillert fstypesnames[lp->d_partitions[j].p_fstype], 19745fea0b85Smillert j == 0 ? 1 : 2); 1975bd6726faSmillert } 1976bd6726faSmillert fclose(fp); 197793160b9bSkrw } 1978bd6726faSmillert } 197924a2c1a4Smillert 198024a2c1a4Smillert int 1981604d3bdeSkrw get_offset(struct disklabel *lp, int partno) 198224a2c1a4Smillert { 1983604d3bdeSkrw struct diskchunk *chunks; 198424a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 198515c15d8aSkrw u_int64_t ui, maxsize; 1986604d3bdeSkrw int i, fstype; 198724a2c1a4Smillert 1988dea75673Skrw ui = getuint(lp, "offset", 19891e0ad43cSotto "Starting sector for this partition.", 19901e0ad43cSotto DL_GETPOFFSET(pp), 19911e0ad43cSotto DL_GETPOFFSET(pp), 0, DO_CONVERSIONS | 199224a2c1a4Smillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 1993e9ff19beSkrw 1994e9ff19beSkrw if (ui == ULLONG_MAX - 1) 199524a2c1a4Smillert fputs("Command aborted\n", stderr); 1996e9ff19beSkrw else if (ui == ULLONG_MAX) 199724a2c1a4Smillert fputs("Invalid entry\n", stderr); 199840e98e9fSkrw else if (ui < starting_sector || ui >= ending_sector) 1999e9ff19beSkrw fprintf(stderr, "The offset must be >= %llu and < %llu, " 2000e9ff19beSkrw "the limits of the OpenBSD portion\n" 2001e9ff19beSkrw "of the disk. The 'b' command can change these limits.\n", 200240e98e9fSkrw starting_sector, ending_sector); 2003fc1a4cc6Sderaadt #ifdef SUN_AAT0 200449bf537cSderaadt else if (partno == 0 && ui != 0) 200549bf537cSderaadt fprintf(stderr, "This architecture requires that " 200640f544cdSderaadt "partition 'a' start at sector 0.\n"); 200749bf537cSderaadt #endif 200815c15d8aSkrw else { 2009604d3bdeSkrw fstype = pp->p_fstype; 2010604d3bdeSkrw pp->p_fstype = FS_UNUSED; 2011604d3bdeSkrw chunks = free_chunks(lp); 2012604d3bdeSkrw pp->p_fstype = fstype; 2013e9ff19beSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 2014e9ff19beSkrw if (ui < chunks[i].start || ui >= chunks[i].stop) 201515c15d8aSkrw continue; 20161e0ad43cSotto DL_SETPOFFSET(pp, ui); 201715c15d8aSkrw maxsize = chunks[i].stop - DL_GETPOFFSET(pp); 201815c15d8aSkrw if (DL_GETPSIZE(pp) > maxsize) 201915c15d8aSkrw DL_SETPSIZE(pp, maxsize); 202024a2c1a4Smillert return (0); 202124a2c1a4Smillert } 202215c15d8aSkrw fputs("The offset must be in a free area.\n", stderr); 202315c15d8aSkrw } 2024e9ff19beSkrw 2025e9ff19beSkrw /* Partition offset was not set. */ 2026e9ff19beSkrw return (1); 202715c15d8aSkrw } 202824a2c1a4Smillert 202924a2c1a4Smillert int 20309fdcb4d6Skrw get_size(struct disklabel *lp, int partno) 203124a2c1a4Smillert { 203224a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 203314192793Skrw u_int64_t maxsize, ui; 203414192793Skrw 203514192793Skrw maxsize = max_partition_size(lp, partno); 203624a2c1a4Smillert 2037dea75673Skrw ui = getuint(lp, "size", "Size of the partition. " 20387da73705Skrw "You may also say +/- amount for a relative change.", 203914192793Skrw DL_GETPSIZE(pp), maxsize, DL_GETPOFFSET(pp), 2040525051f1Sotto DO_CONVERSIONS | ((pp->p_fstype == FS_BSDFFS || 2041525051f1Sotto pp->p_fstype == FS_SWAP) ? DO_ROUNDING : 0)); 2042e9ff19beSkrw 2043e9ff19beSkrw if (ui == ULLONG_MAX - 1) 204424a2c1a4Smillert fputs("Command aborted\n", stderr); 2045e9ff19beSkrw else if (ui == ULLONG_MAX) 204624a2c1a4Smillert fputs("Invalid entry\n", stderr); 204728e3704eSkrw else if (ui == 0) 204828e3704eSkrw fputs("The size must be > 0\n", stderr); 204940e98e9fSkrw else if (ui + DL_GETPOFFSET(pp) > ending_sector) 205040e98e9fSkrw fprintf(stderr, "The size can't be more than " 205140e98e9fSkrw "%llu sectors, or the partition would\n" 205240e98e9fSkrw "extend beyond the last sector (%llu) of the " 205340e98e9fSkrw "OpenBSD portion of\nthe disk. " 205440e98e9fSkrw "The 'b' command can change this limit.\n", 205540e98e9fSkrw ending_sector - DL_GETPOFFSET(pp), ending_sector); 205614192793Skrw else if (ui > maxsize) 205714192793Skrw fprintf(stderr,"Sorry, there are only %llu sectors left\n", 205814192793Skrw maxsize); 205959ccf790Skrw else { 206059ccf790Skrw DL_SETPSIZE(pp, ui); 206124a2c1a4Smillert return (0); 206224a2c1a4Smillert } 2063e9ff19beSkrw 2064e9ff19beSkrw /* Partition size was not set. */ 2065e9ff19beSkrw return (1); 2066e9ff19beSkrw } 206724a2c1a4Smillert 206824a2c1a4Smillert int 20698809fabbSderaadt get_fsize(struct disklabel *lp, int partno) 207024a2c1a4Smillert { 20711e0ad43cSotto u_int64_t ui, fsize, frag; 207224a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 207324a2c1a4Smillert 2074a4c87e64Skrw if (!expert || pp->p_fstype != FS_BSDFFS) 2075a4c87e64Skrw return (0); 2076a4c87e64Skrw 2077ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 2078ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 2079ddfcbf38Sotto if (fsize == 0) 2080ddfcbf38Sotto frag = 8; 2081ddfcbf38Sotto 208224a2c1a4Smillert for (;;) { 2083dea75673Skrw ui = getuint(lp, "fragment size", 20843c92d7f2Stedu "Size of fs block fragments. Usually 2048 or 512.", 2085ddfcbf38Sotto fsize, fsize, 0, 0); 20861e0ad43cSotto if (ui == ULLONG_MAX - 1) { 208724a2c1a4Smillert fputs("Command aborted\n", stderr); 208824a2c1a4Smillert return(1); 20891e0ad43cSotto } else if (ui == ULLONG_MAX) 209024a2c1a4Smillert fputs("Invalid entry\n", stderr); 209124a2c1a4Smillert else 209224a2c1a4Smillert break; 209324a2c1a4Smillert } 209424a2c1a4Smillert if (ui == 0) 209524a2c1a4Smillert puts("Zero fragment size implies zero block size"); 2096ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag); 209724a2c1a4Smillert return(0); 209824a2c1a4Smillert } 209924a2c1a4Smillert 210024a2c1a4Smillert int 21018809fabbSderaadt get_bsize(struct disklabel *lp, int partno) 210224a2c1a4Smillert { 21031e0ad43cSotto u_int64_t ui, bsize, frag, fsize; 210424a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 210524a2c1a4Smillert 2106a4c87e64Skrw if (!expert || pp->p_fstype != FS_BSDFFS) 2107a4c87e64Skrw return (0); 2108a4c87e64Skrw 210924a2c1a4Smillert /* Avoid dividing by zero... */ 2110ddfcbf38Sotto if (pp->p_fragblock == 0) 211124a2c1a4Smillert return(1); 2112ddfcbf38Sotto 2113ddfcbf38Sotto bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock); 2114ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 2115ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 211624a2c1a4Smillert 211724a2c1a4Smillert for (;;) { 2118dea75673Skrw ui = getuint(lp, "block size", 21193c92d7f2Stedu "Size of filesystem blocks. Usually 16384 or 4096.", 2120ddfcbf38Sotto fsize * frag, fsize * frag, 212124a2c1a4Smillert 0, 0); 212224a2c1a4Smillert 212324a2c1a4Smillert /* sanity checks */ 21241e0ad43cSotto if (ui == ULLONG_MAX - 1) { 212524a2c1a4Smillert fputs("Command aborted\n", stderr); 212624a2c1a4Smillert return(1); 21271e0ad43cSotto } else if (ui == ULLONG_MAX) 212824a2c1a4Smillert fputs("Invalid entry\n", stderr); 212924a2c1a4Smillert else if (ui < getpagesize()) 213024a2c1a4Smillert fprintf(stderr, 213124a2c1a4Smillert "Error: block size must be at least as big " 213224a2c1a4Smillert "as page size (%d).\n", getpagesize()); 2133ddfcbf38Sotto else if (ui % fsize != 0) 213424a2c1a4Smillert fputs("Error: block size must be a multiple of the " 213524a2c1a4Smillert "fragment size.\n", stderr); 2136ddfcbf38Sotto else if (ui / fsize < 1) 213724a2c1a4Smillert fputs("Error: block size must be at least as big as " 213824a2c1a4Smillert "fragment size.\n", stderr); 213924a2c1a4Smillert else 214024a2c1a4Smillert break; 214124a2c1a4Smillert } 2142ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui / frag, frag); 214324a2c1a4Smillert return(0); 214424a2c1a4Smillert } 214524a2c1a4Smillert 214624a2c1a4Smillert int 21478809fabbSderaadt get_fstype(struct disklabel *lp, int partno) 214824a2c1a4Smillert { 214924a2c1a4Smillert char *p; 21501e0ad43cSotto u_int64_t ui; 215124a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 215224a2c1a4Smillert 215324a2c1a4Smillert if (pp->p_fstype < FSMAXTYPES) { 2154c33fcabaSmillert p = getstring("FS type", 215524a2c1a4Smillert "Filesystem type (usually 4.2BSD or swap)", 215624a2c1a4Smillert fstypenames[pp->p_fstype]); 215724a2c1a4Smillert if (p == NULL) { 215824a2c1a4Smillert fputs("Command aborted\n", stderr); 215924a2c1a4Smillert return(1); 216024a2c1a4Smillert } 216124a2c1a4Smillert for (ui = 0; ui < FSMAXTYPES; ui++) { 216224a2c1a4Smillert if (!strcasecmp(p, fstypenames[ui])) { 216324a2c1a4Smillert pp->p_fstype = ui; 216424a2c1a4Smillert break; 216524a2c1a4Smillert } 216624a2c1a4Smillert } 216724a2c1a4Smillert if (ui >= FSMAXTYPES) { 216824a2c1a4Smillert printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p); 216924a2c1a4Smillert pp->p_fstype = FS_OTHER; 217024a2c1a4Smillert } 217124a2c1a4Smillert } else { 217224a2c1a4Smillert for (;;) { 2173dea75673Skrw ui = getuint(lp, "FS type (decimal)", 217424a2c1a4Smillert "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", 217524a2c1a4Smillert pp->p_fstype, pp->p_fstype, 0, 0); 21761e0ad43cSotto if (ui == ULLONG_MAX - 1) { 217724a2c1a4Smillert fputs("Command aborted\n", stderr); 217824a2c1a4Smillert return(1); 21791e0ad43cSotto } if (ui == ULLONG_MAX) 218024a2c1a4Smillert fputs("Invalid entry\n", stderr); 218124a2c1a4Smillert else 218224a2c1a4Smillert break; 218324a2c1a4Smillert } 218424a2c1a4Smillert pp->p_fstype = ui; 218524a2c1a4Smillert } 218624a2c1a4Smillert return(0); 218724a2c1a4Smillert } 218824a2c1a4Smillert 218924a2c1a4Smillert int 219034ae4198Skrw get_mp(struct disklabel *lp, int partno) 219124a2c1a4Smillert { 219224a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 2193ec9fde5fSkrw char *p; 2194ec9fde5fSkrw int i; 219524a2c1a4Smillert 219634ae4198Skrw if (fstabfile && pp->p_fstype != FS_UNUSED && 219724a2c1a4Smillert pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT && 219824a2c1a4Smillert pp->p_fstype != FS_OTHER) { 2199ddaff619Smillert for (;;) { 2200c33fcabaSmillert p = getstring("mount point", 220124a2c1a4Smillert "Where to mount this filesystem (ie: / /var /usr)", 220234ae4198Skrw mountpoints[partno] ? mountpoints[partno] : "none"); 220324a2c1a4Smillert if (p == NULL) { 220424a2c1a4Smillert fputs("Command aborted\n", stderr); 220524a2c1a4Smillert return(1); 220624a2c1a4Smillert } 2207ddaff619Smillert if (strcasecmp(p, "none") == 0) { 220834ae4198Skrw free(mountpoints[partno]); 220934ae4198Skrw mountpoints[partno] = NULL; 2210ddaff619Smillert break; 2211ddaff619Smillert } 2212ec9fde5fSkrw for (i = 0; i < MAXPARTITIONS; i++) 221393160b9bSkrw if (mountpoints[i] != NULL && i != partno && 2214ec9fde5fSkrw strcmp(p, mountpoints[i]) == 0) 2215ec9fde5fSkrw break; 2216ec9fde5fSkrw if (i < MAXPARTITIONS) { 221793160b9bSkrw fprintf(stderr, "'%c' already being mounted at " 221893160b9bSkrw "'%s'\n", 'a'+i, p); 2219ec9fde5fSkrw break; 2220ec9fde5fSkrw } 2221ddaff619Smillert if (*p == '/') { 2222ddaff619Smillert /* XXX - might as well realloc */ 222334ae4198Skrw free(mountpoints[partno]); 222434ae4198Skrw if ((mountpoints[partno] = strdup(p)) == NULL) 222524a2c1a4Smillert errx(4, "out of memory"); 2226ddaff619Smillert break; 2227ddaff619Smillert } 2228ddaff619Smillert fputs("Mount points must start with '/'\n", stderr); 222924a2c1a4Smillert } 223024a2c1a4Smillert } 223124a2c1a4Smillert return(0); 223224a2c1a4Smillert } 22333f843443Smillert 22343f843443Smillert int 22358809fabbSderaadt micmp(const void *a1, const void *a2) 22363f843443Smillert { 22373f843443Smillert struct mountinfo *mi1 = (struct mountinfo *)a1; 22383f843443Smillert struct mountinfo *mi2 = (struct mountinfo *)a2; 22393f843443Smillert 22403f843443Smillert /* We want all the NULLs at the end... */ 22413f843443Smillert if (mi1->mountpoint == NULL && mi2->mountpoint == NULL) 22423f843443Smillert return(0); 22433f843443Smillert else if (mi1->mountpoint == NULL) 22443f843443Smillert return(1); 22453f843443Smillert else if (mi2->mountpoint == NULL) 22463f843443Smillert return(-1); 22473f843443Smillert else 22483f843443Smillert return(strcmp(mi1->mountpoint, mi2->mountpoint)); 22493f843443Smillert } 2250c33fcabaSmillert 2251c33fcabaSmillert void 225287023ed9Skrw get_geometry(int f, struct disklabel **dgpp) 2253c33fcabaSmillert { 2254c33fcabaSmillert struct stat st; 2255c33fcabaSmillert struct disklabel *disk_geop; 225687023ed9Skrw 2257c33fcabaSmillert if (fstat(f, &st) == -1) 2258c33fcabaSmillert err(4, "Can't stat device"); 2259c33fcabaSmillert 2260c33fcabaSmillert /* Get disk geometry */ 2261c33fcabaSmillert if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL) 2262c33fcabaSmillert errx(4, "out of memory"); 2263c33fcabaSmillert if (ioctl(f, DIOCGPDINFO, disk_geop) < 0 && 2264c33fcabaSmillert ioctl(f, DIOCGDINFO, disk_geop) < 0) 2265c33fcabaSmillert err(4, "ioctl DIOCGDINFO"); 2266c33fcabaSmillert *dgpp = disk_geop; 2267c33fcabaSmillert } 2268c33fcabaSmillert 2269c33fcabaSmillert void 22708809fabbSderaadt set_geometry(struct disklabel *lp, struct disklabel *dgp, 227187023ed9Skrw struct disklabel *ugp, char *p) 2272c33fcabaSmillert { 2273c33fcabaSmillert if (p == NULL) { 22749a36aa41Ssthen p = getstring("[d]isk or [u]ser geometry", 2275c33fcabaSmillert "Enter 'd' to use the geometry based on what the disk " 22769a36aa41Ssthen "itself thinks it is, or 'u' to use the geometry that " 22779a36aa41Ssthen "was found in the label.", 2278c33fcabaSmillert "d"); 2279c33fcabaSmillert } 2280c33fcabaSmillert if (p == NULL) { 2281c33fcabaSmillert fputs("Command aborted\n", stderr); 2282c33fcabaSmillert return; 2283c33fcabaSmillert } 2284c33fcabaSmillert switch (*p) { 2285c33fcabaSmillert case 'd': 2286c33fcabaSmillert case 'D': 2287c33fcabaSmillert if (dgp == NULL) 2288c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2289c33fcabaSmillert else { 2290c33fcabaSmillert lp->d_secsize = dgp->d_secsize; 2291c33fcabaSmillert lp->d_nsectors = dgp->d_nsectors; 2292c33fcabaSmillert lp->d_ntracks = dgp->d_ntracks; 2293c33fcabaSmillert lp->d_ncylinders = dgp->d_ncylinders; 2294c33fcabaSmillert lp->d_secpercyl = dgp->d_secpercyl; 229534af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(dgp)); 2296c33fcabaSmillert } 2297c33fcabaSmillert break; 2298c33fcabaSmillert case 'u': 2299c33fcabaSmillert case 'U': 2300c33fcabaSmillert if (ugp == NULL) 2301c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2302c33fcabaSmillert else { 2303c33fcabaSmillert lp->d_secsize = ugp->d_secsize; 2304c33fcabaSmillert lp->d_nsectors = ugp->d_nsectors; 2305c33fcabaSmillert lp->d_ntracks = ugp->d_ntracks; 2306c33fcabaSmillert lp->d_ncylinders = ugp->d_ncylinders; 2307c33fcabaSmillert lp->d_secpercyl = ugp->d_secpercyl; 230834af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(ugp)); 2309c33fcabaSmillert if (dgp != NULL && ugp->d_secsize == dgp->d_secsize && 2310c33fcabaSmillert ugp->d_nsectors == dgp->d_nsectors && 2311c33fcabaSmillert ugp->d_ntracks == dgp->d_ntracks && 2312c33fcabaSmillert ugp->d_ncylinders == dgp->d_ncylinders && 2313c33fcabaSmillert ugp->d_secpercyl == dgp->d_secpercyl && 231434af67a3Sotto DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp)) 2315c33fcabaSmillert fputs("Note: user geometry is the same as disk " 2316c33fcabaSmillert "geometry.\n", stderr); 2317c33fcabaSmillert } 2318c33fcabaSmillert break; 2319c33fcabaSmillert default: 23209a36aa41Ssthen fputs("You must enter either 'd' or 'u'.\n", stderr); 2321c33fcabaSmillert break; 2322c33fcabaSmillert } 2323c33fcabaSmillert } 23249afbe9eeSmillert 23259afbe9eeSmillert void 23269fdcb4d6Skrw zero_partitions(struct disklabel *lp) 23279afbe9eeSmillert { 23289afbe9eeSmillert int i; 23299afbe9eeSmillert 2330b4ed6301Skrw for (i = 0; i < MAXPARTITIONS; i++) { 23319afbe9eeSmillert memset(&lp->d_partitions[i], 0, sizeof(struct partition)); 2332b4ed6301Skrw free(mountpoints[i]); 2333b4ed6301Skrw mountpoints[i] = NULL; 2334b4ed6301Skrw } 2335b4ed6301Skrw 233634af67a3Sotto DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); 23379afbe9eeSmillert } 233814192793Skrw 233914192793Skrw u_int64_t 234014192793Skrw max_partition_size(struct disklabel *lp, int partno) 234114192793Skrw { 234214192793Skrw struct partition *pp = &lp->d_partitions[partno]; 234314192793Skrw struct diskchunk *chunks; 2344*44ffe03bSotto u_int64_t maxsize = 0, offset; 234514192793Skrw int fstype, i; 234614192793Skrw 234714192793Skrw fstype = pp->p_fstype; 234814192793Skrw pp->p_fstype = FS_UNUSED; 234914192793Skrw chunks = free_chunks(lp); 235014192793Skrw pp->p_fstype = fstype; 235114192793Skrw 235214192793Skrw offset = DL_GETPOFFSET(pp); 235314192793Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 235414192793Skrw if (offset < chunks[i].start || offset >= chunks[i].stop) 235514192793Skrw continue; 235614192793Skrw maxsize = chunks[i].stop - offset; 235714192793Skrw break; 235814192793Skrw } 235914192793Skrw return (maxsize); 236014192793Skrw } 2361aff3f969Sotto 2362aff3f969Sotto void 2363aff3f969Sotto psize(daddr64_t sz, char unit, struct disklabel *lp) 2364aff3f969Sotto { 2365aff3f969Sotto double d = scale(sz, unit, lp); 2366aff3f969Sotto if (d < 0) 2367aff3f969Sotto printf("%llu", sz); 2368aff3f969Sotto else 2369aff3f969Sotto printf("%.*f%c", unit == 'B' ? 0 : 1, d, unit); 2370aff3f969Sotto } 2371aff3f969Sotto 2372aff3f969Sotto void 237334ae4198Skrw display_edit(struct disklabel *lp, char unit, u_int64_t fr) 2374aff3f969Sotto { 2375aff3f969Sotto int i; 2376aff3f969Sotto 2377352d199bSkrw unit = canonical_unit(lp, unit); 2378aff3f969Sotto 2379aff3f969Sotto printf("OpenBSD area: "); 238059882f1dSkrw psize(starting_sector, 0, lp); 2381aff3f969Sotto printf("-"); 238259882f1dSkrw psize(ending_sector, 0, lp); 2383aff3f969Sotto printf("; size: "); 2384aff3f969Sotto psize(ending_sector - starting_sector, unit, lp); 2385aff3f969Sotto printf("; free: "); 2386aff3f969Sotto psize(fr, unit, lp); 2387aff3f969Sotto 2388aff3f969Sotto printf("\n# %16.16s %16.16s fstype [fsize bsize cpg]\n", 2389aff3f969Sotto "size", "offset"); 2390aff3f969Sotto for (i = 0; i < lp->d_npartitions; i++) 239134ae4198Skrw display_partition(stdout, lp, i, unit); 2392aff3f969Sotto } 2393aff3f969Sotto 2394