1*d18c2a43Skrw /* $OpenBSD: editor.c,v 1.160 2008/01/22 00:06:25 krw 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 #ifndef lint 20*d18c2a43Skrw static char rcsid[] = "$OpenBSD: editor.c,v 1.160 2008/01/22 00:06:25 krw Exp $"; 216fe57b42Smillert #endif /* not lint */ 226fe57b42Smillert 236fe57b42Smillert #include <sys/types.h> 246fe57b42Smillert #include <sys/param.h> 25c33fcabaSmillert #include <sys/stat.h> 26c33fcabaSmillert #include <sys/ioctl.h> 276fe57b42Smillert #define DKTYPENAMES 286fe57b42Smillert #include <sys/disklabel.h> 296fe57b42Smillert 306fe57b42Smillert #include <ufs/ffs/fs.h> 316fe57b42Smillert 326fe57b42Smillert #include <ctype.h> 336fe57b42Smillert #include <err.h> 346fe57b42Smillert #include <errno.h> 356fe57b42Smillert #include <string.h> 36803ff7d5Smillert #include <libgen.h> 376fe57b42Smillert #include <stdio.h> 386fe57b42Smillert #include <stdlib.h> 396fe57b42Smillert #include <unistd.h> 406fe57b42Smillert 41f21a098bSotto #include "extern.h" 424793b14cSmillert #include "pathnames.h" 434793b14cSmillert 446fe57b42Smillert /* flags for getuint() */ 456fe57b42Smillert #define DO_CONVERSIONS 0x00000001 466fe57b42Smillert #define DO_ROUNDING 0x00000002 476fe57b42Smillert 48f98aebd4Smillert #ifndef NUMBOOT 49f98aebd4Smillert #define NUMBOOT 0 50f98aebd4Smillert #endif 51f98aebd4Smillert 5296a888c6Smillert /* structure to describe a portion of a disk */ 5396a888c6Smillert struct diskchunk { 541e0ad43cSotto u_int64_t start; 551e0ad43cSotto u_int64_t stop; 5696a888c6Smillert }; 5796a888c6Smillert 583f843443Smillert /* used when sorting mountpoints in mpsave() */ 593f843443Smillert struct mountinfo { 603f843443Smillert char *mountpoint; 613f843443Smillert int partno; 623f843443Smillert }; 633f843443Smillert 649fdcb4d6Skrw void edit_parms(struct disklabel *); 659fdcb4d6Skrw void editor_add(struct disklabel *, char **, char *); 669fdcb4d6Skrw void editor_change(struct disklabel *, char *); 679fdcb4d6Skrw u_int64_t editor_countfree(struct disklabel *); 689fdcb4d6Skrw void editor_delete(struct disklabel *, char **, char *); 69c72b5b24Smillert void editor_help(char *); 709fdcb4d6Skrw void editor_modify(struct disklabel *, char **, char *); 71c72b5b24Smillert void editor_name(struct disklabel *, char **, char *); 72c72b5b24Smillert char *getstring(char *, char *, char *); 731e0ad43cSotto u_int64_t getuint(struct disklabel *, int, char *, char *, u_int64_t, u_int64_t, u_int64_t, int); 741f0f871dSkrw int has_overlap(struct disklabel *); 75c72b5b24Smillert int partition_cmp(const void *, const void *); 76c72b5b24Smillert struct partition **sort_partitions(struct disklabel *, u_int16_t *); 77c72b5b24Smillert void getdisktype(struct disklabel *, char *, char *); 7887023ed9Skrw void find_bounds(struct disklabel *); 799fdcb4d6Skrw void set_bounds(struct disklabel *); 80c72b5b24Smillert struct diskchunk *free_chunks(struct disklabel *); 81c72b5b24Smillert char ** mpcopy(char **, char **); 82c72b5b24Smillert int micmp(const void *, const void *); 83c72b5b24Smillert int mpequal(char **, char **); 84c72b5b24Smillert int mpsave(struct disklabel *, char **, char *, char *); 85c72b5b24Smillert int get_bsize(struct disklabel *, int); 86c72b5b24Smillert int get_fsize(struct disklabel *, int); 87c72b5b24Smillert int get_fstype(struct disklabel *, int); 88c72b5b24Smillert int get_mp(struct disklabel *, char **, int); 89604d3bdeSkrw int get_offset(struct disklabel *, int); 909fdcb4d6Skrw int get_size(struct disklabel *, int); 9187023ed9Skrw void get_geometry(int, struct disklabel **); 9287023ed9Skrw void set_geometry(struct disklabel *, struct disklabel *, struct disklabel *, 9387023ed9Skrw char *); 949fdcb4d6Skrw void zero_partitions(struct disklabel *); 9514192793Skrw u_int64_t max_partition_size(struct disklabel *, int); 9696a888c6Smillert 971e0ad43cSotto static u_int64_t starting_sector; 981e0ad43cSotto static u_int64_t ending_sector; 992d8451b0Smillert static int expert; 1006fe57b42Smillert 1016fe57b42Smillert /* 1026fe57b42Smillert * Simple partition editor. Primarily intended for new labels. 1036fe57b42Smillert */ 1046fe57b42Smillert int 1058809fabbSderaadt editor(struct disklabel *lp, int f, char *dev, char *fstabfile) 1066fe57b42Smillert { 1076fe57b42Smillert struct disklabel lastlabel, tmplabel, label = *lp; 10887023ed9Skrw struct disklabel *disk_geop; 10996a888c6Smillert struct partition *pp; 1106fe57b42Smillert FILE *fp; 1116fe57b42Smillert char buf[BUFSIZ], *cmd, *arg; 112a4df0321Sderaadt char **mountpoints = NULL, **omountpoints = NULL, **tmpmountpoints = NULL; 113bd6726faSmillert 114bd6726faSmillert /* Alloc and init mount point info */ 115bd6726faSmillert if (fstabfile) { 116bd6726faSmillert if (!(mountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 117bd6726faSmillert !(omountpoints = calloc(MAXPARTITIONS, sizeof(char *))) || 118bd6726faSmillert !(tmpmountpoints = calloc(MAXPARTITIONS, sizeof(char *)))) 119bd6726faSmillert errx(4, "out of memory"); 120bd6726faSmillert } 1216fe57b42Smillert 12296a888c6Smillert /* Don't allow disk type of "unknown" */ 123803ff7d5Smillert getdisktype(&label, "You need to specify a type for this disk.", dev); 1246fe57b42Smillert 12587023ed9Skrw /* Get the on-disk geometries if possible */ 12687023ed9Skrw get_geometry(f, &disk_geop); 127c33fcabaSmillert 128d09f3941Smillert /* How big is the OpenBSD portion of the disk? */ 12987023ed9Skrw find_bounds(&label); 130d09f3941Smillert 13196a888c6Smillert /* Make sure there is no partition overlap. */ 1321f0f871dSkrw if (has_overlap(&label)) 1336fe57b42Smillert errx(1, "can't run when there is partition overlap."); 1346fe57b42Smillert 13596a888c6Smillert /* If we don't have a 'c' partition, create one. */ 136d09f3941Smillert pp = &label.d_partitions[RAW_PART]; 1371e0ad43cSotto if (label.d_npartitions < 3 || DL_GETPSIZE(pp) == 0) { 13896a888c6Smillert puts("No 'c' partition found, adding one that spans the disk."); 13996a888c6Smillert if (label.d_npartitions < 3) 14096a888c6Smillert label.d_npartitions = 3; 14134af67a3Sotto DL_SETPOFFSET(pp, 0); 14234af67a3Sotto DL_SETPSIZE(pp, DL_GETDSIZE(&label)); 14396a888c6Smillert pp->p_fstype = FS_UNUSED; 144ddfcbf38Sotto pp->p_fragblock = pp->p_cpg = 0; 14596a888c6Smillert } 1460f820bbbSmillert 147fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 148fc1a4cc6Sderaadt if (label.d_flags & D_VENDOR) { 149fc1a4cc6Sderaadt puts("This platform requires that partition offsets/sizes " 150fc1a4cc6Sderaadt "be on cylinder boundaries.\n" 151fc1a4cc6Sderaadt "Partition offsets/sizes will be rounded to the " 152fc1a4cc6Sderaadt "nearest cylinder automatically."); 153fc1a4cc6Sderaadt } 1546fe57b42Smillert #endif 1556fe57b42Smillert 156bd6726faSmillert /* Set d_bbsize and d_sbsize as necessary */ 15755403f76Smillert if (label.d_bbsize == 0) 15855403f76Smillert label.d_bbsize = BBSIZE; 15955403f76Smillert if (label.d_sbsize == 0) 16055403f76Smillert label.d_sbsize = SBSIZE; 161f98aebd4Smillert 162440b1d70Smillert /* Interleave must be >= 1 */ 163440b1d70Smillert if (label.d_interleave == 0) 164440b1d70Smillert label.d_interleave = 1; 165440b1d70Smillert 1666893bfe5Sderaadt puts("Initial label editor (enter '?' for help at any prompt)"); 1676fe57b42Smillert lastlabel = label; 1686fe57b42Smillert for (;;) { 1696fe57b42Smillert fputs("> ", stdout); 1706e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 1716e0becc5Smillert putchar('\n'); 1726e0becc5Smillert buf[0] = 'q'; 1736e0becc5Smillert buf[1] = '\0'; 1746e0becc5Smillert } 175260513deSmillert if ((cmd = strtok(buf, " \t\r\n")) == NULL) 176260513deSmillert continue; 177260513deSmillert arg = strtok(NULL, " \t\r\n"); 1786fe57b42Smillert 1796fe57b42Smillert switch (*cmd) { 1806fe57b42Smillert 1816fe57b42Smillert case '?': 182ea37abd3Sderaadt case 'h': 183617e6e4aSmillert editor_help(arg ? arg : ""); 1846fe57b42Smillert break; 1856fe57b42Smillert 1866fe57b42Smillert case 'a': 1876fe57b42Smillert tmplabel = lastlabel; 1886fe57b42Smillert lastlabel = label; 189bd6726faSmillert if (mountpoints != NULL) { 190bd6726faSmillert mpcopy(tmpmountpoints, omountpoints); 191bd6726faSmillert mpcopy(omountpoints, mountpoints); 192bd6726faSmillert } 1939fdcb4d6Skrw editor_add(&label, mountpoints, arg); 19496a888c6Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 19596a888c6Smillert lastlabel = tmplabel; 196bd6726faSmillert if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints)) 197bd6726faSmillert mpcopy(omountpoints, tmpmountpoints); 19896a888c6Smillert break; 19996a888c6Smillert 20096a888c6Smillert case 'b': 20196a888c6Smillert tmplabel = lastlabel; 20296a888c6Smillert lastlabel = label; 2039fdcb4d6Skrw set_bounds(&label); 2046fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2056fe57b42Smillert lastlabel = tmplabel; 2066fe57b42Smillert break; 2076fe57b42Smillert 2086fe57b42Smillert case 'c': 2096fe57b42Smillert tmplabel = lastlabel; 2106fe57b42Smillert lastlabel = label; 2119fdcb4d6Skrw editor_change(&label, arg); 2126fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2136fe57b42Smillert lastlabel = tmplabel; 2146fe57b42Smillert break; 2156fe57b42Smillert 2169afbe9eeSmillert case 'D': 217cdd7eb76Smillert tmplabel = lastlabel; 218cdd7eb76Smillert lastlabel = label; 21971bba4ecSkrw if (ioctl(f, DIOCGPDINFO, &label) == 0) { 22071bba4ecSkrw dflag = 1; 22171bba4ecSkrw } else { 222cdd7eb76Smillert warn("unable to get default partition table"); 223cdd7eb76Smillert lastlabel = tmplabel; 224cdd7eb76Smillert } 2259afbe9eeSmillert break; 2269afbe9eeSmillert 2276fe57b42Smillert case 'd': 2286fe57b42Smillert tmplabel = lastlabel; 2296fe57b42Smillert lastlabel = label; 230bd6726faSmillert if (mountpoints != NULL) { 231bd6726faSmillert mpcopy(tmpmountpoints, omountpoints); 232bd6726faSmillert mpcopy(omountpoints, mountpoints); 233bd6726faSmillert } 2349fdcb4d6Skrw editor_delete(&label, mountpoints, arg); 2356fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2366fe57b42Smillert lastlabel = tmplabel; 237bd6726faSmillert if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints)) 238bd6726faSmillert mpcopy(omountpoints, tmpmountpoints); 2396fe57b42Smillert break; 2406fe57b42Smillert 2419afbe9eeSmillert case 'e': 2429afbe9eeSmillert tmplabel = lastlabel; 2439afbe9eeSmillert lastlabel = label; 2449fdcb4d6Skrw edit_parms(&label); 2459afbe9eeSmillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2469afbe9eeSmillert lastlabel = tmplabel; 2479afbe9eeSmillert break; 2489afbe9eeSmillert 249c33fcabaSmillert case 'g': 250c33fcabaSmillert tmplabel = lastlabel; 251c33fcabaSmillert lastlabel = label; 25287023ed9Skrw set_geometry(&label, disk_geop, lp, arg); 253c33fcabaSmillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 254c33fcabaSmillert lastlabel = tmplabel; 255c33fcabaSmillert break; 256c33fcabaSmillert 2576fe57b42Smillert case 'm': 2586fe57b42Smillert tmplabel = lastlabel; 2596fe57b42Smillert lastlabel = label; 260bd6726faSmillert if (mountpoints != NULL) { 261bd6726faSmillert mpcopy(tmpmountpoints, omountpoints); 262bd6726faSmillert mpcopy(omountpoints, mountpoints); 263bd6726faSmillert } 2649fdcb4d6Skrw editor_modify(&label, mountpoints, arg); 2656fe57b42Smillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0) 2666fe57b42Smillert lastlabel = tmplabel; 267bd6726faSmillert if (mountpoints != NULL && mpequal(omountpoints, tmpmountpoints)) 268bd6726faSmillert mpcopy(omountpoints, tmpmountpoints); 269bd6726faSmillert break; 270bd6726faSmillert 271bd6726faSmillert case 'n': 272bd6726faSmillert if (mountpoints == NULL) { 273bd6726faSmillert fputs("This option is not valid when run " 27484d0bb16Sderaadt "without the -f flag.\n", stderr); 275bd6726faSmillert break; 276bd6726faSmillert } 277bd6726faSmillert mpcopy(tmpmountpoints, omountpoints); 278bd6726faSmillert mpcopy(omountpoints, mountpoints); 279bd6726faSmillert editor_name(&label, mountpoints, arg); 280bd6726faSmillert if (mpequal(omountpoints, tmpmountpoints)) 281bd6726faSmillert mpcopy(omountpoints, tmpmountpoints); 2826fe57b42Smillert break; 2836fe57b42Smillert 2846fe57b42Smillert case 'p': 2855b19a791Sotto display(stdout, &label, mountpoints, arg ? *arg : 0, 1, 2869fdcb4d6Skrw editor_countfree(&label)); 2876fe57b42Smillert break; 2886fe57b42Smillert 289508086e9Smillert case 'M': { 290508086e9Smillert sig_t opipe = signal(SIGPIPE, SIG_IGN); 29108f8e31fSotto char *pager, *cmd = NULL; 292e7936562Sderaadt extern const u_char manpage[]; 29308f8e31fSotto extern const int manpage_sz; 2945d12b01bSderaadt 295489bd112Spjanzen if ((pager = getenv("PAGER")) == NULL || *pager == '\0') 296508086e9Smillert pager = _PATH_LESS; 29708f8e31fSotto 29808f8e31fSotto if (asprintf(&cmd, "gunzip -qc|%s", pager) != -1 && 29908f8e31fSotto (fp = popen(cmd, "w")) != NULL) { 30008f8e31fSotto (void) fwrite(manpage, manpage_sz, 1, fp); 3015d12b01bSderaadt pclose(fp); 302508086e9Smillert } else 303508086e9Smillert warn("unable to execute %s", pager); 304508086e9Smillert 30508f8e31fSotto free(cmd); 306508086e9Smillert (void)signal(SIGPIPE, opipe); 3075d12b01bSderaadt break; 308508086e9Smillert } 3095d12b01bSderaadt 3106fe57b42Smillert case 'q': 31169220492Smillert if (donothing) { 31269220492Smillert puts("In no change mode, not writing label."); 31369220492Smillert return(1); 31469220492Smillert } 315bd6726faSmillert /* Save mountpoint info if there is any. */ 316bd6726faSmillert if (mountpoints != NULL) 317bd6726faSmillert mpsave(&label, mountpoints, dev, fstabfile); 31871bba4ecSkrw /* 31971bba4ecSkrw * If we didn't manufacture a new default label and 32071bba4ecSkrw * didn't change the label read from disk, there is no 32171bba4ecSkrw * need to do anything before exiting. 32271bba4ecSkrw */ 32371bba4ecSkrw if (!dflag && memcmp(lp, &label, sizeof(label)) == 0) { 324bd6726faSmillert puts("No label changes."); 3256fe57b42Smillert return(1); 3266fe57b42Smillert } 3276fe57b42Smillert do { 328d0e67762Smillert arg = getstring("Write new label?", 329d0e67762Smillert "Write the modified label to disk?", 330d0e67762Smillert "y"); 33196a888c6Smillert } while (arg && tolower(*arg) != 'y' && tolower(*arg) != 'n'); 33296a888c6Smillert if (arg && tolower(*arg) == 'y') { 333d0e67762Smillert if (writelabel(f, bootarea, &label) == 0) { 3346fe57b42Smillert *lp = label; 3356fe57b42Smillert return(0); 3366fe57b42Smillert } 337d0e67762Smillert warnx("unable to write label"); 338d0e67762Smillert } 3396fe57b42Smillert return(1); 3406fe57b42Smillert /* NOTREACHED */ 3416fe57b42Smillert break; 3426fe57b42Smillert 34325f9c360Skrw case 'r': { 34425f9c360Skrw struct diskchunk *chunks; 34525f9c360Skrw int i; 3469fdcb4d6Skrw /* Display free space. */ 34725f9c360Skrw chunks = free_chunks(&label); 34825f9c360Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; 34925f9c360Skrw i++) 35025f9c360Skrw fprintf(stderr, "Free sectors: %16llu - %16llu " 35125f9c360Skrw "(%16llu)\n", 35225f9c360Skrw chunks[i].start, chunks[i].stop - 1, 35325f9c360Skrw chunks[i].stop - chunks[i].start); 35425f9c360Skrw fprintf(stderr, "Total free sectors: %llu.\n", 3559fdcb4d6Skrw editor_countfree(&label)); 356c0bdc608Smillert break; 35725f9c360Skrw } 358c0bdc608Smillert 3596fe57b42Smillert case 's': 3606fe57b42Smillert if (arg == NULL) { 361c33fcabaSmillert arg = getstring("Filename", 3626fe57b42Smillert "Name of the file to save label into.", 3636fe57b42Smillert NULL); 36496a888c6Smillert if (arg == NULL && *arg == '\0') 3656fe57b42Smillert break; 3666fe57b42Smillert } 3676fe57b42Smillert if ((fp = fopen(arg, "w")) == NULL) { 3686fe57b42Smillert warn("cannot open %s", arg); 3696fe57b42Smillert } else { 3705b19a791Sotto display(fp, &label, NULL, 0, 0, 0); 3716fe57b42Smillert (void)fclose(fp); 3726fe57b42Smillert } 3736fe57b42Smillert break; 3746fe57b42Smillert 3756fe57b42Smillert case 'u': 376bd6726faSmillert if (memcmp(&label, &lastlabel, sizeof(label)) == 0 && 377bd6726faSmillert mountpoints != NULL && 378bd6726faSmillert mpequal(mountpoints, omountpoints)) { 3796fe57b42Smillert puts("Nothing to undo!"); 3806fe57b42Smillert } else { 3816fe57b42Smillert tmplabel = label; 3826fe57b42Smillert label = lastlabel; 3836fe57b42Smillert lastlabel = tmplabel; 384bd6726faSmillert /* Restore mountpoints */ 385bd6726faSmillert if (mountpoints != NULL) 386bd6726faSmillert mpcopy(mountpoints, omountpoints); 3876fe57b42Smillert puts("Last change undone."); 3886fe57b42Smillert } 3896fe57b42Smillert break; 3906fe57b42Smillert 391040947cfSmillert case 'w': 392bd6726faSmillert if (donothing) { 393040947cfSmillert puts("In no change mode, not writing label."); 394bd6726faSmillert break; 395bd6726faSmillert } 396bd6726faSmillert /* Save mountpoint info if there is any. */ 397bd6726faSmillert if (mountpoints != NULL) 398bd6726faSmillert mpsave(&label, mountpoints, dev, fstabfile); 39941f684b9Skrw /* Write label to disk. */ 40041f684b9Skrw if (writelabel(f, bootarea, &label) != 0) 401040947cfSmillert warnx("unable to write label"); 40271bba4ecSkrw else { 40371bba4ecSkrw dflag = 0; 4045af08e9cSmillert *lp = label; 40571bba4ecSkrw } 406040947cfSmillert break; 407040947cfSmillert 4082d8451b0Smillert case 'X': 4092d8451b0Smillert expert = !expert; 4102d8451b0Smillert printf("%s expert mode\n", expert ? "Entering" : 4112d8451b0Smillert "Exiting"); 4122d8451b0Smillert break; 4132d8451b0Smillert 4146fe57b42Smillert case 'x': 4156fe57b42Smillert return(1); 4166fe57b42Smillert break; 4176fe57b42Smillert 4189afbe9eeSmillert case 'z': 419cdd7eb76Smillert tmplabel = lastlabel; 420cdd7eb76Smillert lastlabel = label; 4219fdcb4d6Skrw zero_partitions(&label); 4226fe57b42Smillert break; 4236fe57b42Smillert 4249afbe9eeSmillert case '\n': 4256fe57b42Smillert break; 4266fe57b42Smillert 4276fe57b42Smillert default: 4286fe57b42Smillert printf("Unknown option: %c ('?' for help)\n", *cmd); 4296fe57b42Smillert break; 4306fe57b42Smillert } 4316fe57b42Smillert } 4326fe57b42Smillert } 4336fe57b42Smillert 4346fe57b42Smillert /* 4356fe57b42Smillert * Add a new partition. 4366fe57b42Smillert */ 4376fe57b42Smillert void 4389fdcb4d6Skrw editor_add(struct disklabel *lp, char **mp, char *p) 4396fe57b42Smillert { 44096a888c6Smillert struct partition *pp; 44196a888c6Smillert struct diskchunk *chunks; 4425caa08b2Skrw char buf[2]; 4436fe57b42Smillert int i, partno; 444f8ab7229Schl u_int64_t freesectors, new_offset, new_size; 4459fdcb4d6Skrw 4469fdcb4d6Skrw freesectors = editor_countfree(lp); 4476fe57b42Smillert 4486fe57b42Smillert /* XXX - prompt user to steal space from another partition instead */ 449fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 4509fdcb4d6Skrw if ((lp->d_flags & D_VENDOR) && freesectors < lp->d_secpercyl) { 451fc1a4cc6Sderaadt fputs("No space left, you need to shrink a partition " 452fc1a4cc6Sderaadt "(need at least one full cylinder)\n", 453fc1a4cc6Sderaadt stderr); 454fc1a4cc6Sderaadt return; 455fc1a4cc6Sderaadt } 4568390cf28Smillert #endif 4579fdcb4d6Skrw if (freesectors == 0) { 4586fe57b42Smillert fputs("No space left, you need to shrink a partition\n", 4596fe57b42Smillert stderr); 4606fe57b42Smillert return; 4616fe57b42Smillert } 4626fe57b42Smillert 4635caa08b2Skrw if (p == NULL) { 4645caa08b2Skrw /* 4655caa08b2Skrw * Use the first unused partition that is not 'c' as the 4665caa08b2Skrw * default partition in the prompt string. 4675caa08b2Skrw */ 4685caa08b2Skrw pp = &lp->d_partitions[0]; 4695caa08b2Skrw buf[0] = buf[1] = '\0'; 4705caa08b2Skrw for (partno = 0; partno < MAXPARTITIONS; partno++, pp++) { 4715caa08b2Skrw if (DL_GETPSIZE(pp) == 0 && partno != RAW_PART) { 4725caa08b2Skrw buf[0] = partno + 'a'; 4735caa08b2Skrw p = &buf[0]; 4746fe57b42Smillert break; 4756fe57b42Smillert } 4765caa08b2Skrw } 477c33fcabaSmillert p = getstring("partition", 4786fe57b42Smillert "The letter of the new partition, a - p.", p); 4796fe57b42Smillert } 4805caa08b2Skrw if (p == NULL) { 4815caa08b2Skrw fputs("Command aborted\n", stderr); 4825caa08b2Skrw return; 4835caa08b2Skrw } 4845caa08b2Skrw partno = p[0] - 'a'; 4855caa08b2Skrw if (partno < 0 || partno == RAW_PART || partno >= MAXPARTITIONS) { 4865caa08b2Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 4875caa08b2Skrw "(excluding 'c').\n", 'a' + MAXPARTITIONS - 1); 4885caa08b2Skrw return; 4895caa08b2Skrw } 4905caa08b2Skrw pp = &lp->d_partitions[partno]; 4915caa08b2Skrw 4925caa08b2Skrw if (pp->p_fstype != FS_UNUSED && DL_GETPSIZE(pp) != 0) { 4935caa08b2Skrw fprintf(stderr, "Partition '%c' exists. Delete it first.\n", 4945caa08b2Skrw p[0]); 4955caa08b2Skrw return; 4966fe57b42Smillert } 49796a888c6Smillert 498caf41f96Skrw /* 499caf41f96Skrw * Increase d_npartitions if necessary. Ensure all new partitions are 500caf41f96Skrw * zero'ed to avoid inadvertant overlaps. 501caf41f96Skrw */ 502caf41f96Skrw for(; lp->d_npartitions <= partno; lp->d_npartitions++) 503caf41f96Skrw memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(*pp)); 50496a888c6Smillert 50589f4601dSkrw /* Make sure selected partition is zero'd too. */ 50689f4601dSkrw memset(pp, 0, sizeof(*pp)); 50715c15d8aSkrw chunks = free_chunks(lp); 50815c15d8aSkrw 50915c15d8aSkrw /* 51015c15d8aSkrw * Since we know there's free space, there must be at least one 51115c15d8aSkrw * chunk. So find the largest chunk and assume we want to add the 51215c15d8aSkrw * partition in that free space. 51315c15d8aSkrw */ 51415c15d8aSkrw new_size = new_offset = 0; 51515c15d8aSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 51615c15d8aSkrw if (chunks[i].stop - chunks[i].start > new_size) { 51715c15d8aSkrw new_size = chunks[i].stop - chunks[i].start; 51815c15d8aSkrw new_offset = chunks[i].start; 51915c15d8aSkrw } 52015c15d8aSkrw } 5211e0ad43cSotto DL_SETPSIZE(pp, new_size); 5221e0ad43cSotto DL_SETPOFFSET(pp, new_offset); 52396a888c6Smillert pp->p_fstype = partno == 1 ? FS_SWAP : FS_BSDFFS; 5244a8b9208Stedu #if defined (__sparc__) && !defined(__sparc64__) 525d98d4df7Stedu /* can't boot from > 8k boot blocks */ 526ddfcbf38Sotto pp->p_fragblock = 527ddfcbf38Sotto DISKLABELV1_FFS_FRAGBLOCK(partno == 0 ? 1024 : 2048, 8); 528d98d4df7Stedu #else 529ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(2048, 8); 530d98d4df7Stedu #endif 5319b972314Skrw pp->p_cpg = 1; 53296a888c6Smillert 533a4c87e64Skrw if (get_offset(lp, partno) == 0 && 534a4c87e64Skrw get_size(lp, partno) == 0 && 535a4c87e64Skrw get_fstype(lp, partno) == 0 && 536a4c87e64Skrw get_mp(lp, mp, partno) == 0 && 537a4c87e64Skrw get_fsize(lp, partno) == 0 && 538a4c87e64Skrw get_bsize(lp, partno) == 0) 53996a888c6Smillert return; 54096a888c6Smillert 541a4c87e64Skrw /* Bailed out at some point, so effectively delete the partition. */ 542a4c87e64Skrw DL_SETPSIZE(pp, 0); 5436fe57b42Smillert } 5446fe57b42Smillert 5456fe57b42Smillert /* 546bd6726faSmillert * Set the mountpoint of an existing partition ('name'). 547bd6726faSmillert */ 548bd6726faSmillert void 5498809fabbSderaadt editor_name(struct disklabel *lp, char **mp, char *p) 550bd6726faSmillert { 551bd6726faSmillert struct partition *pp; 552bd6726faSmillert int partno; 553bd6726faSmillert 554bd6726faSmillert /* Change which partition? */ 555bd6726faSmillert if (p == NULL) { 556c33fcabaSmillert p = getstring("partition to name", 557bd6726faSmillert "The letter of the partition to name, a - p.", NULL); 558bd6726faSmillert } 559bd6726faSmillert if (p == NULL) { 560bd6726faSmillert fputs("Command aborted\n", stderr); 561bd6726faSmillert return; 562bd6726faSmillert } 563bd6726faSmillert partno = p[0] - 'a'; 5646c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 5656c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 5666c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 567bd6726faSmillert return; 56866df1f0cSkrw } 56966df1f0cSkrw pp = &lp->d_partitions[partno]; 57066df1f0cSkrw 57166df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 57266df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 573bd6726faSmillert return; 574bd6726faSmillert } 575bd6726faSmillert 576bd6726faSmillert /* Not all fstypes can be named */ 577bd6726faSmillert if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_SWAP || 578bd387921Stodd pp->p_fstype == FS_BOOT || pp->p_fstype == FS_OTHER || 579bd387921Stodd pp->p_fstype == FS_RAID) { 580bd6726faSmillert fprintf(stderr, "You cannot name a filesystem of type %s.\n", 581baa55472Smillert fstypenames[lp->d_partitions[partno].p_fstype]); 582bd6726faSmillert return; 583bd6726faSmillert } 584bd6726faSmillert 585ddaff619Smillert get_mp(lp, mp, partno); 586bd6726faSmillert } 587bd6726faSmillert 588bd6726faSmillert /* 5896fe57b42Smillert * Change an existing partition. 5906fe57b42Smillert */ 5916fe57b42Smillert void 5929fdcb4d6Skrw editor_modify(struct disklabel *lp, char **mp, char *p) 5936fe57b42Smillert { 5946fe57b42Smillert struct partition origpart, *pp; 595f8ab7229Schl int partno; 5966fe57b42Smillert 5976fe57b42Smillert /* Change which partition? */ 5986fe57b42Smillert if (p == NULL) { 599c33fcabaSmillert p = getstring("partition to modify", 6006fe57b42Smillert "The letter of the partition to modify, a - p.", NULL); 6016fe57b42Smillert } 60296a888c6Smillert if (p == NULL) { 60396a888c6Smillert fputs("Command aborted\n", stderr); 60496a888c6Smillert return; 60596a888c6Smillert } 6066fe57b42Smillert partno = p[0] - 'a'; 6076c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 6086c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 6096c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 6106fe57b42Smillert return; 61166df1f0cSkrw } 61266df1f0cSkrw pp = &lp->d_partitions[partno]; 61366df1f0cSkrw 61466df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 61566df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 6166fe57b42Smillert return; 6176fe57b42Smillert } 6186fe57b42Smillert 61966df1f0cSkrw origpart = *pp; 62066df1f0cSkrw 621a4c87e64Skrw if (get_offset(lp, partno) == 0 && 622a4c87e64Skrw get_size(lp, partno) == 0 && 623a4c87e64Skrw get_fstype(lp, partno) == 0 && 624a4c87e64Skrw get_mp(lp, mp, partno) == 0 && 625a4c87e64Skrw get_fsize(lp, partno) == 0 && 626a4c87e64Skrw get_bsize(lp, partno) == 0) 62796a888c6Smillert return; 6286fe57b42Smillert 629a4c87e64Skrw /* Bailed out at some point, so undo any changes. */ 630a4c87e64Skrw *pp = origpart; 6316fe57b42Smillert } 6326fe57b42Smillert 6336fe57b42Smillert /* 6346fe57b42Smillert * Delete an existing partition. 6356fe57b42Smillert */ 6366fe57b42Smillert void 6379fdcb4d6Skrw editor_delete(struct disklabel *lp, char **mp, char *p) 6386fe57b42Smillert { 63966df1f0cSkrw struct partition *pp; 640135c90d1Skrw int partno; 6416fe57b42Smillert 6426fe57b42Smillert if (p == NULL) { 643c33fcabaSmillert p = getstring("partition to delete", 644945ae268Smillert "The letter of the partition to delete, a - p, or '*'.", 645945ae268Smillert NULL); 6466fe57b42Smillert } 64796a888c6Smillert if (p == NULL) { 64896a888c6Smillert fputs("Command aborted\n", stderr); 64996a888c6Smillert return; 65096a888c6Smillert } 651945ae268Smillert if (p[0] == '*') { 6529fdcb4d6Skrw zero_partitions(lp); 653945ae268Smillert return; 654945ae268Smillert } 655135c90d1Skrw partno = p[0] - 'a'; 656135c90d1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 6576c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 6586c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 65933262abfSmiod return; 66066df1f0cSkrw } 661135c90d1Skrw pp = &lp->d_partitions[partno]; 66266df1f0cSkrw 66366df1f0cSkrw if (pp->p_fstype == FS_UNUSED && DL_GETPSIZE(pp) == 0) { 66466df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 66533262abfSmiod return; 66666df1f0cSkrw } 66766df1f0cSkrw 6686fe57b42Smillert /* Really delete it (as opposed to just setting to "unused") */ 669135c90d1Skrw memset(pp, 0, sizeof(*pp)); 670135c90d1Skrw 671135c90d1Skrw if (mp != NULL && mp[partno] != NULL) { 672135c90d1Skrw free(mp[partno]); 673135c90d1Skrw mp[partno] = NULL; 674bd6726faSmillert } 6756fe57b42Smillert } 6766fe57b42Smillert 6776fe57b42Smillert /* 6786fe57b42Smillert * Change the size of an existing partition. 6796fe57b42Smillert */ 6806fe57b42Smillert void 6819fdcb4d6Skrw editor_change(struct disklabel *lp, char *p) 6826fe57b42Smillert { 6834b9a3bdaSmillert struct partition *pp; 68466df1f0cSkrw int partno; 6856fe57b42Smillert 6866fe57b42Smillert if (p == NULL) { 687c33fcabaSmillert p = getstring("partition to change size", 6886fe57b42Smillert "The letter of the partition to change size, a - p.", NULL); 6896fe57b42Smillert } 69096a888c6Smillert if (p == NULL) { 69196a888c6Smillert fputs("Command aborted\n", stderr); 69296a888c6Smillert return; 69396a888c6Smillert } 6946fe57b42Smillert partno = p[0] - 'a'; 6956c729bd1Skrw if (partno < 0 || partno == RAW_PART || partno >= lp->d_npartitions) { 6966c729bd1Skrw fprintf(stderr, "Partition must be between 'a' and '%c' " 6976c729bd1Skrw "(excluding 'c').\n", 'a' + lp->d_npartitions - 1); 6986fe57b42Smillert return; 6996fe57b42Smillert } 7004b9a3bdaSmillert pp = &lp->d_partitions[partno]; 7016fe57b42Smillert 70266df1f0cSkrw if (DL_GETPSIZE(pp) == 0) { 70366df1f0cSkrw fprintf(stderr, "Partition '%c' is not in use.\n", p[0]); 70466df1f0cSkrw return; 70566df1f0cSkrw } 70666df1f0cSkrw 70714192793Skrw printf("Partition %c is currently %llu sectors in size, and can have " 70814192793Skrw "a maximum\nsize of %llu sectors.\n", 70914192793Skrw p[0], DL_GETPSIZE(pp), max_partition_size(lp, partno)); 7107da73705Skrw 71159ccf790Skrw /* Get new size */ 7129fdcb4d6Skrw get_size(lp, partno); 7136fe57b42Smillert } 7146fe57b42Smillert 7156fe57b42Smillert /* 7166fe57b42Smillert * Sort the partitions based on starting offset. 7176fe57b42Smillert * This assumes there can be no overlap. 7186fe57b42Smillert */ 7196fe57b42Smillert int 7208809fabbSderaadt partition_cmp(const void *e1, const void *e2) 7216fe57b42Smillert { 7226fe57b42Smillert struct partition *p1 = *(struct partition **)e1; 7236fe57b42Smillert struct partition *p2 = *(struct partition **)e2; 7241e0ad43cSotto u_int64_t o1 = DL_GETPOFFSET(p1); 7251e0ad43cSotto u_int64_t o2 = DL_GETPOFFSET(p2); 7266fe57b42Smillert 7271e0ad43cSotto if (o1 < o2) 728651d5bd9Sotto return -1; 7291e0ad43cSotto else if (o1 > o2) 730651d5bd9Sotto return 1; 731651d5bd9Sotto else 732651d5bd9Sotto return 0; 7336fe57b42Smillert } 7346fe57b42Smillert 7356fe57b42Smillert char * 7368809fabbSderaadt getstring(char *prompt, char *helpstring, char *oval) 7376fe57b42Smillert { 7386fe57b42Smillert static char buf[BUFSIZ]; 7396fe57b42Smillert int n; 7406fe57b42Smillert 7416fe57b42Smillert buf[0] = '\0'; 7426fe57b42Smillert do { 7436fe57b42Smillert printf("%s: [%s] ", prompt, oval ? oval : ""); 7446e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 745260513deSmillert buf[0] = '\0'; 74696a888c6Smillert if (feof(stdin)) { 74724c6582eSmillert clearerr(stdin); 74896a888c6Smillert putchar('\n'); 74996a888c6Smillert return(NULL); 75096a888c6Smillert } 7516e0becc5Smillert } 7526fe57b42Smillert n = strlen(buf); 7536fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 7546fe57b42Smillert buf[--n] = '\0'; 7556fe57b42Smillert if (buf[0] == '?') 7566fe57b42Smillert puts(helpstring); 7574fb6ab7cSmillert else if (oval != NULL && buf[0] == '\0') 7584fb6ab7cSmillert strlcpy(buf, oval, sizeof(buf)); 7596fe57b42Smillert } while (buf[0] == '?'); 7606fe57b42Smillert 7616fe57b42Smillert return(&buf[0]); 7626fe57b42Smillert } 7636fe57b42Smillert 7646fe57b42Smillert /* 7651e0ad43cSotto * Returns ULLONG_MAX on error 76624a2c1a4Smillert * Usually only called by helper functions. 7676fe57b42Smillert */ 7681e0ad43cSotto u_int64_t 7698809fabbSderaadt getuint(struct disklabel *lp, int partno, char *prompt, char *helpstring, 7701e0ad43cSotto u_int64_t oval, u_int64_t maxval, u_int64_t offset, int flags) 7716fe57b42Smillert { 7726fe57b42Smillert char buf[BUFSIZ], *endptr, *p, operator = '\0'; 7731e0ad43cSotto u_int64_t rval = oval; 7746fe57b42Smillert size_t n; 7756fe57b42Smillert int mult = 1; 77614cc915fSmillert double d, percent = 1.0; 7776fe57b42Smillert 7784b9a3bdaSmillert /* We only care about the remainder */ 7794b9a3bdaSmillert offset = offset % lp->d_secpercyl; 7804b9a3bdaSmillert 7816fe57b42Smillert buf[0] = '\0'; 7826fe57b42Smillert do { 7831e0ad43cSotto printf("%s: [%llu] ", prompt, oval); 7846e0becc5Smillert if (fgets(buf, sizeof(buf), stdin) == NULL) { 7856e0becc5Smillert buf[0] = '\0'; 78696a888c6Smillert if (feof(stdin)) { 78724c6582eSmillert clearerr(stdin); 78896a888c6Smillert putchar('\n'); 7891e0ad43cSotto return(ULLONG_MAX - 1); 79096a888c6Smillert } 7916e0becc5Smillert } 7926fe57b42Smillert n = strlen(buf); 7936fe57b42Smillert if (n > 0 && buf[n-1] == '\n') 7946fe57b42Smillert buf[--n] = '\0'; 7956fe57b42Smillert if (buf[0] == '?') 7966fe57b42Smillert puts(helpstring); 7976fe57b42Smillert } while (buf[0] == '?'); 7986fe57b42Smillert 7996fe57b42Smillert if (buf[0] == '*' && buf[1] == '\0') { 8006fe57b42Smillert rval = maxval; 8016fe57b42Smillert } else { 8026fe57b42Smillert /* deal with units */ 8036fe57b42Smillert if (buf[0] != '\0' && n > 0) { 8046fe57b42Smillert if ((flags & DO_CONVERSIONS)) { 80596a888c6Smillert switch (tolower(buf[n-1])) { 8066fe57b42Smillert 8076fe57b42Smillert case 'c': 8086fe57b42Smillert mult = lp->d_secpercyl; 8096fe57b42Smillert buf[--n] = '\0'; 8106fe57b42Smillert break; 8116fe57b42Smillert case 'b': 8126fe57b42Smillert mult = -lp->d_secsize; 8136fe57b42Smillert buf[--n] = '\0'; 8146fe57b42Smillert break; 8156fe57b42Smillert case 'k': 81650c0f47aSkrw if (lp->d_secsize > 1024) 81750c0f47aSkrw mult = -lp->d_secsize / 1024; 81850c0f47aSkrw else 8196fe57b42Smillert mult = 1024 / lp->d_secsize; 8206fe57b42Smillert buf[--n] = '\0'; 8216fe57b42Smillert break; 8226fe57b42Smillert case 'm': 8236fe57b42Smillert mult = 1048576 / lp->d_secsize; 8246fe57b42Smillert buf[--n] = '\0'; 8256fe57b42Smillert break; 8261a51a1eeSmillert case 'g': 8271a51a1eeSmillert mult = 1073741824 / lp->d_secsize; 8281a51a1eeSmillert buf[--n] = '\0'; 8291a51a1eeSmillert break; 83014cc915fSmillert case '%': 83114cc915fSmillert buf[--n] = '\0'; 83214cc915fSmillert percent = strtod(buf, NULL) / 100.0; 8331e0ad43cSotto snprintf(buf, sizeof(buf), "%lld", 8341e0ad43cSotto DL_GETDSIZE(lp)); 83514cc915fSmillert break; 83614cc915fSmillert case '&': 83714cc915fSmillert buf[--n] = '\0'; 83814cc915fSmillert percent = strtod(buf, NULL) / 100.0; 8391e0ad43cSotto snprintf(buf, sizeof(buf), "%lld", 84014cc915fSmillert maxval); 84114cc915fSmillert break; 8426fe57b42Smillert } 84396a888c6Smillert } 8446fe57b42Smillert 8456fe57b42Smillert /* Did they give us an operator? */ 8466fe57b42Smillert p = &buf[0]; 8476fe57b42Smillert if (*p == '+' || *p == '-') 8486fe57b42Smillert operator = *p++; 8496fe57b42Smillert 8506fe57b42Smillert endptr = p; 85196a888c6Smillert errno = 0; 85296a888c6Smillert d = strtod(p, &endptr); 85396a888c6Smillert if (errno == ERANGE) 8541e0ad43cSotto rval = ULLONG_MAX; /* too big/small */ 85596a888c6Smillert else if (*endptr != '\0') { 8566fe57b42Smillert errno = EINVAL; /* non-numbers in str */ 8571e0ad43cSotto rval = ULLONG_MAX; 8586fe57b42Smillert } else { 85996a888c6Smillert /* XXX - should check for overflow */ 86096a888c6Smillert if (mult > 0) 86114cc915fSmillert rval = d * mult * percent; 86296a888c6Smillert else 86396a888c6Smillert /* Negative mult means divide (fancy) */ 86414cc915fSmillert rval = d / (-mult) * percent; 8656fe57b42Smillert 86696a888c6Smillert /* Apply the operator */ 8676fe57b42Smillert if (operator == '+') 8686fe57b42Smillert rval += oval; 8696fe57b42Smillert else if (operator == '-') 8706fe57b42Smillert rval = oval - rval; 8716fe57b42Smillert } 8726fe57b42Smillert } 8736fe57b42Smillert } 8748390cf28Smillert if ((flags & DO_ROUNDING) && rval != ULLONG_MAX) { 87596a888c6Smillert /* Round to nearest cylinder unless given in sectors */ 8768390cf28Smillert if ( 877fc1a4cc6Sderaadt #ifdef SUN_CYLCHECK 878fc1a4cc6Sderaadt ((lp->d_flags & D_VENDOR) || mult != 1) && 879fc1a4cc6Sderaadt #else 8808390cf28Smillert mult != 1 && 881dbffb156Smillert #endif 8828390cf28Smillert (rval + offset) % lp->d_secpercyl != 0) { 8831e0ad43cSotto u_int64_t cyls; 884dbffb156Smillert 8858390cf28Smillert /* Round to higher cylinder but no more than maxval */ 8868390cf28Smillert cyls = (rval / lp->d_secpercyl) + 1; 8878390cf28Smillert if ((cyls * lp->d_secpercyl) - offset > maxval) 888dbffb156Smillert cyls--; 8894b9a3bdaSmillert rval = (cyls * lp->d_secpercyl) - offset; 8908390cf28Smillert printf("Rounding to cylinder: %llu\n", rval); 8916fe57b42Smillert } 8924b9a3bdaSmillert } 8936fe57b42Smillert 8946fe57b42Smillert return(rval); 8956fe57b42Smillert } 8966fe57b42Smillert 8976fe57b42Smillert /* 8981f0f871dSkrw * Check for partition overlap in lp and prompt the user to resolve the overlap 8991f0f871dSkrw * if any is found. Returns 1 if unable to resolve, else 0. 9006fe57b42Smillert */ 9016fe57b42Smillert int 9021f0f871dSkrw has_overlap(struct disklabel *lp) 9036fe57b42Smillert { 9046fe57b42Smillert struct partition **spp; 9056fe57b42Smillert u_int16_t npartitions; 906e6aa8bafSmillert int c, i, j; 907e6aa8bafSmillert char buf[BUFSIZ]; 9086fe57b42Smillert 909a7e61405Smillert /* Get a sorted list of the partitions */ 910a7e61405Smillert spp = sort_partitions(lp, &npartitions); 9116fe57b42Smillert 912*d18c2a43Skrw if (npartitions < RAW_PART) 9136fe57b42Smillert return(0); /* nothing to do */ 9146fe57b42Smillert 9156fe57b42Smillert /* Now that we have things sorted by starting sector check overlap */ 9166fe57b42Smillert for (i = 0; i < npartitions; i++) { 9176fe57b42Smillert for (j = i + 1; j < npartitions; j++) { 9186fe57b42Smillert /* `if last_sec_in_part + 1 > first_sec_in_next_part' */ 9191e0ad43cSotto if (DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]) > DL_GETPOFFSET(spp[j])) { 9206fe57b42Smillert /* Overlap! Convert to real part numbers. */ 9216fe57b42Smillert i = ((char *)spp[i] - (char *)lp->d_partitions) 9226fe57b42Smillert / sizeof(**spp); 9236fe57b42Smillert j = ((char *)spp[j] - (char *)lp->d_partitions) 9246fe57b42Smillert / sizeof(**spp); 9256fe57b42Smillert printf("\nError, partitions %c and %c overlap:\n", 9266fe57b42Smillert 'a' + i, 'a' + j); 927366bf641Skrw printf("# %16.16s %16.16s fstype " 928651d5bd9Sotto "[fsize bsize cpg]\n", "size", "offset"); 929f21a098bSotto display_partition(stdout, lp, NULL, i, 0); 930f21a098bSotto display_partition(stdout, lp, NULL, j, 0); 9316fe57b42Smillert 932e6aa8bafSmillert /* Get partition to disable or ^D */ 933e6aa8bafSmillert do { 934616cd1c4Smillert printf("Disable which one? (^D to abort) [%c %c] ", 9356fe57b42Smillert 'a' + i, 'a' + j); 936e6aa8bafSmillert buf[0] = '\0'; 937616cd1c4Smillert if (!fgets(buf, sizeof(buf), stdin)) { 938616cd1c4Smillert putchar('\n'); 939e6aa8bafSmillert return(1); /* ^D */ 940616cd1c4Smillert } 941e6aa8bafSmillert c = buf[0] - 'a'; 942e6aa8bafSmillert } while (buf[1] != '\n' && buf[1] != '\0' && 943e6aa8bafSmillert c != i && c != j); 944e6aa8bafSmillert 945e6aa8bafSmillert /* Mark the selected one as unused */ 9466fe57b42Smillert lp->d_partitions[c].p_fstype = FS_UNUSED; 9471f0f871dSkrw return (has_overlap(lp)); 9486fe57b42Smillert } 9496fe57b42Smillert } 9506fe57b42Smillert } 951f0b4d0a9Smillert 952e6aa8bafSmillert return(0); 9536fe57b42Smillert } 9546fe57b42Smillert 9556fe57b42Smillert void 9569fdcb4d6Skrw edit_parms(struct disklabel *lp) 9576fe57b42Smillert { 9586fe57b42Smillert char *p; 9599fdcb4d6Skrw u_int64_t freesectors, ui; 96096a888c6Smillert struct disklabel oldlabel = *lp; 9616fe57b42Smillert 962ea37abd3Sderaadt printf("Changing device parameters for %s:\n", specname); 9636fe57b42Smillert 9640f820bbbSmillert /* disk type */ 9650f820bbbSmillert for (;;) { 966c33fcabaSmillert p = getstring("disk type", 96741282a2aSmillert "What kind of disk is this? Usually SCSI, ESDI, ST506, or " 96841282a2aSmillert "floppy (use ESDI for IDE).", dktypenames[lp->d_type]); 96996a888c6Smillert if (p == NULL) { 97096a888c6Smillert fputs("Command aborted\n", stderr); 97196a888c6Smillert return; 97296a888c6Smillert } 97341282a2aSmillert if (strcasecmp(p, "IDE") == 0) 97441282a2aSmillert ui = DTYPE_ESDI; 97541282a2aSmillert else 97641282a2aSmillert for (ui = 1; ui < DKMAXTYPES && 97741282a2aSmillert strcasecmp(p, dktypenames[ui]); ui++) 9780f820bbbSmillert ; 9790f820bbbSmillert if (ui < DKMAXTYPES) { 9800f820bbbSmillert break; 9810f820bbbSmillert } else { 9820f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", p); 9830f820bbbSmillert fputs("Valid types are: ", stdout); 9840f820bbbSmillert for (ui = 1; ui < DKMAXTYPES; ui++) { 9850f820bbbSmillert printf("\"%s\"", dktypenames[ui]); 9860f820bbbSmillert if (ui < DKMAXTYPES - 1) 9870f820bbbSmillert fputs(", ", stdout); 9880f820bbbSmillert } 9890f820bbbSmillert putchar('\n'); 9900f820bbbSmillert } 9910f820bbbSmillert } 9920f820bbbSmillert lp->d_type = ui; 9930f820bbbSmillert 9946fe57b42Smillert /* pack/label id */ 995c33fcabaSmillert p = getstring("label name", 9966fe57b42Smillert "15 char string that describes this label, usually the disk name.", 9976fe57b42Smillert lp->d_packname); 99896a888c6Smillert if (p == NULL) { 99996a888c6Smillert fputs("Command aborted\n", stderr); 100096a888c6Smillert *lp = oldlabel; /* undo damage */ 100196a888c6Smillert return; 100296a888c6Smillert } 10034fb6ab7cSmillert strncpy(lp->d_packname, p, sizeof(lp->d_packname)); /* checked */ 10046fe57b42Smillert 10056fe57b42Smillert /* sectors/track */ 10066fe57b42Smillert for (;;) { 10076fe57b42Smillert ui = getuint(lp, 0, "sectors/track", 10086fe57b42Smillert "The Numer of sectors per track.", lp->d_nsectors, 10094b9a3bdaSmillert lp->d_nsectors, 0, 0); 10101e0ad43cSotto if (ui == ULLONG_MAX - 1) { 101196a888c6Smillert fputs("Command aborted\n", stderr); 101296a888c6Smillert *lp = oldlabel; /* undo damage */ 101396a888c6Smillert return; 10141e0ad43cSotto } if (ui == ULLONG_MAX) 10156fe57b42Smillert fputs("Invalid entry\n", stderr); 10166fe57b42Smillert else 10176fe57b42Smillert break; 10186fe57b42Smillert } 10196fe57b42Smillert lp->d_nsectors = ui; 10206fe57b42Smillert 10216fe57b42Smillert /* tracks/cylinder */ 10226fe57b42Smillert for (;;) { 10236fe57b42Smillert ui = getuint(lp, 0, "tracks/cylinder", 10246fe57b42Smillert "The number of tracks per cylinder.", lp->d_ntracks, 10254b9a3bdaSmillert lp->d_ntracks, 0, 0); 10261e0ad43cSotto if (ui == ULLONG_MAX - 1) { 102796a888c6Smillert fputs("Command aborted\n", stderr); 102896a888c6Smillert *lp = oldlabel; /* undo damage */ 102996a888c6Smillert return; 10301e0ad43cSotto } else if (ui == ULLONG_MAX) 10316fe57b42Smillert fputs("Invalid entry\n", stderr); 10326fe57b42Smillert else 10336fe57b42Smillert break; 10346fe57b42Smillert } 10356fe57b42Smillert lp->d_ntracks = ui; 10366fe57b42Smillert 10376fe57b42Smillert /* sectors/cylinder */ 1038148b6188Smillert for (;;) { 1039148b6188Smillert ui = getuint(lp, 0, "sectors/cylinder", 1040148b6188Smillert "The number of sectors per cylinder (Usually sectors/track " 10414b9a3bdaSmillert "* tracks/cylinder).", lp->d_secpercyl, lp->d_secpercyl, 10424b9a3bdaSmillert 0, 0); 10431e0ad43cSotto if (ui == ULLONG_MAX - 1) { 104496a888c6Smillert fputs("Command aborted\n", stderr); 104596a888c6Smillert *lp = oldlabel; /* undo damage */ 104696a888c6Smillert return; 10471e0ad43cSotto } else if (ui == ULLONG_MAX) 1048148b6188Smillert fputs("Invalid entry\n", stderr); 1049148b6188Smillert else 1050148b6188Smillert break; 1051148b6188Smillert } 1052148b6188Smillert lp->d_secpercyl = ui; 10536fe57b42Smillert 10546fe57b42Smillert /* number of cylinders */ 10556fe57b42Smillert for (;;) { 10566fe57b42Smillert ui = getuint(lp, 0, "number of cylinders", 10576fe57b42Smillert "The total number of cylinders on the disk.", 10584b9a3bdaSmillert lp->d_ncylinders, lp->d_ncylinders, 0, 0); 10591e0ad43cSotto if (ui == ULLONG_MAX - 1) { 106096a888c6Smillert fputs("Command aborted\n", stderr); 106196a888c6Smillert *lp = oldlabel; /* undo damage */ 106296a888c6Smillert return; 10631e0ad43cSotto } else if (ui == ULLONG_MAX) 10646fe57b42Smillert fputs("Invalid entry\n", stderr); 10656fe57b42Smillert else 10666fe57b42Smillert break; 10676fe57b42Smillert } 10686fe57b42Smillert lp->d_ncylinders = ui; 10696fe57b42Smillert 10706fe57b42Smillert /* total sectors */ 10716fe57b42Smillert for (;;) { 107234af67a3Sotto u_int64_t nsec = MAX(DL_GETDSIZE(lp), 107334af67a3Sotto (u_int64_t)lp->d_ncylinders * lp->d_secpercyl); 10746fe57b42Smillert ui = getuint(lp, 0, "total sectors", 10756fe57b42Smillert "The total number of sectors on the disk.", 1076baaa8969Smillert nsec, nsec, 0, 0); 10771e0ad43cSotto if (ui == ULLONG_MAX - 1) { 107896a888c6Smillert fputs("Command aborted\n", stderr); 107996a888c6Smillert *lp = oldlabel; /* undo damage */ 108096a888c6Smillert return; 10811e0ad43cSotto } else if (ui == ULLONG_MAX) 10826fe57b42Smillert fputs("Invalid entry\n", stderr); 10831e0ad43cSotto else if (ui > DL_GETDSIZE(lp) && 10841e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 1085f98aebd4Smillert puts("You may want to increase the size of the 'c' " 1086f98aebd4Smillert "partition."); 10876fe57b42Smillert break; 10881e0ad43cSotto } else if (ui < DL_GETDSIZE(lp) && 10891e0ad43cSotto ending_sector == DL_GETDSIZE(lp)) { 10906fe57b42Smillert /* shrink free count */ 10919fdcb4d6Skrw freesectors = editor_countfree(lp); 10929fdcb4d6Skrw if (DL_GETDSIZE(lp) - ui > freesectors) 10936fe57b42Smillert fprintf(stderr, 10941e0ad43cSotto "Not enough free space to shrink by %llu " 10951e0ad43cSotto "sectors (only %llu sectors left)\n", 10969fdcb4d6Skrw DL_GETDSIZE(lp) - ui, freesectors); 1097c4f83f03Skrw else 10986fe57b42Smillert break; 10996fe57b42Smillert } else 11006fe57b42Smillert break; 11016fe57b42Smillert } 110241ed49b7Smillert /* Adjust ending_sector if necessary. */ 110396a888c6Smillert if (ending_sector > ui) 110496a888c6Smillert ending_sector = ui; 11051e0ad43cSotto DL_SETDSIZE(lp, ui); 11066fe57b42Smillert 11076fe57b42Smillert /* rpm */ 11086fe57b42Smillert for (;;) { 11096fe57b42Smillert ui = getuint(lp, 0, "rpm", 1110a7e61405Smillert "The rotational speed of the disk in revolutions per minute.", 11114b9a3bdaSmillert lp->d_rpm, lp->d_rpm, 0, 0); 11121e0ad43cSotto if (ui == ULLONG_MAX - 1) { 111396a888c6Smillert fputs("Command aborted\n", stderr); 111496a888c6Smillert *lp = oldlabel; /* undo damage */ 111596a888c6Smillert return; 11161e0ad43cSotto } else if (ui == ULLONG_MAX) 11176fe57b42Smillert fputs("Invalid entry\n", stderr); 11186fe57b42Smillert else 11196fe57b42Smillert break; 11206fe57b42Smillert } 11216fe57b42Smillert lp->d_rpm = ui; 1122440b1d70Smillert 1123440b1d70Smillert /* interleave */ 1124440b1d70Smillert for (;;) { 1125440b1d70Smillert ui = getuint(lp, 0, "interleave", 1126440b1d70Smillert "The physical sector interleave, set when formatting. Almost always 1.", 11274b9a3bdaSmillert lp->d_interleave, lp->d_interleave, 0, 0); 11281e0ad43cSotto if (ui == ULLONG_MAX - 1) { 1129440b1d70Smillert fputs("Command aborted\n", stderr); 1130440b1d70Smillert *lp = oldlabel; /* undo damage */ 1131440b1d70Smillert return; 11321e0ad43cSotto } else if (ui == ULLONG_MAX || ui == 0) 1133440b1d70Smillert fputs("Invalid entry\n", stderr); 1134440b1d70Smillert else 1135440b1d70Smillert break; 1136440b1d70Smillert } 1137440b1d70Smillert lp->d_interleave = ui; 11386fe57b42Smillert } 1139a7e61405Smillert 1140a7e61405Smillert struct partition ** 11418809fabbSderaadt sort_partitions(struct disklabel *lp, u_int16_t *npart) 1142a7e61405Smillert { 1143*d18c2a43Skrw static struct partition *spp[MAXPARTITIONS+2]; 1144a7e61405Smillert u_int16_t npartitions; 1145a7e61405Smillert int i; 1146a7e61405Smillert 1147*d18c2a43Skrw memset(spp, 0, sizeof(spp)); 1148*d18c2a43Skrw 1149a7e61405Smillert /* How many "real" partitions do we have? */ 1150a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1151a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1152a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 11531e0ad43cSotto DL_GETPSIZE(&lp->d_partitions[i]) != 0) 1154a7e61405Smillert npartitions++; 1155a7e61405Smillert } 115696a888c6Smillert if (npartitions == 0) { 115796a888c6Smillert *npart = 0; 115896a888c6Smillert return(NULL); 115996a888c6Smillert } 1160a7e61405Smillert 1161a7e61405Smillert for (npartitions = 0, i = 0; i < lp->d_npartitions; i++) { 1162a7e61405Smillert if (lp->d_partitions[i].p_fstype != FS_UNUSED && 1163a7e61405Smillert lp->d_partitions[i].p_fstype != FS_BOOT && 11641e0ad43cSotto DL_GETPSIZE(&lp->d_partitions[i]) != 0) 1165a7e61405Smillert spp[npartitions++] = &lp->d_partitions[i]; 1166a7e61405Smillert } 1167a7e61405Smillert 1168a7e61405Smillert /* 1169a7e61405Smillert * Sort the partitions based on starting offset. 1170a7e61405Smillert * This is safe because we guarantee no overlap. 1171a7e61405Smillert */ 1172a7e61405Smillert if (npartitions > 1) 1173a7e61405Smillert if (heapsort((void *)spp, npartitions, sizeof(spp[0]), 1174a7e61405Smillert partition_cmp)) 1175a7e61405Smillert err(4, "failed to sort partition table"); 1176a7e61405Smillert 1177a7e61405Smillert *npart = npartitions; 1178a7e61405Smillert return(spp); 1179a7e61405Smillert } 11800f820bbbSmillert 11810f820bbbSmillert /* 11820f820bbbSmillert * Get a valid disk type if necessary. 11830f820bbbSmillert */ 11840f820bbbSmillert void 11858809fabbSderaadt getdisktype(struct disklabel *lp, char *banner, char *dev) 11860f820bbbSmillert { 11870f820bbbSmillert int i; 1188803ff7d5Smillert char *s, *def = "SCSI"; 1189803ff7d5Smillert struct dtypes { 1190803ff7d5Smillert char *dev; 1191803ff7d5Smillert char *type; 1192803ff7d5Smillert } dtypes[] = { 1193c33fcabaSmillert { "sd", "SCSI" }, 1194c33fcabaSmillert { "rz", "SCSI" }, 1195c33fcabaSmillert { "wd", "IDE" }, 1196c33fcabaSmillert { "fd", "FLOPPY" }, 1197c33fcabaSmillert { "xd", "SMD" }, 1198c33fcabaSmillert { "xy", "SMD" }, 1199c33fcabaSmillert { "hd", "HP-IB" }, 1200c33fcabaSmillert { "ccd", "CCD" }, 1201c33fcabaSmillert { "vnd", "VND" }, 1202c33fcabaSmillert { "svnd", "VND" }, 1203c33fcabaSmillert { NULL, NULL } 1204803ff7d5Smillert }; 1205803ff7d5Smillert 1206803ff7d5Smillert if ((s = basename(dev)) != NULL) { 1207803ff7d5Smillert if (*s == 'r') 1208803ff7d5Smillert s++; 1209803ff7d5Smillert i = strcspn(s, "0123456789"); 1210803ff7d5Smillert s[i] = '\0'; 1211803ff7d5Smillert dev = s; 1212803ff7d5Smillert for (i = 0; dtypes[i].dev != NULL; i++) { 1213803ff7d5Smillert if (strcmp(dev, dtypes[i].dev) == 0) { 1214803ff7d5Smillert def = dtypes[i].type; 1215803ff7d5Smillert break; 1216803ff7d5Smillert } 1217803ff7d5Smillert } 1218803ff7d5Smillert } 12190f820bbbSmillert 12200f820bbbSmillert if (lp->d_type > DKMAXTYPES || lp->d_type == 0) { 12210f820bbbSmillert puts(banner); 12220f820bbbSmillert puts("Possible values are:"); 1223eb5dd924Sderaadt printf("\"IDE\", "); 12240f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 12250f820bbbSmillert printf("\"%s\"", dktypenames[i]); 12260f820bbbSmillert if (i < DKMAXTYPES - 1) 12270f820bbbSmillert fputs(", ", stdout); 12280f820bbbSmillert } 12290f820bbbSmillert putchar('\n'); 12300f820bbbSmillert 12310f820bbbSmillert for (;;) { 1232c33fcabaSmillert s = getstring("Disk type", 1233803ff7d5Smillert "What kind of disk is this? Usually SCSI, IDE, " 1234803ff7d5Smillert "ESDI, CCD, ST506, or floppy.", def); 123596a888c6Smillert if (s == NULL) 123696a888c6Smillert continue; 12375b412421Smillert if (strcasecmp(s, "IDE") == 0) { 12385b412421Smillert lp->d_type = DTYPE_ESDI; 12395b412421Smillert return; 12405b412421Smillert } 12410f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) 12420f820bbbSmillert if (strcasecmp(s, dktypenames[i]) == 0) { 12430f820bbbSmillert lp->d_type = i; 12440f820bbbSmillert return; 12450f820bbbSmillert } 12460f820bbbSmillert printf("\"%s\" is not a valid disk type.\n", s); 12470f820bbbSmillert fputs("Valid types are: ", stdout); 12480f820bbbSmillert for (i = 1; i < DKMAXTYPES; i++) { 12490f820bbbSmillert printf("\"%s\"", dktypenames[i]); 12500f820bbbSmillert if (i < DKMAXTYPES - 1) 12510f820bbbSmillert fputs(", ", stdout); 12520f820bbbSmillert } 12530f820bbbSmillert putchar('\n'); 12540f820bbbSmillert } 12550f820bbbSmillert } 12560f820bbbSmillert } 125796a888c6Smillert 125896a888c6Smillert /* 125996a888c6Smillert * Get beginning and ending sectors of the OpenBSD portion of the disk 126096a888c6Smillert * from the user. 12614793b14cSmillert * XXX - should mention MBR values if DOSLABEL 126296a888c6Smillert */ 126396a888c6Smillert void 12649fdcb4d6Skrw set_bounds(struct disklabel *lp) 126596a888c6Smillert { 12661e0ad43cSotto u_int64_t ui, start_temp; 126796a888c6Smillert 126896a888c6Smillert /* Starting sector */ 126996a888c6Smillert do { 127096a888c6Smillert ui = getuint(lp, 0, "Starting sector", 127196a888c6Smillert "The start of the OpenBSD portion of the disk.", 12721e0ad43cSotto starting_sector, DL_GETDSIZE(lp), 0, 0); 12731e0ad43cSotto if (ui == ULLONG_MAX - 1) { 127496a888c6Smillert fputs("Command aborted\n", stderr); 127596a888c6Smillert return; 127696a888c6Smillert } 12771e0ad43cSotto } while (ui >= DL_GETDSIZE(lp)); 127896a888c6Smillert start_temp = ui; 127996a888c6Smillert 12804793b14cSmillert /* Size */ 128196a888c6Smillert do { 1282f98aebd4Smillert ui = getuint(lp, 0, "Size ('*' for entire disk)", 1283f98aebd4Smillert "The size of the OpenBSD portion of the disk ('*' for the " 1284f98aebd4Smillert "entire disk).", ending_sector - starting_sector, 12851e0ad43cSotto DL_GETDSIZE(lp) - start_temp, 0, 0); 12861e0ad43cSotto if (ui == ULLONG_MAX - 1) { 128796a888c6Smillert fputs("Command aborted\n", stderr); 128896a888c6Smillert return; 128996a888c6Smillert } 12901e0ad43cSotto } while (ui > DL_GETDSIZE(lp) - start_temp); 12914793b14cSmillert ending_sector = start_temp + ui; 129296a888c6Smillert starting_sector = start_temp; 129396a888c6Smillert } 129496a888c6Smillert 129596a888c6Smillert /* 129696a888c6Smillert * Return a list of the "chunks" of free space available 129796a888c6Smillert */ 129896a888c6Smillert struct diskchunk * 12998809fabbSderaadt free_chunks(struct disklabel *lp) 130096a888c6Smillert { 130196a888c6Smillert u_int16_t npartitions; 130296a888c6Smillert struct partition **spp; 130396a888c6Smillert static struct diskchunk chunks[MAXPARTITIONS + 2]; 130496a888c6Smillert int i, numchunks; 130596a888c6Smillert 130696a888c6Smillert /* Sort the partitions based on offset */ 130796a888c6Smillert spp = sort_partitions(lp, &npartitions); 130896a888c6Smillert 130996a888c6Smillert /* If there are no partitions, it's all free. */ 131096a888c6Smillert if (spp == NULL) { 13112d8451b0Smillert chunks[0].start = starting_sector; 131296a888c6Smillert chunks[0].stop = ending_sector; 131396a888c6Smillert chunks[1].start = chunks[1].stop = 0; 131496a888c6Smillert return(chunks); 131596a888c6Smillert } 131696a888c6Smillert 131796a888c6Smillert /* Find chunks of free space */ 131896a888c6Smillert numchunks = 0; 1319749c5bcaSkrw if (spp && DL_GETPOFFSET(spp[0]) > starting_sector) { 13202d8451b0Smillert chunks[0].start = starting_sector; 13211e0ad43cSotto chunks[0].stop = DL_GETPOFFSET(spp[0]); 132296a888c6Smillert numchunks++; 132396a888c6Smillert } 132496a888c6Smillert for (i = 0; i < npartitions; i++) { 132596a888c6Smillert if (i + 1 < npartitions) { 13261e0ad43cSotto u_int o1 = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]); 13271e0ad43cSotto u_int o2 = DL_GETPOFFSET(spp[i+1]); 13281e0ad43cSotto if (o1 < o2) { 13291e0ad43cSotto chunks[numchunks].start = o1; 13301e0ad43cSotto chunks[numchunks].stop = o2; 133196a888c6Smillert numchunks++; 133296a888c6Smillert } 133396a888c6Smillert } else { 13341e0ad43cSotto u_int o1 = DL_GETPOFFSET(spp[i]) + DL_GETPSIZE(spp[i]); 133596a888c6Smillert /* Last partition */ 13361e0ad43cSotto if (o1 < ending_sector) { 133796a888c6Smillert 13381e0ad43cSotto chunks[numchunks].start = o1; 133965ce672dScsapuntz chunks[numchunks].stop = ending_sector; 134096a888c6Smillert numchunks++; 134196a888c6Smillert } 134296a888c6Smillert } 134396a888c6Smillert } 134496a888c6Smillert 134596a888c6Smillert /* Terminate and return */ 134696a888c6Smillert chunks[numchunks].start = chunks[numchunks].stop = 0; 134796a888c6Smillert return(chunks); 134896a888c6Smillert } 13494793b14cSmillert 13504793b14cSmillert /* 13514793b14cSmillert * What is the OpenBSD portion of the disk? Uses the MBR if applicable. 13524793b14cSmillert */ 13534793b14cSmillert void 135487023ed9Skrw find_bounds(struct disklabel *lp) 13554793b14cSmillert { 1356a4df0321Sderaadt #ifdef DOSLABEL 1357d09f3941Smillert struct partition *pp = &lp->d_partitions[RAW_PART]; 1358a4df0321Sderaadt #endif 13594793b14cSmillert /* Defaults */ 13604793b14cSmillert /* XXX - reserve a cylinder for hp300? */ 13614793b14cSmillert starting_sector = 0; 13621e0ad43cSotto ending_sector = DL_GETDSIZE(lp); 13634793b14cSmillert 13644793b14cSmillert #ifdef DOSLABEL 1365528915f5Smillert /* 136630eb6e87Skrw * If we have an MBR, use values from the OpenBSD partition. 1367528915f5Smillert */ 1368d09f3941Smillert if (dosdp) { 136930eb6e87Skrw if (dosdp->dp_typ == DOSPTYP_OPENBSD) { 1370528915f5Smillert u_int32_t i, new_end; 1371528915f5Smillert 1372d09f3941Smillert /* Set start and end based on fdisk partition bounds */ 137326cb38f1Skrw starting_sector = letoh32(dosdp->dp_start); 137426cb38f1Skrw ending_sector = starting_sector + letoh32(dosdp->dp_size); 1375528915f5Smillert 1376528915f5Smillert /* 1377d09f3941Smillert * If there are any BSD or SWAP partitions beyond 1378d09f3941Smillert * ending_sector we extend ending_sector to include 1379d09f3941Smillert * them. This is done because the BIOS geometry is 1380d09f3941Smillert * generally different from the disk geometry. 1381528915f5Smillert */ 1382528915f5Smillert for (i = new_end = 0; i < lp->d_npartitions; i++) { 1383528915f5Smillert pp = &lp->d_partitions[i]; 1384528915f5Smillert if ((pp->p_fstype == FS_BSDFFS || 1385528915f5Smillert pp->p_fstype == FS_SWAP) && 138634af67a3Sotto DL_GETPSIZE(pp) + DL_GETPOFFSET(pp) > 138734af67a3Sotto new_end) 138834af67a3Sotto new_end = DL_GETPSIZE(pp) + 138934af67a3Sotto DL_GETPOFFSET(pp); 1390528915f5Smillert } 1391528915f5Smillert if (new_end > ending_sector) 1392528915f5Smillert ending_sector = new_end; 1393d09f3941Smillert } else { 1394d09f3941Smillert /* Don't trounce the MBR */ 13959785f718Smillert starting_sector = 63; 1396d09f3941Smillert } 1397d09f3941Smillert 13986893bfe5Sderaadt printf("Treating sectors %llu-%llu as the OpenBSD portion of the " 13996893bfe5Sderaadt "disk.\nYou can use the 'b' command to change this.\n\n", 14004793b14cSmillert starting_sector, ending_sector); 14014793b14cSmillert } 1402d3f02056Smillert #elif (NUMBOOT == 1) 1403d3f02056Smillert /* Boot blocks take up the first cylinder */ 1404d3f02056Smillert starting_sector = lp->d_secpercyl; 14056893bfe5Sderaadt printf("Reserving the first data cylinder for boot blocks.\n" 14066893bfe5Sderaadt "You can use the 'b' command to change this.\n\n"); 14074793b14cSmillert #endif 14084793b14cSmillert } 1409c0bdc608Smillert 1410c0bdc608Smillert /* 1411c0bdc608Smillert * Calculate free space. 1412c0bdc608Smillert */ 14139fdcb4d6Skrw u_int64_t 14149fdcb4d6Skrw editor_countfree(struct disklabel *lp) 1415c0bdc608Smillert { 1416d93cb2bbSkrw struct diskchunk *chunks; 14179fdcb4d6Skrw u_int64_t freesectors = 0; 1418c0bdc608Smillert int i; 1419c0bdc608Smillert 1420d93cb2bbSkrw chunks = free_chunks(lp); 1421509930fbSotto 1422d93cb2bbSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) 14239fdcb4d6Skrw freesectors += chunks[i].stop - chunks[i].start; 14249fdcb4d6Skrw 14259fdcb4d6Skrw return (freesectors); 1426c0bdc608Smillert } 1427617e6e4aSmillert 1428617e6e4aSmillert void 14298809fabbSderaadt editor_help(char *arg) 1430617e6e4aSmillert { 1431617e6e4aSmillert 1432617e6e4aSmillert /* XXX - put these strings in a table instead? */ 1433617e6e4aSmillert switch (*arg) { 1434617e6e4aSmillert case 'p': 1435617e6e4aSmillert puts( 1436617e6e4aSmillert "The 'p' command prints the current disk label. By default, it prints the\n" 1437617e6e4aSmillert "size and offset in sectors (a sector is usually 512 bytes). The 'p' command\n" 1438617e6e4aSmillert "takes an optional units argument. Possible values are 'b' for bytes, 'c'\n" 1439617e6e4aSmillert "for cylinders, 'k' for kilobytes, 'm' for megabytes, and 'g' for gigabytes.\n"); 1440617e6e4aSmillert break; 1441617e6e4aSmillert case 'M': 1442617e6e4aSmillert puts( 14439afbe9eeSmillert "The 'M' command pipes the entire OpenBSD manual page for disk label through\n" 1444508086e9Smillert "the pager specified by the PAGER environment variable or 'less' if PAGER is\n" 1445508086e9Smillert "not set. It is especially useful during install when the normal system\n" 1446508086e9Smillert "manual is not available.\n"); 1447617e6e4aSmillert break; 1448617e6e4aSmillert case 'e': 1449617e6e4aSmillert puts( 1450617e6e4aSmillert "The 'e' command is used to edit the disk drive parameters. These include\n" 1451617e6e4aSmillert "the number of sectors/track, tracks/cylinder, sectors/cylinder, number of\n" 1452617e6e4aSmillert "cylinders on the disk , total sectors on the disk, rpm, interleave, disk\n" 1453617e6e4aSmillert "type, and a descriptive label string. You should not change these unless\n" 1454617e6e4aSmillert "you know what you are doing\n"); 1455617e6e4aSmillert break; 1456617e6e4aSmillert case 'a': 1457617e6e4aSmillert puts( 1458617e6e4aSmillert "The 'a' command adds new partitions to the disk. It takes as an optional\n" 1459617e6e4aSmillert "argument the partition letter to add. If you do not specify a partition\n" 1460617e6e4aSmillert "letter, you will be prompted for it; the next available letter will be the\n" 1461617e6e4aSmillert "default answer\n"); 1462617e6e4aSmillert break; 1463617e6e4aSmillert case 'b': 1464617e6e4aSmillert puts( 1465617e6e4aSmillert "The 'b' command is used to change the boundaries of the OpenBSD portion of\n" 1466617e6e4aSmillert "the disk. This is only useful on disks with an fdisk partition. By default,\n" 1467617e6e4aSmillert "on a disk with an fdisk partition, the boundaries are set to be the first\n" 1468617e6e4aSmillert "and last sectors of the OpenBSD fdisk partition. You should only change\n" 1469617e6e4aSmillert "these if your fdisk partition table is incorrect or you have a disk larger\n" 1470617e6e4aSmillert "than 8gig, since 8gig is the maximum size an fdisk partition can be. You\n" 1471617e6e4aSmillert "may enter '*' at the 'Size' prompt to indicate the entire size of the disk\n" 1472617e6e4aSmillert "(minus the starting sector). Use this option with care; if you extend the\n" 1473617e6e4aSmillert "boundaries such that they overlap with another operating system you will\n" 1474617e6e4aSmillert "corrupt the other operating system's data.\n"); 1475617e6e4aSmillert break; 1476617e6e4aSmillert case 'c': 1477617e6e4aSmillert puts( 1478617e6e4aSmillert "The 'c' command is used to change the size of an existing partition. It\n" 1479617e6e4aSmillert "takes as an optional argument the partition letter to change. If you do not\n" 1480617e6e4aSmillert "specify a partition letter, you will be prompted for one. You may add a '+'\n" 1481617e6e4aSmillert "or '-' prefix to the new size to increase or decrease the existing value\n" 1482617e6e4aSmillert "instead of entering an absolute value. You may also use a suffix to indicate\n" 1483617e6e4aSmillert "the units the values is in terms of. Possible suffixes are 'b' for bytes,\n" 1484617e6e4aSmillert "'c' for cylinders, 'k' for kilobytes, 'm' for megabytes, 'g' for gigabytes or\n" 1485617e6e4aSmillert "no suffix for sectors (usually 512 bytes). You may also enter '*' to change\n" 1486617e6e4aSmillert "the size to be the total number of free sectors remaining.\n"); 1487617e6e4aSmillert break; 14889afbe9eeSmillert case 'D': 14899afbe9eeSmillert puts( 14909afbe9eeSmillert "The 'D' command will set the disk label to the default values as reported\n" 14919afbe9eeSmillert "by the disk itself. This similates the case where there is no disk label.\n"); 14929afbe9eeSmillert break; 1493617e6e4aSmillert case 'd': 1494617e6e4aSmillert puts( 1495617e6e4aSmillert "The 'd' command is used to delete an existing partition. It takes as an\n" 1496617e6e4aSmillert "optional argument the partition letter to change. If you do not specify a\n" 1497617e6e4aSmillert "partition letter, you will be prompted for one. You may not delete the ``c''\n" 1498617e6e4aSmillert "partition as 'c' must always exist and by default is marked as 'unused' (so\n" 1499617e6e4aSmillert "it does not take up any space).\n"); 1500617e6e4aSmillert break; 1501c33fcabaSmillert case 'g': 1502c33fcabaSmillert puts( 150387023ed9Skrw "The 'g' command is used select which disk geometry to use, the disk or a\n" 150487023ed9Skrw "user geometry. It takes as an optional argument ``d'' or ``u''. If \n" 1505c33fcabaSmillert "you do not specify the type as an argument, you will be prompted for it.\n"); 1506c33fcabaSmillert break; 1507617e6e4aSmillert case 'm': 1508617e6e4aSmillert puts( 150987023ed9Skrw "The 'm' command is used to modify an existing partition. It takes as an\n" 151087023ed9Skrw "optional argument the partition letter to change. If you do not specify a\n" 1511617e6e4aSmillert "partition letter, you will be prompted for one. This option allows the user\n" 1512617e6e4aSmillert "to change the filesystem type, starting offset, partition size, block fragment\n" 1513617e6e4aSmillert "size, block size, and cylinders per group for the specified partition (not all\n" 1514617e6e4aSmillert "parameters are configurable for non-BSD partitions).\n"); 1515617e6e4aSmillert break; 1516bd6726faSmillert case 'n': 1517bd6726faSmillert puts( 1518fb932baaSaaron "The 'n' command is used to set the mount point for a partition (ie: name it).\n" 1519bd6726faSmillert "It takes as an optional argument the partition letter to name. If you do\n" 1520bd6726faSmillert "not specify a partition letter, you will be prompted for one. This option\n" 1521bd6726faSmillert "is only valid if disklabel was invoked with the -F flag.\n"); 1522bd6726faSmillert break; 1523617e6e4aSmillert case 'r': 1524617e6e4aSmillert puts( 152525f9c360Skrw "The 'r' command is used to recalculate and display details about\n" 152625f9c360Skrw "the available free space.\n"); 1527617e6e4aSmillert break; 1528617e6e4aSmillert case 'u': 1529617e6e4aSmillert puts( 1530617e6e4aSmillert "The 'u' command will undo (or redo) the last change. Entering 'u' once will\n" 1531617e6e4aSmillert "undo your last change. Entering it again will restore the change.\n"); 1532617e6e4aSmillert break; 1533617e6e4aSmillert case 's': 1534617e6e4aSmillert puts( 1535617e6e4aSmillert "The 's' command is used to save a copy of the label to a file in ascii format\n" 1536617e6e4aSmillert "(suitable for loading via disklabel's [-R] option). It takes as an optional\n" 1537617e6e4aSmillert "argument the filename to save the label to. If you do not specify a filename,\n" 1538617e6e4aSmillert "you will be prompted for one.\n"); 1539617e6e4aSmillert break; 1540617e6e4aSmillert case 'w': 1541617e6e4aSmillert puts( 1542617e6e4aSmillert "The 'w' command will write the current label to disk. This option will\n" 1543617e6e4aSmillert "commit any changes to the on-disk label.\n"); 1544617e6e4aSmillert break; 1545617e6e4aSmillert case 'q': 1546617e6e4aSmillert puts( 1547617e6e4aSmillert "The 'q' command quits the label editor. If any changes have been made you\n" 1548617e6e4aSmillert "will be asked whether or not to save the changes to the on-disk label.\n"); 1549617e6e4aSmillert break; 15509afbe9eeSmillert case 'X': 15519afbe9eeSmillert puts( 15529afbe9eeSmillert "The 'X' command toggles disklabel in to/out of 'expert mode'. By default,\n" 15539afbe9eeSmillert "some settings are reserved for experts only (such as the block and fragment\n" 15549afbe9eeSmillert "size on ffs partitions).\n"); 15559afbe9eeSmillert break; 1556617e6e4aSmillert case 'x': 1557617e6e4aSmillert puts( 1558617e6e4aSmillert "The 'x' command exits the label editor without saving any changes to the\n" 1559617e6e4aSmillert "on-disk label.\n"); 1560617e6e4aSmillert break; 15619afbe9eeSmillert case 'z': 15629afbe9eeSmillert puts( 15639afbe9eeSmillert "The 'z' command zeroes out the existing partition table, leaving only the 'c'\n" 15649afbe9eeSmillert "partition. The drive parameters are not changed.\n"); 15659afbe9eeSmillert break; 1566617e6e4aSmillert default: 1567617e6e4aSmillert puts("Available commands:"); 156852317843Sjmc puts("\t? [cmnd] - this message or command specific help."); 1569617e6e4aSmillert puts("\ta [part] - add new partition."); 1570617e6e4aSmillert puts("\tb - set OpenBSD disk boundaries."); 1571617e6e4aSmillert puts("\tc [part] - change partition size."); 15729afbe9eeSmillert puts("\tD - set label to default."); 157352317843Sjmc puts("\td [part] - delete partition."); 157452317843Sjmc puts("\te - edit drive parameters."); 157587023ed9Skrw puts("\tg [d|u] - use [d]isk or [u]ser geometry."); 157652317843Sjmc puts("\tM - show entire OpenBSD man page for disklabel."); 1577617e6e4aSmillert puts("\tm [part] - modify existing partition."); 1578bd6726faSmillert puts("\tn [part] - set the mount point for a partition."); 157952317843Sjmc puts("\tp [unit] - print label."); 1580617e6e4aSmillert puts("\tq - quit and save changes."); 158125f9c360Skrw puts("\tr - recalculate & display free space details."); 158252317843Sjmc puts("\ts [path] - save label to file."); 158352317843Sjmc puts("\tu - undo last change."); 158452317843Sjmc puts("\tw - write label to disk."); 15852d8451b0Smillert puts("\tX - toggle expert mode."); 158652317843Sjmc puts("\tx - exit without saving changes."); 15879afbe9eeSmillert puts("\tz - zero out partition table."); 1588617e6e4aSmillert puts( 1589617e6e4aSmillert "Numeric parameters may use suffixes to indicate units:\n\t" 1590617e6e4aSmillert "'b' for bytes, 'c' for cylinders, 'k' for kilobytes, 'm' for megabytes,\n\t" 1591617e6e4aSmillert "'g' for gigabytes or no suffix for sectors (usually 512 bytes).\n\t" 159214cc915fSmillert "'%' for percent of total disk size, '&' for percent of free space.\n\t" 1593617e6e4aSmillert "Non-sector units will be rounded to the nearest cylinder.\n" 1594617e6e4aSmillert "Entering '?' at most prompts will give you (simple) context sensitive help."); 1595617e6e4aSmillert break; 1596617e6e4aSmillert } 1597617e6e4aSmillert } 1598bd6726faSmillert 1599bd6726faSmillert char ** 16008809fabbSderaadt mpcopy(char **to, char **from) 1601bd6726faSmillert { 1602bd6726faSmillert int i; 16030612d09dSderaadt char *top; 1604bd6726faSmillert 1605bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1606bd6726faSmillert if (from[i] != NULL) { 1607dcab0d16Sderaadt int len = strlen(from[i]) + 1; 1608dcab0d16Sderaadt 16090612d09dSderaadt top = realloc(to[i], len); 16100612d09dSderaadt if (top == NULL) 1611bd6726faSmillert errx(4, "out of memory"); 16120612d09dSderaadt to[i] = top; 1613dcab0d16Sderaadt (void)strlcpy(to[i], from[i], len); 1614bd6726faSmillert } else if (to[i] != NULL) { 1615bd6726faSmillert free(to[i]); 1616bd6726faSmillert to[i] = NULL; 1617bd6726faSmillert } 1618bd6726faSmillert } 1619bd6726faSmillert return(to); 1620bd6726faSmillert } 1621bd6726faSmillert 1622bd6726faSmillert int 16238809fabbSderaadt mpequal(char **mp1, char **mp2) 1624bd6726faSmillert { 1625bd6726faSmillert int i; 1626bd6726faSmillert 1627bd6726faSmillert for (i = 0; i < MAXPARTITIONS; i++) { 1628bd6726faSmillert if (mp1[i] == NULL && mp2[i] == NULL) 1629bd6726faSmillert continue; 1630bd6726faSmillert 1631bd6726faSmillert if ((mp1[i] != NULL && mp2[i] == NULL) || 1632bd6726faSmillert (mp1[i] == NULL && mp2[i] != NULL) || 1633bd6726faSmillert (strcmp(mp1[i], mp2[i]) != 0)) 1634bd6726faSmillert return(0); 1635bd6726faSmillert } 1636bd6726faSmillert return(1); 1637bd6726faSmillert } 1638bd6726faSmillert 1639bd6726faSmillert int 16408809fabbSderaadt mpsave(struct disklabel *lp, char **mp, char *cdev, char *fstabfile) 1641bd6726faSmillert { 16425fea0b85Smillert int i, j, mpset; 1643bd6726faSmillert char bdev[MAXPATHLEN], *p; 16443f843443Smillert struct mountinfo mi[MAXPARTITIONS]; 1645bd6726faSmillert FILE *fp; 1646bd6726faSmillert 16473f843443Smillert memset(&mi, 0, sizeof(mi)); 16483f843443Smillert 1649bd6726faSmillert for (i = 0, mpset = 0; i < MAXPARTITIONS; i++) { 1650bd6726faSmillert if (mp[i] != NULL) { 16513f843443Smillert mi[i].mountpoint = mp[i]; 16523f843443Smillert mi[i].partno = i; 1653bd6726faSmillert mpset = 1; 1654bd6726faSmillert } 1655bd6726faSmillert } 16563f843443Smillert /* Exit if there is nothing to do... */ 1657bd6726faSmillert if (!mpset) 16583f843443Smillert return(0); 1659bd6726faSmillert 1660bd6726faSmillert /* Convert cdev to bdev */ 1661bd6726faSmillert if (strncmp(_PATH_DEV, cdev, sizeof(_PATH_DEV) - 1) == 0 && 1662bd6726faSmillert cdev[sizeof(_PATH_DEV) - 1] == 'r') { 1663bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", _PATH_DEV, 1664bd6726faSmillert &cdev[sizeof(_PATH_DEV)]); 1665bd6726faSmillert } else { 1666bd6726faSmillert if ((p = strrchr(cdev, '/')) == NULL || *(++p) != 'r') 1667bd6726faSmillert return(1); 1668bd6726faSmillert *p = '\0'; 1669bd6726faSmillert snprintf(bdev, sizeof(bdev), "%s%s", cdev, p + 1); 1670bd6726faSmillert *p = 'r'; 1671bd6726faSmillert } 1672bd6726faSmillert bdev[strlen(bdev) - 1] = '\0'; 1673bd6726faSmillert 16743f843443Smillert /* Sort mountpoints so we don't try to mount /usr/local before /usr */ 16753f843443Smillert qsort((void *)mi, MAXPARTITIONS, sizeof(struct mountinfo), micmp); 16763f843443Smillert 1677bd6726faSmillert if ((fp = fopen(fstabfile, "w")) == NULL) 1678bd6726faSmillert return(1); 1679bd6726faSmillert 16803f843443Smillert for (i = 0; i < MAXPARTITIONS && mi[i].mountpoint != NULL; i++) { 16815fea0b85Smillert j = mi[i].partno; 16825fea0b85Smillert fprintf(fp, "%s%c %s %s rw 1 %d\n", bdev, 'a' + j, 16833f843443Smillert mi[i].mountpoint, 16845fea0b85Smillert fstypesnames[lp->d_partitions[j].p_fstype], 16855fea0b85Smillert j == 0 ? 1 : 2); 1686bd6726faSmillert } 1687bd6726faSmillert fclose(fp); 1688bd6726faSmillert return(0); 1689bd6726faSmillert } 169024a2c1a4Smillert 169124a2c1a4Smillert int 1692604d3bdeSkrw get_offset(struct disklabel *lp, int partno) 169324a2c1a4Smillert { 1694604d3bdeSkrw struct diskchunk *chunks; 169524a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 169615c15d8aSkrw u_int64_t ui, maxsize; 1697604d3bdeSkrw int i, fstype; 169824a2c1a4Smillert 169924a2c1a4Smillert ui = getuint(lp, partno, "offset", 17001e0ad43cSotto "Starting sector for this partition.", 17011e0ad43cSotto DL_GETPOFFSET(pp), 17021e0ad43cSotto DL_GETPOFFSET(pp), 0, DO_CONVERSIONS | 170324a2c1a4Smillert (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0)); 1704e9ff19beSkrw 1705e9ff19beSkrw if (ui == ULLONG_MAX - 1) 170624a2c1a4Smillert fputs("Command aborted\n", stderr); 1707e9ff19beSkrw else if (ui == ULLONG_MAX) 170824a2c1a4Smillert fputs("Invalid entry\n", stderr); 170940e98e9fSkrw else if (ui < starting_sector || ui >= ending_sector) 1710e9ff19beSkrw fprintf(stderr, "The offset must be >= %llu and < %llu, " 1711e9ff19beSkrw "the limits of the OpenBSD portion\n" 1712e9ff19beSkrw "of the disk. The 'b' command can change these limits.\n", 171340e98e9fSkrw starting_sector, ending_sector); 1714fc1a4cc6Sderaadt #ifdef SUN_AAT0 171549bf537cSderaadt else if (partno == 0 && ui != 0) 171649bf537cSderaadt fprintf(stderr, "This architecture requires that " 171740f544cdSderaadt "partition 'a' start at sector 0.\n"); 171849bf537cSderaadt #endif 171915c15d8aSkrw else { 1720604d3bdeSkrw fstype = pp->p_fstype; 1721604d3bdeSkrw pp->p_fstype = FS_UNUSED; 1722604d3bdeSkrw chunks = free_chunks(lp); 1723604d3bdeSkrw pp->p_fstype = fstype; 1724e9ff19beSkrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 1725e9ff19beSkrw if (ui < chunks[i].start || ui >= chunks[i].stop) 172615c15d8aSkrw continue; 17271e0ad43cSotto DL_SETPOFFSET(pp, ui); 172815c15d8aSkrw maxsize = chunks[i].stop - DL_GETPOFFSET(pp); 172915c15d8aSkrw if (DL_GETPSIZE(pp) > maxsize) 173015c15d8aSkrw DL_SETPSIZE(pp, maxsize); 173124a2c1a4Smillert return (0); 173224a2c1a4Smillert } 173315c15d8aSkrw fputs("The offset must be in a free area.\n", stderr); 173415c15d8aSkrw } 1735e9ff19beSkrw 1736e9ff19beSkrw /* Partition offset was not set. */ 1737e9ff19beSkrw return (1); 173815c15d8aSkrw } 173924a2c1a4Smillert 174024a2c1a4Smillert int 17419fdcb4d6Skrw get_size(struct disklabel *lp, int partno) 174224a2c1a4Smillert { 174324a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 174414192793Skrw u_int64_t maxsize, ui; 174514192793Skrw 174614192793Skrw maxsize = max_partition_size(lp, partno); 174724a2c1a4Smillert 17487da73705Skrw ui = getuint(lp, partno, "size", "Size of the partition. " 17497da73705Skrw "You may also say +/- amount for a relative change.", 175014192793Skrw DL_GETPSIZE(pp), maxsize, DL_GETPOFFSET(pp), 1751525051f1Sotto DO_CONVERSIONS | ((pp->p_fstype == FS_BSDFFS || 1752525051f1Sotto pp->p_fstype == FS_SWAP) ? DO_ROUNDING : 0)); 1753e9ff19beSkrw 1754e9ff19beSkrw if (ui == ULLONG_MAX - 1) 175524a2c1a4Smillert fputs("Command aborted\n", stderr); 1756e9ff19beSkrw else if (ui == ULLONG_MAX) 175724a2c1a4Smillert fputs("Invalid entry\n", stderr); 175828e3704eSkrw else if (ui == 0) 175928e3704eSkrw fputs("The size must be > 0\n", stderr); 176040e98e9fSkrw else if (ui + DL_GETPOFFSET(pp) > ending_sector) 176140e98e9fSkrw fprintf(stderr, "The size can't be more than " 176240e98e9fSkrw "%llu sectors, or the partition would\n" 176340e98e9fSkrw "extend beyond the last sector (%llu) of the " 176440e98e9fSkrw "OpenBSD portion of\nthe disk. " 176540e98e9fSkrw "The 'b' command can change this limit.\n", 176640e98e9fSkrw ending_sector - DL_GETPOFFSET(pp), ending_sector); 176714192793Skrw else if (ui > maxsize) 176814192793Skrw fprintf(stderr,"Sorry, there are only %llu sectors left\n", 176914192793Skrw maxsize); 177059ccf790Skrw else { 177159ccf790Skrw DL_SETPSIZE(pp, ui); 177224a2c1a4Smillert return (0); 177324a2c1a4Smillert } 1774e9ff19beSkrw 1775e9ff19beSkrw /* Partition size was not set. */ 1776e9ff19beSkrw return (1); 1777e9ff19beSkrw } 177824a2c1a4Smillert 177924a2c1a4Smillert int 17808809fabbSderaadt get_fsize(struct disklabel *lp, int partno) 178124a2c1a4Smillert { 17821e0ad43cSotto u_int64_t ui, fsize, frag; 178324a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 178424a2c1a4Smillert 1785a4c87e64Skrw if (!expert || pp->p_fstype != FS_BSDFFS) 1786a4c87e64Skrw return (0); 1787a4c87e64Skrw 1788ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 1789ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 1790ddfcbf38Sotto if (fsize == 0) 1791ddfcbf38Sotto frag = 8; 1792ddfcbf38Sotto 179324a2c1a4Smillert for (;;) { 179424a2c1a4Smillert ui = getuint(lp, partno, "fragment size", 17953c92d7f2Stedu "Size of fs block fragments. Usually 2048 or 512.", 1796ddfcbf38Sotto fsize, fsize, 0, 0); 17971e0ad43cSotto if (ui == ULLONG_MAX - 1) { 179824a2c1a4Smillert fputs("Command aborted\n", stderr); 179924a2c1a4Smillert return(1); 18001e0ad43cSotto } else if (ui == ULLONG_MAX) 180124a2c1a4Smillert fputs("Invalid entry\n", stderr); 180224a2c1a4Smillert else 180324a2c1a4Smillert break; 180424a2c1a4Smillert } 180524a2c1a4Smillert if (ui == 0) 180624a2c1a4Smillert puts("Zero fragment size implies zero block size"); 1807ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui, frag); 180824a2c1a4Smillert return(0); 180924a2c1a4Smillert } 181024a2c1a4Smillert 181124a2c1a4Smillert int 18128809fabbSderaadt get_bsize(struct disklabel *lp, int partno) 181324a2c1a4Smillert { 18141e0ad43cSotto u_int64_t ui, bsize, frag, fsize; 181524a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 181624a2c1a4Smillert 1817a4c87e64Skrw if (!expert || pp->p_fstype != FS_BSDFFS) 1818a4c87e64Skrw return (0); 1819a4c87e64Skrw 182024a2c1a4Smillert /* Avoid dividing by zero... */ 1821ddfcbf38Sotto if (pp->p_fragblock == 0) 182224a2c1a4Smillert return(1); 1823ddfcbf38Sotto 1824ddfcbf38Sotto bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock); 1825ddfcbf38Sotto fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 1826ddfcbf38Sotto frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 182724a2c1a4Smillert 182824a2c1a4Smillert for (;;) { 182924a2c1a4Smillert ui = getuint(lp, partno, "block size", 18303c92d7f2Stedu "Size of filesystem blocks. Usually 16384 or 4096.", 1831ddfcbf38Sotto fsize * frag, fsize * frag, 183224a2c1a4Smillert 0, 0); 183324a2c1a4Smillert 183424a2c1a4Smillert /* sanity checks */ 18351e0ad43cSotto if (ui == ULLONG_MAX - 1) { 183624a2c1a4Smillert fputs("Command aborted\n", stderr); 183724a2c1a4Smillert return(1); 18381e0ad43cSotto } else if (ui == ULLONG_MAX) 183924a2c1a4Smillert fputs("Invalid entry\n", stderr); 184024a2c1a4Smillert else if (ui < getpagesize()) 184124a2c1a4Smillert fprintf(stderr, 184224a2c1a4Smillert "Error: block size must be at least as big " 184324a2c1a4Smillert "as page size (%d).\n", getpagesize()); 1844ddfcbf38Sotto else if (ui % fsize != 0) 184524a2c1a4Smillert fputs("Error: block size must be a multiple of the " 184624a2c1a4Smillert "fragment size.\n", stderr); 1847ddfcbf38Sotto else if (ui / fsize < 1) 184824a2c1a4Smillert fputs("Error: block size must be at least as big as " 184924a2c1a4Smillert "fragment size.\n", stderr); 185024a2c1a4Smillert else 185124a2c1a4Smillert break; 185224a2c1a4Smillert } 1853ddfcbf38Sotto pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(ui / frag, frag); 185424a2c1a4Smillert return(0); 185524a2c1a4Smillert } 185624a2c1a4Smillert 185724a2c1a4Smillert int 18588809fabbSderaadt get_fstype(struct disklabel *lp, int partno) 185924a2c1a4Smillert { 186024a2c1a4Smillert char *p; 18611e0ad43cSotto u_int64_t ui; 186224a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 186324a2c1a4Smillert 186424a2c1a4Smillert if (pp->p_fstype < FSMAXTYPES) { 1865c33fcabaSmillert p = getstring("FS type", 186624a2c1a4Smillert "Filesystem type (usually 4.2BSD or swap)", 186724a2c1a4Smillert fstypenames[pp->p_fstype]); 186824a2c1a4Smillert if (p == NULL) { 186924a2c1a4Smillert fputs("Command aborted\n", stderr); 187024a2c1a4Smillert return(1); 187124a2c1a4Smillert } 187224a2c1a4Smillert for (ui = 0; ui < FSMAXTYPES; ui++) { 187324a2c1a4Smillert if (!strcasecmp(p, fstypenames[ui])) { 187424a2c1a4Smillert pp->p_fstype = ui; 187524a2c1a4Smillert break; 187624a2c1a4Smillert } 187724a2c1a4Smillert } 187824a2c1a4Smillert if (ui >= FSMAXTYPES) { 187924a2c1a4Smillert printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p); 188024a2c1a4Smillert pp->p_fstype = FS_OTHER; 188124a2c1a4Smillert } 188224a2c1a4Smillert } else { 188324a2c1a4Smillert for (;;) { 188424a2c1a4Smillert ui = getuint(lp, partno, "FS type (decimal)", 188524a2c1a4Smillert "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).", 188624a2c1a4Smillert pp->p_fstype, pp->p_fstype, 0, 0); 18871e0ad43cSotto if (ui == ULLONG_MAX - 1) { 188824a2c1a4Smillert fputs("Command aborted\n", stderr); 188924a2c1a4Smillert return(1); 18901e0ad43cSotto } if (ui == ULLONG_MAX) 189124a2c1a4Smillert fputs("Invalid entry\n", stderr); 189224a2c1a4Smillert else 189324a2c1a4Smillert break; 189424a2c1a4Smillert } 189524a2c1a4Smillert pp->p_fstype = ui; 189624a2c1a4Smillert } 189724a2c1a4Smillert return(0); 189824a2c1a4Smillert } 189924a2c1a4Smillert 190024a2c1a4Smillert int 19018809fabbSderaadt get_mp(struct disklabel *lp, char **mp, int partno) 190224a2c1a4Smillert { 190324a2c1a4Smillert char *p; 190424a2c1a4Smillert struct partition *pp = &lp->d_partitions[partno]; 190524a2c1a4Smillert 190624a2c1a4Smillert if (mp != NULL && pp->p_fstype != FS_UNUSED && 190724a2c1a4Smillert pp->p_fstype != FS_SWAP && pp->p_fstype != FS_BOOT && 190824a2c1a4Smillert pp->p_fstype != FS_OTHER) { 1909ddaff619Smillert for (;;) { 1910c33fcabaSmillert p = getstring("mount point", 191124a2c1a4Smillert "Where to mount this filesystem (ie: / /var /usr)", 191224a2c1a4Smillert mp[partno] ? mp[partno] : "none"); 191324a2c1a4Smillert if (p == NULL) { 191424a2c1a4Smillert fputs("Command aborted\n", stderr); 191524a2c1a4Smillert return(1); 191624a2c1a4Smillert } 1917ddaff619Smillert if (strcasecmp(p, "none") == 0) { 191824a2c1a4Smillert if (mp[partno] != NULL) { 191924a2c1a4Smillert free(mp[partno]); 192024a2c1a4Smillert mp[partno] = NULL; 192124a2c1a4Smillert } 1922ddaff619Smillert break; 1923ddaff619Smillert } 1924ddaff619Smillert if (*p == '/') { 1925ddaff619Smillert /* XXX - might as well realloc */ 1926ddaff619Smillert if (mp[partno] != NULL) 1927ddaff619Smillert free(mp[partno]); 192824a2c1a4Smillert if ((mp[partno] = strdup(p)) == NULL) 192924a2c1a4Smillert errx(4, "out of memory"); 1930ddaff619Smillert break; 1931ddaff619Smillert } 1932ddaff619Smillert fputs("Mount points must start with '/'\n", stderr); 193324a2c1a4Smillert } 193424a2c1a4Smillert } 193524a2c1a4Smillert return(0); 193624a2c1a4Smillert } 19373f843443Smillert 19383f843443Smillert int 19398809fabbSderaadt micmp(const void *a1, const void *a2) 19403f843443Smillert { 19413f843443Smillert struct mountinfo *mi1 = (struct mountinfo *)a1; 19423f843443Smillert struct mountinfo *mi2 = (struct mountinfo *)a2; 19433f843443Smillert 19443f843443Smillert /* We want all the NULLs at the end... */ 19453f843443Smillert if (mi1->mountpoint == NULL && mi2->mountpoint == NULL) 19463f843443Smillert return(0); 19473f843443Smillert else if (mi1->mountpoint == NULL) 19483f843443Smillert return(1); 19493f843443Smillert else if (mi2->mountpoint == NULL) 19503f843443Smillert return(-1); 19513f843443Smillert else 19523f843443Smillert return(strcmp(mi1->mountpoint, mi2->mountpoint)); 19533f843443Smillert } 1954c33fcabaSmillert 1955c33fcabaSmillert void 195687023ed9Skrw get_geometry(int f, struct disklabel **dgpp) 1957c33fcabaSmillert { 1958c33fcabaSmillert struct stat st; 1959c33fcabaSmillert struct disklabel *disk_geop; 196087023ed9Skrw 1961c33fcabaSmillert if (fstat(f, &st) == -1) 1962c33fcabaSmillert err(4, "Can't stat device"); 1963c33fcabaSmillert 1964c33fcabaSmillert /* Get disk geometry */ 1965c33fcabaSmillert if ((disk_geop = calloc(1, sizeof(struct disklabel))) == NULL) 1966c33fcabaSmillert errx(4, "out of memory"); 1967c33fcabaSmillert if (ioctl(f, DIOCGPDINFO, disk_geop) < 0 && 1968c33fcabaSmillert ioctl(f, DIOCGDINFO, disk_geop) < 0) 1969c33fcabaSmillert err(4, "ioctl DIOCGDINFO"); 1970c33fcabaSmillert *dgpp = disk_geop; 1971c33fcabaSmillert } 1972c33fcabaSmillert 1973c33fcabaSmillert void 19748809fabbSderaadt set_geometry(struct disklabel *lp, struct disklabel *dgp, 197587023ed9Skrw struct disklabel *ugp, char *p) 1976c33fcabaSmillert { 1977c33fcabaSmillert if (p == NULL) { 19789a36aa41Ssthen p = getstring("[d]isk or [u]ser geometry", 1979c33fcabaSmillert "Enter 'd' to use the geometry based on what the disk " 19809a36aa41Ssthen "itself thinks it is, or 'u' to use the geometry that " 19819a36aa41Ssthen "was found in the label.", 1982c33fcabaSmillert "d"); 1983c33fcabaSmillert } 1984c33fcabaSmillert if (p == NULL) { 1985c33fcabaSmillert fputs("Command aborted\n", stderr); 1986c33fcabaSmillert return; 1987c33fcabaSmillert } 1988c33fcabaSmillert switch (*p) { 1989c33fcabaSmillert case 'd': 1990c33fcabaSmillert case 'D': 1991c33fcabaSmillert if (dgp == NULL) 1992c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 1993c33fcabaSmillert else { 1994c33fcabaSmillert lp->d_secsize = dgp->d_secsize; 1995c33fcabaSmillert lp->d_nsectors = dgp->d_nsectors; 1996c33fcabaSmillert lp->d_ntracks = dgp->d_ntracks; 1997c33fcabaSmillert lp->d_ncylinders = dgp->d_ncylinders; 1998c33fcabaSmillert lp->d_secpercyl = dgp->d_secpercyl; 199934af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(dgp)); 2000c33fcabaSmillert } 2001c33fcabaSmillert break; 2002c33fcabaSmillert case 'u': 2003c33fcabaSmillert case 'U': 2004c33fcabaSmillert if (ugp == NULL) 2005c33fcabaSmillert fputs("BIOS geometry not defined.\n", stderr); 2006c33fcabaSmillert else { 2007c33fcabaSmillert lp->d_secsize = ugp->d_secsize; 2008c33fcabaSmillert lp->d_nsectors = ugp->d_nsectors; 2009c33fcabaSmillert lp->d_ntracks = ugp->d_ntracks; 2010c33fcabaSmillert lp->d_ncylinders = ugp->d_ncylinders; 2011c33fcabaSmillert lp->d_secpercyl = ugp->d_secpercyl; 201234af67a3Sotto DL_SETDSIZE(lp, DL_GETDSIZE(ugp)); 2013c33fcabaSmillert if (dgp != NULL && ugp->d_secsize == dgp->d_secsize && 2014c33fcabaSmillert ugp->d_nsectors == dgp->d_nsectors && 2015c33fcabaSmillert ugp->d_ntracks == dgp->d_ntracks && 2016c33fcabaSmillert ugp->d_ncylinders == dgp->d_ncylinders && 2017c33fcabaSmillert ugp->d_secpercyl == dgp->d_secpercyl && 201834af67a3Sotto DL_GETDSIZE(ugp) == DL_GETDSIZE(dgp)) 2019c33fcabaSmillert fputs("Note: user geometry is the same as disk " 2020c33fcabaSmillert "geometry.\n", stderr); 2021c33fcabaSmillert } 2022c33fcabaSmillert break; 2023c33fcabaSmillert default: 20249a36aa41Ssthen fputs("You must enter either 'd' or 'u'.\n", stderr); 2025c33fcabaSmillert break; 2026c33fcabaSmillert } 2027c33fcabaSmillert } 20289afbe9eeSmillert 20299afbe9eeSmillert void 20309fdcb4d6Skrw zero_partitions(struct disklabel *lp) 20319afbe9eeSmillert { 20329afbe9eeSmillert int i; 20339afbe9eeSmillert 20349afbe9eeSmillert for (i = 0; i < MAXPARTITIONS; i++) 20359afbe9eeSmillert memset(&lp->d_partitions[i], 0, sizeof(struct partition)); 203634af67a3Sotto DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); 20379afbe9eeSmillert } 203814192793Skrw 203914192793Skrw u_int64_t 204014192793Skrw max_partition_size(struct disklabel *lp, int partno) 204114192793Skrw { 204214192793Skrw struct partition *pp = &lp->d_partitions[partno]; 204314192793Skrw struct diskchunk *chunks; 204414192793Skrw u_int64_t maxsize, offset; 204514192793Skrw int fstype, i; 204614192793Skrw 204714192793Skrw fstype = pp->p_fstype; 204814192793Skrw pp->p_fstype = FS_UNUSED; 204914192793Skrw chunks = free_chunks(lp); 205014192793Skrw pp->p_fstype = fstype; 205114192793Skrw 205214192793Skrw offset = DL_GETPOFFSET(pp); 205314192793Skrw for (i = 0; chunks[i].start != 0 || chunks[i].stop != 0; i++) { 205414192793Skrw if (offset < chunks[i].start || offset >= chunks[i].stop) 205514192793Skrw continue; 205614192793Skrw maxsize = chunks[i].stop - offset; 205714192793Skrw break; 205814192793Skrw } 205914192793Skrw return (maxsize); 206014192793Skrw } 2061