disks.c revision 50479
1297627Sjmcneill/* 2297627Sjmcneill * The new sysinstall program. 3297627Sjmcneill * 4297627Sjmcneill * This is probably the last program in the `sysinstall' line - the next 5297627Sjmcneill * generation being essentially a complete rewrite. 6297627Sjmcneill * 7297627Sjmcneill * $FreeBSD: head/usr.sbin/sade/disks.c 50479 1999-08-28 01:35:59Z peter $ 8297627Sjmcneill * 9297627Sjmcneill * Copyright (c) 1995 10297627Sjmcneill * Jordan Hubbard. All rights reserved. 11297627Sjmcneill * 12297627Sjmcneill * Redistribution and use in source and binary forms, with or without 13297627Sjmcneill * modification, are permitted provided that the following conditions 14297627Sjmcneill * are met: 15297627Sjmcneill * 1. Redistributions of source code must retain the above copyright 16297627Sjmcneill * notice, this list of conditions and the following disclaimer, 17297627Sjmcneill * verbatim and that no modifications are made prior to this 18297627Sjmcneill * point in the file. 19297627Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright 20297627Sjmcneill * notice, this list of conditions and the following disclaimer in the 21297627Sjmcneill * documentation and/or other materials provided with the distribution. 22297627Sjmcneill * 23297627Sjmcneill * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 24297627Sjmcneill * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25297627Sjmcneill * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26297627Sjmcneill * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 27297627Sjmcneill * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28297627Sjmcneill * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29297627Sjmcneill * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 30297627Sjmcneill * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31297627Sjmcneill * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32297627Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33297627Sjmcneill * SUCH DAMAGE. 34297627Sjmcneill * 35297627Sjmcneill */ 36297627Sjmcneill 37297627Sjmcneill#include "sysinstall.h" 38297627Sjmcneill#include <ctype.h> 39297627Sjmcneill#include <fcntl.h> 40297627Sjmcneill#include <sys/stat.h> 41297627Sjmcneill#include <sys/disklabel.h> 42297627Sjmcneill 43297627Sjmcneill/* Where we start displaying chunk information on the screen */ 44297627Sjmcneill#define CHUNK_START_ROW 5 45297627Sjmcneill 46297627Sjmcneill/* Where we keep track of MBR chunks */ 47297627Sjmcneillstatic struct chunk *chunk_info[16]; 48297627Sjmcneillstatic int current_chunk; 49297627Sjmcneill 50297627Sjmcneillstatic void diskPartitionNonInteractive(Device *dev); 51297627Sjmcneill 52308274Smanustatic void 53305436Smanurecord_chunks(Disk *d) 54297627Sjmcneill{ 55297627Sjmcneill struct chunk *c1 = NULL; 56297627Sjmcneill int i = 0; 57297627Sjmcneill int last_free = 0; 58297627Sjmcneill 59297627Sjmcneill if (!d->chunks) 60297627Sjmcneill msgFatal("No chunk list found for %s!", d->name); 61297627Sjmcneill 62297627Sjmcneill for (c1 = d->chunks->part; c1; c1 = c1->next) { 63297627Sjmcneill if (c1->type == unused && c1->size > last_free) { 64297627Sjmcneill last_free = c1->size; 65297627Sjmcneill current_chunk = i; 66297627Sjmcneill } 67297627Sjmcneill chunk_info[i++] = c1; 68297627Sjmcneill } 69297627Sjmcneill chunk_info[i] = NULL; 70297627Sjmcneill if (current_chunk >= i) 71297627Sjmcneill current_chunk = i - 1; 72297627Sjmcneill} 73297627Sjmcneill 74297627Sjmcneillstatic int Total; 75297627Sjmcneill 76297627Sjmcneillstatic void 77297627Sjmcneillprint_chunks(Disk *d) 78297627Sjmcneill{ 79297627Sjmcneill int row; 80297627Sjmcneill int i; 81297627Sjmcneill 82297627Sjmcneill for (i = Total = 0; chunk_info[i]; i++) 83297627Sjmcneill Total += chunk_info[i]->size; 84297627Sjmcneill if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) { 85297627Sjmcneill dialog_clear_norefresh(); 86297627Sjmcneill msgConfirm("WARNING: A geometry of %d/%d/%d for %s is incorrect. Using\n" 87297627Sjmcneill "a more likely geometry. If this geometry is incorrect or you\n" 88297627Sjmcneill "are unsure as to whether or not it's correct, please consult\n" 89297627Sjmcneill "the Hardware Guide in the Documentation submenu or use the\n" 90297627Sjmcneill "(G)eometry command to change it now.\n\n" 91297627Sjmcneill "Remember: you need to enter whatever your BIOS thinks the\n" 92297627Sjmcneill "geometry is! For IDE, it's what you were told in the BIOS\n" 93297627Sjmcneill "setup. For SCSI, it's the translation mode your controller is\n" 94297627Sjmcneill "using. Do NOT use a ``physical geometry''.", 95297627Sjmcneill d->bios_cyl, d->bios_hd, d->bios_sect, d->name); 96297627Sjmcneill Sanitize_Bios_Geom(d); 97297627Sjmcneill } 98297627Sjmcneill attrset(A_NORMAL); 99297627Sjmcneill mvaddstr(0, 0, "Disk name:\t"); 100297627Sjmcneill clrtobot(); 101297627Sjmcneill attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL); 102297627Sjmcneill attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL); 103297627Sjmcneill mvprintw(1, 0, 104297627Sjmcneill "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %lu sectors", 105297627Sjmcneill d->bios_cyl, d->bios_hd, d->bios_sect, 106305436Smanu d->bios_cyl * d->bios_hd * d->bios_sect); 107305436Smanu mvprintw(3, 0, "%10s %10s %10s %8s %6s %10s %8s %8s", 108305436Smanu "Offset", "Size", "End", "Name", "PType", "Desc", 109305436Smanu "Subtype", "Flags"); 110305436Smanu for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) { 111305436Smanu if (i == current_chunk) 112305436Smanu attrset(ATTR_SELECTED); 113299688Smanu mvprintw(row, 0, "%10ld %10lu %10lu %8s %6d %10s %8d\t%-6s", 114299688Smanu chunk_info[i]->offset, chunk_info[i]->size, 115299688Smanu chunk_info[i]->end, chunk_info[i]->name, 116299688Smanu chunk_info[i]->type, 117299688Smanu slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype), 118299688Smanu chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i])); 119299688Smanu if (i == current_chunk) 120299688Smanu attrset(A_NORMAL); 121299688Smanu } 122297627Sjmcneill} 123297627Sjmcneill 124297627Sjmcneillstatic void 125297627Sjmcneillprint_command_summary() 126297627Sjmcneill{ 127297627Sjmcneill mvprintw(14, 0, "The following commands are supported (in upper or lower case):"); 128297627Sjmcneill mvprintw(16, 0, "A = Use Entire Disk B = Bad Block Scan C = Create Slice"); 129297627Sjmcneill mvprintw(17, 0, "D = Delete Slice G = Set Drive Geometry S = Set Bootable"); 130297627Sjmcneill mvprintw(18, 0, "T = Change Type U = Undo All Changes Q = Finish"); 131297627Sjmcneill if (!RunningAsInit) 132297627Sjmcneill mvprintw(18, 48, "W = Write Changes"); 133297627Sjmcneill mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select."); 134297627Sjmcneill move(0, 0); 135297627Sjmcneill} 136297627Sjmcneill 137297627Sjmcneillstatic u_char * 138297627SjmcneillgetBootMgr(char *dname) 139297627Sjmcneill{ 140297627Sjmcneill#ifndef __alpha__ /* only meaningful on x86 */ 141297627Sjmcneill extern u_char mbr[], boot0[]; 142297627Sjmcneill char str[80]; 143297627Sjmcneill char *cp; 144297627Sjmcneill int i = 0; 145299113Sjmcneill 146299113Sjmcneill cp = variable_get(VAR_BOOTMGR); 147299113Sjmcneill if (!cp) { 148299113Sjmcneill /* Figure out what kind of MBR the user wants */ 149299113Sjmcneill sprintf(str, "Install Boot Manager for drive %s?", dname); 150299113Sjmcneill MenuMBRType.title = str; 151297627Sjmcneill i = dmenuOpenSimple(&MenuMBRType, FALSE); 152297627Sjmcneill } 153297627Sjmcneill else { 154297627Sjmcneill if (!strncmp(cp, "boot", 4)) 155297627Sjmcneill BootMgr = 0; 156297627Sjmcneill else if (!strcmp(cp, "standard")) 157297627Sjmcneill BootMgr = 1; 158297627Sjmcneill else 159297627Sjmcneill BootMgr = 2; 160297627Sjmcneill } 161297627Sjmcneill if (cp || i) { 162297627Sjmcneill switch (BootMgr) { 163297627Sjmcneill case 0: 164297627Sjmcneill return boot0; 165297627Sjmcneill 166297627Sjmcneill case 1: 167297627Sjmcneill return mbr; 168297627Sjmcneill 169297627Sjmcneill case 2: 170297627Sjmcneill default: 171305436Smanu break; 172299688Smanu } 173297627Sjmcneill } 174297627Sjmcneill#endif 175299113Sjmcneill return NULL; 176297627Sjmcneill} 177297627Sjmcneill 178297627Sjmcneillint 179297627SjmcneilldiskGetSelectCount(Device ***devs) 180297627Sjmcneill{ 181297627Sjmcneill int i, cnt, enabled; 182297627Sjmcneill char *cp; 183297627Sjmcneill Device **dp; 184297627Sjmcneill 185297627Sjmcneill cp = variable_get(VAR_DISK); 186297627Sjmcneill dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK); 187297627Sjmcneill cnt = deviceCount(dp); 188297627Sjmcneill if (!cnt) 189297627Sjmcneill return -1; 190297627Sjmcneill for (i = 0, enabled = 0; i < cnt; i++) { 191297627Sjmcneill if (dp[i]->enabled) 192297627Sjmcneill ++enabled; 193297627Sjmcneill } 194297627Sjmcneill return enabled; 195297627Sjmcneill} 196297627Sjmcneill 197297627Sjmcneillvoid 198297627SjmcneilldiskPartition(Device *dev) 199297627Sjmcneill{ 200297627Sjmcneill char *cp, *p; 201297627Sjmcneill int rv, key = 0; 202297627Sjmcneill Boolean chunking; 203297627Sjmcneill char *msg = NULL; 204297627Sjmcneill u_char *mbrContents; 205297627Sjmcneill WINDOW *w = savescr(); 206297627Sjmcneill Disk *d = (Disk *)dev->private; 207297627Sjmcneill 208297627Sjmcneill chunking = TRUE; 209297627Sjmcneill keypad(stdscr, TRUE); 210297627Sjmcneill 211297627Sjmcneill /* Flush both the dialog and curses library views of the screen 212297627Sjmcneill since we don't always know who called us */ 213297627Sjmcneill dialog_clear_norefresh(), clear(); 214297627Sjmcneill current_chunk = 0; 215297627Sjmcneill 216297627Sjmcneill /* Set up the chunk array */ 217297627Sjmcneill record_chunks(d); 218297627Sjmcneill 219297627Sjmcneill while (chunking) { 220297627Sjmcneill char *val, geometry[80]; 221297627Sjmcneill 222297627Sjmcneill /* Now print our overall state */ 223297627Sjmcneill if (d) 224297627Sjmcneill print_chunks(d); 225297627Sjmcneill print_command_summary(); 226297627Sjmcneill if (msg) { 227297627Sjmcneill attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 228297627Sjmcneill beep(); 229297627Sjmcneill msg = NULL; 230297627Sjmcneill } 231297627Sjmcneill else { 232297627Sjmcneill move(23, 0); 233297627Sjmcneill clrtoeol(); 234297627Sjmcneill } 235297627Sjmcneill 236297627Sjmcneill /* Get command character */ 237297627Sjmcneill key = getch(); 238297627Sjmcneill switch (toupper(key)) { 239297627Sjmcneill case '\014': /* ^L (redraw) */ 240297627Sjmcneill clear(); 241297627Sjmcneill msg = NULL; 242297627Sjmcneill break; 243297627Sjmcneill 244297627Sjmcneill case '\020': /* ^P */ 245297627Sjmcneill case KEY_UP: 246297627Sjmcneill case '-': 247297627Sjmcneill if (current_chunk != 0) 248297627Sjmcneill --current_chunk; 249297627Sjmcneill break; 250297627Sjmcneill 251297627Sjmcneill case '\016': /* ^N */ 252297627Sjmcneill case KEY_DOWN: 253297627Sjmcneill case '+': 254297627Sjmcneill case '\r': 255297627Sjmcneill case '\n': 256297627Sjmcneill if (chunk_info[current_chunk + 1]) 257297627Sjmcneill ++current_chunk; 258297627Sjmcneill break; 259297627Sjmcneill 260297627Sjmcneill case KEY_HOME: 261297627Sjmcneill current_chunk = 0; 262297627Sjmcneill break; 263297627Sjmcneill 264297627Sjmcneill case KEY_END: 265297627Sjmcneill while (chunk_info[current_chunk + 1]) 266297627Sjmcneill ++current_chunk; 267297627Sjmcneill break; 268297627Sjmcneill 269297627Sjmcneill case KEY_F(1): 270297627Sjmcneill case '?': 271297627Sjmcneill systemDisplayHelp("slice"); 272297627Sjmcneill clear(); 273297627Sjmcneill break; 274297627Sjmcneill 275297627Sjmcneill case 'A': 276297627Sjmcneill#ifdef __alpha__ 277297627Sjmcneill rv = 1; 278297627Sjmcneill#else /* The rest is only relevant on x86 */ 279297627Sjmcneill cp = variable_get(VAR_DEDICATE_DISK); 280297627Sjmcneill if (cp && !strcasecmp(cp, "always")) 281297627Sjmcneill rv = 1; 282297627Sjmcneill else { 283297627Sjmcneill rv = msgYesNo("Do you want to do this with a true partition entry\n" 284297627Sjmcneill "so as to remain cooperative with any future possible\n" 285297627Sjmcneill "operating systems on the drive(s)?\n" 286297627Sjmcneill "(See also the section about ``dangerously dedicated''\n" 287297627Sjmcneill "disks in the FreeBSD FAQ.)"); 288297627Sjmcneill if (rv == -1) 289297627Sjmcneill rv = 0; 290297627Sjmcneill } 291297627Sjmcneill#endif 292297627Sjmcneill All_FreeBSD(d, rv); 293297627Sjmcneill variable_set2(DISK_PARTITIONED, "yes", 0); 294297627Sjmcneill record_chunks(d); 295297627Sjmcneill clear(); 296297627Sjmcneill break; 297297627Sjmcneill 298297627Sjmcneill case 'B': 299297627Sjmcneill if (chunk_info[current_chunk]->type != freebsd) 300297627Sjmcneill msg = "Can only scan for bad blocks in FreeBSD slice."; 301297627Sjmcneill else if (strncmp(d->name, "sd", 2) || 302297627Sjmcneill strncmp(d->name, "da", 2) || 303297627Sjmcneill !msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\n" 304297627Sjmcneill "Are you sure you want to do this on a SCSI disk?")) { 305297627Sjmcneill if (chunk_info[current_chunk]->flags & CHUNK_BAD144) 306297627Sjmcneill chunk_info[current_chunk]->flags &= ~CHUNK_BAD144; 307297627Sjmcneill else 308297627Sjmcneill chunk_info[current_chunk]->flags |= CHUNK_BAD144; 309297627Sjmcneill } 310297627Sjmcneill clear(); 311297627Sjmcneill break; 312297627Sjmcneill 313297627Sjmcneill case 'C': 314297627Sjmcneill if (chunk_info[current_chunk]->type != unused) 315297627Sjmcneill msg = "Slice in use, delete it first or move to an unused one."; 316297627Sjmcneill else { 317297627Sjmcneill char *val, tmp[20], *cp; 318297627Sjmcneill int size, subtype; 319297627Sjmcneill chunk_e partitiontype; 320297627Sjmcneill 321297627Sjmcneill snprintf(tmp, 20, "%lu", chunk_info[current_chunk]->size); 322297627Sjmcneill val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" 323297627Sjmcneill "or append a trailing `M' for megabytes (e.g. 20M)."); 324297627Sjmcneill if (val && (size = strtol(val, &cp, 0)) > 0) { 325297627Sjmcneill if (*cp && toupper(*cp) == 'M') 326297627Sjmcneill size *= ONE_MEG; 327297627Sjmcneill strcpy(tmp, "165"); 328297627Sjmcneill val = msgGetInput(tmp, "Enter type of partition to create:\n\n" 329297627Sjmcneill "Pressing Enter will choose the default, a native FreeBSD\n" 330297627Sjmcneill "slice (type 165). You can choose other types, 6 for a\n" 331297627Sjmcneill "DOS partition or 131 for a Linux partition, for example.\n\n" 332297627Sjmcneill "Note: If you choose a non-FreeBSD partition type, it will not\n" 333297627Sjmcneill "be formatted or otherwise prepared, it will simply reserve space\n" 334297627Sjmcneill "for you to use another tool, such as DOS FORMAT, to later format\n" 335297627Sjmcneill "and use the partition."); 336297627Sjmcneill if (val && (subtype = strtol(val, NULL, 0)) > 0) { 337297627Sjmcneill if (subtype == 165) 338297627Sjmcneill partitiontype = freebsd; 339297627Sjmcneill else if (subtype == 6) 340297627Sjmcneill partitiontype = fat; 341297627Sjmcneill else 342297627Sjmcneill partitiontype = unknown; 343297627Sjmcneill#ifdef __alpha__ 344297627Sjmcneill if (partitiontype == freebsd && size == chunk_info[current_chunk]->size) 345297627Sjmcneill All_FreeBSD(d, 1); 346297627Sjmcneill else 347297627Sjmcneill#endif 348297627Sjmcneill Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, 349297627Sjmcneill (chunk_info[current_chunk]->flags & CHUNK_ALIGN)); 350297627Sjmcneill variable_set2(DISK_PARTITIONED, "yes", 0); 351297627Sjmcneill record_chunks(d); 352297627Sjmcneill } 353297627Sjmcneill } 354297627Sjmcneill clear(); 355297627Sjmcneill } 356297627Sjmcneill break; 357297627Sjmcneill 358297627Sjmcneill case KEY_DC: 359297627Sjmcneill case 'D': 360297627Sjmcneill if (chunk_info[current_chunk]->type == unused) 361297627Sjmcneill msg = "Slice is already unused!"; 362297627Sjmcneill else { 363297627Sjmcneill Delete_Chunk(d, chunk_info[current_chunk]); 364297627Sjmcneill variable_set2(DISK_PARTITIONED, "yes", 0); 365297627Sjmcneill record_chunks(d); 366297627Sjmcneill } 367297627Sjmcneill break; 368297627Sjmcneill 369297627Sjmcneill case 'T': 370297627Sjmcneill if (chunk_info[current_chunk]->type == unused) 371297627Sjmcneill msg = "Slice is currently unused (use create instead)"; 372297627Sjmcneill else { 373297627Sjmcneill char *val, tmp[20]; 374297627Sjmcneill int subtype; 375297627Sjmcneill chunk_e partitiontype; 376297627Sjmcneill WINDOW *save = savescr(); 377297627Sjmcneill 378297627Sjmcneill strcpy(tmp, "165"); 379297627Sjmcneill val = msgGetInput(tmp, "New partition type:\n\n" 380297627Sjmcneill "Pressing Enter will choose the default, a native FreeBSD\n" 381297627Sjmcneill "slice (type 165). Other popular values are 6 for\n" 382297627Sjmcneill "DOS FAT partition, 131 for a Linux ext2fs partition or\n" 383297627Sjmcneill "130 for a Linux swap partition.\n\n" 384297627Sjmcneill "Note: If you choose a non-FreeBSD partition type, it will not\n" 385297627Sjmcneill "be formatted or otherwise prepared, it will simply reserve space\n" 386297627Sjmcneill "for you to use another tool, such as DOS format, to later format\n" 387297627Sjmcneill "and actually use the partition."); 388297627Sjmcneill if (val && (subtype = strtol(val, NULL, 0)) > 0) { 389297627Sjmcneill if (subtype == 165) 390297627Sjmcneill partitiontype = freebsd; 391297627Sjmcneill else if (subtype == 6) 392297627Sjmcneill partitiontype = fat; 393297627Sjmcneill else 394297627Sjmcneill partitiontype = unknown; 395297627Sjmcneill chunk_info[current_chunk]->type = partitiontype; 396297627Sjmcneill chunk_info[current_chunk]->subtype = subtype; 397297627Sjmcneill } 398297627Sjmcneill restorescr(save); 399297627Sjmcneill } 400297627Sjmcneill break; 401297627Sjmcneill 402297627Sjmcneill case 'G': 403297627Sjmcneill snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); 404297627Sjmcneill val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" 405297627Sjmcneill "Don't forget to use the two slash (/) separator characters!\n" 406297627Sjmcneill "It's not possible to parse the field without them."); 407297627Sjmcneill if (val) { 408297627Sjmcneill long nc, nh, ns; 409297627Sjmcneill nc = strtol(val, &val, 0); 410297627Sjmcneill nh = strtol(val + 1, &val, 0); 411297627Sjmcneill ns = strtol(val + 1, 0, 0); 412297627Sjmcneill Set_Bios_Geom(d, nc, nh, ns); 413297627Sjmcneill } 414297627Sjmcneill clear(); 415297627Sjmcneill break; 416297627Sjmcneill 417297627Sjmcneill case 'S': 418297627Sjmcneill /* Set Bootable */ 419297627Sjmcneill chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; 420297627Sjmcneill break; 421297627Sjmcneill 422297627Sjmcneill case 'U': 423297627Sjmcneill if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 424297627Sjmcneill msgConfirm("You've already written this information out - you\n" 425297627Sjmcneill "can't undo it."); 426297627Sjmcneill } 427297627Sjmcneill else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 428297627Sjmcneill char cp[BUFSIZ]; 429297627Sjmcneill 430297627Sjmcneill sstrncpy(cp, d->name, sizeof cp); 431297627Sjmcneill Free_Disk(dev->private); 432297627Sjmcneill d = Open_Disk(cp); 433297627Sjmcneill if (!d) 434297627Sjmcneill msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); 435297627Sjmcneill dev->private = d; 436297627Sjmcneill variable_unset(DISK_PARTITIONED); 437297627Sjmcneill variable_unset(DISK_LABELLED); 438297627Sjmcneill if (d) 439297627Sjmcneill record_chunks(d); 440297627Sjmcneill } 441297627Sjmcneill clear(); 442297627Sjmcneill break; 443297627Sjmcneill 444297627Sjmcneill case 'W': 445297627Sjmcneill if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 446297627Sjmcneill "installation. If you are installing FreeBSD for the first time\n" 447297627Sjmcneill "then you should simply type Q when you're finished here and your\n" 448297627Sjmcneill "changes will be committed in one batch automatically at the end of\n" 449297627Sjmcneill "these questions. If you're adding a disk, you should NOT write\n" 450297627Sjmcneill "from this screen, you should do it from the label editor.\n\n" 451297627Sjmcneill "Are you absolutely sure you want to do this now?")) { 452297627Sjmcneill variable_set2(DISK_PARTITIONED, "yes", 0); 453297627Sjmcneill 454297627Sjmcneill /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated 455297627Sjmcneill * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested 456297627Sjmcneill * booteasy or a "standard" MBR -- both would be fatal in this case. 457297627Sjmcneill */ 458297627Sjmcneill#if 0 459297627Sjmcneill if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL 460297627Sjmcneill && (mbrContents = getBootMgr(d->name)) != NULL) 461297627Sjmcneill Set_Boot_Mgr(d, mbrContents); 462297627Sjmcneill#else 463297627Sjmcneill /* 464297627Sjmcneill * Don't offer to update the MBR on this disk if the first "real" chunk looks like 465297627Sjmcneill * a FreeBSD "all disk" partition, or the disk is entirely FreeBSD. 466297627Sjmcneill */ 467297627Sjmcneill if (((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) && 468297627Sjmcneill (mbrContents = getBootMgr(d->name)) != NULL) 469297627Sjmcneill Set_Boot_Mgr(d, mbrContents); 470297627Sjmcneill#endif 471297627Sjmcneill 472297627Sjmcneill if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) 473297627Sjmcneill msgConfirm("Disk partition write returned an error status!"); 474297627Sjmcneill else 475305436Smanu msgConfirm("Wrote FDISK partition information out successfully."); 476305436Smanu } 477305436Smanu clear(); 478305436Smanu break; 479305436Smanu 480305436Smanu case '|': 481305436Smanu if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n" 482305436Smanu "No seat belts whatsoever are provided!")) { 483305436Smanu clear(); 484305436Smanu refresh(); 485305436Smanu slice_wizard(d); 486305436Smanu variable_set2(DISK_PARTITIONED, "yes", 0); 487305436Smanu record_chunks(d); 488305436Smanu } 489305436Smanu else 490305436Smanu msg = "Wise choice!"; 491305436Smanu clear(); 492305436Smanu break; 493305436Smanu 494305436Smanu case '\033': /* ESC */ 495305436Smanu case 'Q': 496305436Smanu chunking = FALSE; 497305436Smanu /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated 498305436Smanu * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested 499305436Smanu * booteasy or a "standard" MBR -- both would be fatal in this case. 500305436Smanu */ 501305436Smanu#if 0 502305436Smanu if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL 503305436Smanu && (mbrContents = getBootMgr(d->name)) != NULL) 504305436Smanu Set_Boot_Mgr(d, mbrContents); 505305436Smanu#else 506305436Smanu /* 507305436Smanu * Don't offer to update the MBR on this disk if the first "real" chunk looks like 508305436Smanu * a FreeBSD "all disk" partition, or the disk is entirely FreeBSD. 509305436Smanu */ 510305436Smanu if (((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) && 511305436Smanu (mbrContents = getBootMgr(d->name)) != NULL) 512305436Smanu Set_Boot_Mgr(d, mbrContents); 513305436Smanu#endif 514305436Smanu break; 515305436Smanu 516305436Smanu default: 517305436Smanu beep(); 518305436Smanu msg = "Type F1 or ? for help"; 519305436Smanu break; 520305436Smanu } 521305436Smanu } 522305436Smanu p = CheckRules(d); 523305436Smanu if (p) { 524305436Smanu char buf[FILENAME_MAX]; 525305436Smanu 526305436Smanu dialog_clear_norefresh(); 527305436Smanu use_helpline("Press F1 to read more about disk slices."); 528305436Smanu use_helpfile(systemHelpFile("partition", buf)); 529305436Smanu if (!variable_get(VAR_NO_WARN)) 530305436Smanu dialog_mesgbox("Disk slicing warning:", p, -1, -1); 531305436Smanu free(p); 532305436Smanu } 533305436Smanu restorescr(w); 534305436Smanu} 535305436Smanu 536305436Smanustatic u_char * 537305436Smanubootalloc(char *name) 538305436Smanu{ 539305436Smanu char buf[FILENAME_MAX]; 540305436Smanu struct stat sb; 541305436Smanu 542305436Smanu snprintf(buf, sizeof buf, "/boot/%s", name); 543305436Smanu if (stat(buf, &sb) != -1) { 544305436Smanu int fd; 545305436Smanu 546305436Smanu fd = open(buf, O_RDONLY); 547305436Smanu if (fd != -1) { 548305436Smanu u_char *cp; 549305436Smanu 550299688Smanu cp = malloc(sb.st_size); 551299688Smanu if (read(fd, cp, sb.st_size) != sb.st_size) { 552299688Smanu free(cp); 553299688Smanu close(fd); 554299688Smanu msgDebug("bootalloc: couldn't read %d bytes from %s\n", sb.st_size, buf); 555299688Smanu return NULL; 556299688Smanu } 557299688Smanu close(fd); 558299688Smanu return cp; 559299688Smanu } 560299688Smanu msgDebug("bootalloc: couldn't open %s\n", buf); 561299688Smanu } 562299688Smanu else 563299688Smanu msgDebug("bootalloc: can't stat %s\n", buf); 564299688Smanu return NULL; 565299688Smanu} 566299688Smanu 567299688Smanustatic int 568299688SmanupartitionHook(dialogMenuItem *selected) 569297627Sjmcneill{ 570297627Sjmcneill Device **devs = NULL; 571297627Sjmcneill 572297627Sjmcneill devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 573297627Sjmcneill if (!devs) { 574297627Sjmcneill msgConfirm("Unable to find disk %s!", selected->prompt); 575297627Sjmcneill return DITEM_FAILURE; 576297627Sjmcneill } 577297627Sjmcneill /* Toggle enabled status? */ 578297627Sjmcneill if (!devs[0]->enabled) { 579297627Sjmcneill devs[0]->enabled = TRUE; 580297627Sjmcneill diskPartition(devs[0]); 581297627Sjmcneill } 582297627Sjmcneill else 583297627Sjmcneill devs[0]->enabled = FALSE; 584297627Sjmcneill return DITEM_SUCCESS | DITEM_RESTORE; 585297627Sjmcneill} 586297627Sjmcneill 587297627Sjmcneillstatic int 588297627SjmcneillpartitionCheck(dialogMenuItem *selected) 589297627Sjmcneill{ 590297627Sjmcneill Device **devs = NULL; 591297627Sjmcneill 592297627Sjmcneill devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 593297627Sjmcneill if (!devs || devs[0]->enabled == FALSE) 594297627Sjmcneill return FALSE; 595297627Sjmcneill return TRUE; 596297627Sjmcneill} 597297627Sjmcneill 598297627Sjmcneillint 599297627SjmcneilldiskPartitionEditor(dialogMenuItem *self) 600297627Sjmcneill{ 601297627Sjmcneill DMenu *menu; 602297627Sjmcneill Device **devs; 603297627Sjmcneill int i, cnt, devcnt; 604297627Sjmcneill 605297627Sjmcneill cnt = diskGetSelectCount(&devs); 606297627Sjmcneill devcnt = deviceCount(devs); 607297627Sjmcneill if (cnt == -1) { 608297627Sjmcneill msgConfirm("No disks found! Please verify that your disk controller is being\n" 609297627Sjmcneill "properly probed at boot time. See the Hardware Guide on the\n" 610297627Sjmcneill "Documentation menu for clues on diagnosing this type of problem."); 611297627Sjmcneill return DITEM_FAILURE; 612297627Sjmcneill } 613297627Sjmcneill else if (cnt) { 614297627Sjmcneill /* Some are already selected */ 615297627Sjmcneill for (i = 0; i < devcnt; i++) { 616297627Sjmcneill if (devs[i]->enabled) { 617297627Sjmcneill if (variable_get(VAR_NONINTERACTIVE)) 618297627Sjmcneill diskPartitionNonInteractive(devs[i]); 619297627Sjmcneill else 620297627Sjmcneill diskPartition(devs[i]); 621297627Sjmcneill } 622297627Sjmcneill } 623297627Sjmcneill } 624297627Sjmcneill else { 625297627Sjmcneill /* No disks are selected, fall-back case now */ 626297627Sjmcneill if (devcnt == 1) { 627297627Sjmcneill devs[0]->enabled = TRUE; 628297627Sjmcneill if (variable_get(VAR_NONINTERACTIVE)) 629297627Sjmcneill diskPartitionNonInteractive(devs[0]); 630297627Sjmcneill else 631297627Sjmcneill diskPartition(devs[0]); 632297627Sjmcneill return DITEM_SUCCESS; 633297627Sjmcneill } 634297627Sjmcneill else { 635297627Sjmcneill menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); 636297627Sjmcneill if (!menu) { 637297627Sjmcneill msgConfirm("No devices suitable for installation found!\n\n" 638297627Sjmcneill "Please verify that your disk controller (and attached drives)\n" 639297627Sjmcneill "were detected properly. This can be done by pressing the\n" 640297627Sjmcneill "[Scroll Lock] key and using the Arrow keys to move back to\n" 641297627Sjmcneill "the boot messages. Press [Scroll Lock] again to return."); 642297627Sjmcneill return DITEM_FAILURE; 643297627Sjmcneill } 644297627Sjmcneill else { 645297627Sjmcneill i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 646297627Sjmcneill free(menu); 647297627Sjmcneill } 648299113Sjmcneill return i | DITEM_RESTORE; 649299113Sjmcneill } 650299113Sjmcneill } 651299113Sjmcneill return DITEM_SUCCESS; 652299113Sjmcneill} 653299113Sjmcneill 654299113Sjmcneillint 655299113SjmcneilldiskPartitionWrite(dialogMenuItem *self) 656299113Sjmcneill{ 657299113Sjmcneill Device **devs; 658299113Sjmcneill int i; 659299113Sjmcneill char *cp; 660299113Sjmcneill 661299113Sjmcneill devs = deviceFind(NULL, DEVICE_TYPE_DISK); 662299113Sjmcneill if (!devs) { 663299113Sjmcneill msgConfirm("Unable to find any disks to write to??"); 664299113Sjmcneill return DITEM_FAILURE; 665299113Sjmcneill } 666297627Sjmcneill if (isDebug()) 667297627Sjmcneill msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); 668297627Sjmcneill cp = variable_get(DISK_PARTITIONED); 669297627Sjmcneill if (cp && !strcmp(cp, "written")) 670297627Sjmcneill return DITEM_SUCCESS; 671297627Sjmcneill 672297627Sjmcneill for (i = 0; devs[i]; i++) { 673297627Sjmcneill Chunk *c1; 674297627Sjmcneill Disk *d = (Disk *)devs[i]->private; 675297627Sjmcneill static u_char *boot1; 676297627Sjmcneill#ifndef __alpha__ 677297627Sjmcneill static u_char *boot2; 678297627Sjmcneill#endif 679305436Smanu 680299688Smanu if (!devs[i]->enabled) 681297627Sjmcneill continue; 682297627Sjmcneill 683299113Sjmcneill#ifdef __alpha__ 684297627Sjmcneill if (!boot1) boot1 = bootalloc("boot1"); 685297627Sjmcneill Set_Boot_Blocks(d, boot1, NULL); 686297627Sjmcneill#else 687297627Sjmcneill if (!boot1) boot1 = bootalloc("boot1"); 688297627Sjmcneill if (!boot2) boot2 = bootalloc("boot2"); 689297627Sjmcneill Set_Boot_Blocks(d, boot1, boot2); 690297627Sjmcneill#endif 691297627Sjmcneill 692305436Smanu msgNotify("Writing partition information to drive %s", d->name); 693297627Sjmcneill if (!Fake && Write_Disk(d)) { 694297627Sjmcneill msgConfirm("ERROR: Unable to write data to disk %s!", d->name); 695299688Smanu return DITEM_FAILURE; 696299113Sjmcneill } 697297627Sjmcneill 698297627Sjmcneill /* If we've been through here before, we don't need to do the rest */ 699297627Sjmcneill if (cp && !strcmp(cp, "written")) 700297627Sjmcneill return DITEM_SUCCESS; 701297627Sjmcneill 702297627Sjmcneill /* Now scan for bad blocks, if necessary */ 703297627Sjmcneill for (c1 = d->chunks->part; c1; c1 = c1->next) { 704297627Sjmcneill if (c1->flags & CHUNK_BAD144) { 705297627Sjmcneill int ret; 706297627Sjmcneill 707297627Sjmcneill msgNotify("Running bad block scan on slice %s", c1->name); 708297627Sjmcneill if (!Fake) { 709297627Sjmcneill ret = vsystem("bad144 -v /dev/r%s 1234", c1->name); 710297627Sjmcneill if (ret) 711297627Sjmcneill msgConfirm("Bad144 init on %s returned status of %d!", c1->name, ret); 712297627Sjmcneill ret = vsystem("bad144 -v -s /dev/r%s", c1->name); 713297627Sjmcneill if (ret) 714297627Sjmcneill msgConfirm("Bad144 scan on %s returned status of %d!", c1->name, ret); 715297627Sjmcneill } 716297627Sjmcneill } 717297627Sjmcneill } 718297627Sjmcneill } 719297627Sjmcneill /* Now it's not "yes", but "written" */ 720297627Sjmcneill variable_set2(DISK_PARTITIONED, "written", 0); 721297627Sjmcneill return DITEM_SUCCESS; 722297627Sjmcneill} 723297627Sjmcneill 724297627Sjmcneill/* Partition a disk based wholly on which variables are set */ 725297627Sjmcneillstatic void 726297627SjmcneilldiskPartitionNonInteractive(Device *dev) 727297627Sjmcneill{ 728297627Sjmcneill char *cp; 729297627Sjmcneill int i, sz, all_disk = 0; 730297627Sjmcneill u_char *mbrContents; 731297627Sjmcneill Disk *d = (Disk *)dev->private; 732297627Sjmcneill 733297627Sjmcneill record_chunks(d); 734297627Sjmcneill cp = variable_get(VAR_GEOMETRY); 735297627Sjmcneill if (cp) { 736297627Sjmcneill msgDebug("Setting geometry from script to: %s\n", cp); 737297627Sjmcneill d->bios_cyl = strtol(cp, &cp, 0); 738297627Sjmcneill d->bios_hd = strtol(cp + 1, &cp, 0); 739297627Sjmcneill d->bios_sect = strtol(cp + 1, 0, 0); 740297627Sjmcneill } 741297627Sjmcneill 742297627Sjmcneill cp = variable_get(VAR_PARTITION); 743297627Sjmcneill if (cp) { 744297627Sjmcneill if (!strcmp(cp, "free")) { 745297627Sjmcneill /* Do free disk space case */ 746297627Sjmcneill for (i = 0; chunk_info[i]; i++) { 747297627Sjmcneill /* If a chunk is at least 10MB in size, use it. */ 748297627Sjmcneill if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { 749297627Sjmcneill Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3, 750297627Sjmcneill (chunk_info[i]->flags & CHUNK_ALIGN)); 751297627Sjmcneill variable_set2(DISK_PARTITIONED, "yes", 0); 752297627Sjmcneill break; 753297627Sjmcneill } 754297627Sjmcneill } 755297627Sjmcneill if (!chunk_info[i]) { 756297627Sjmcneill dialog_clear(); 757297627Sjmcneill msgConfirm("Unable to find any free space on this disk!"); 758297627Sjmcneill return; 759297627Sjmcneill } 760297627Sjmcneill } 761297627Sjmcneill else if (!strcmp(cp, "all")) { 762297627Sjmcneill /* Do all disk space case */ 763297627Sjmcneill msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 764297627Sjmcneill 765297627Sjmcneill All_FreeBSD(d, FALSE); 766297627Sjmcneill } 767297627Sjmcneill else if (!strcmp(cp, "exclusive")) { 768297627Sjmcneill /* Do really-all-the-disk-space case */ 769297627Sjmcneill msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 770297627Sjmcneill 771297627Sjmcneill All_FreeBSD(d, all_disk = TRUE); 772297627Sjmcneill } 773297627Sjmcneill else if ((sz = strtol(cp, &cp, 0))) { 774297627Sjmcneill /* Look for sz bytes free */ 775297627Sjmcneill if (*cp && toupper(*cp) == 'M') 776297627Sjmcneill sz *= ONE_MEG; 777297627Sjmcneill for (i = 0; chunk_info[i]; i++) { 778297627Sjmcneill /* If a chunk is at least sz MB, use it. */ 779297627Sjmcneill if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { 780297627Sjmcneill Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN)); 781297627Sjmcneill variable_set2(DISK_PARTITIONED, "yes", 0); 782297627Sjmcneill break; 783297627Sjmcneill } 784297627Sjmcneill } 785297627Sjmcneill if (!chunk_info[i]) { 786297627Sjmcneill dialog_clear(); 787297627Sjmcneill msgConfirm("Unable to find %d free blocks on this disk!", sz); 788297627Sjmcneill return; 789297627Sjmcneill } 790297627Sjmcneill } 791297627Sjmcneill else if (!strcmp(cp, "existing")) { 792297627Sjmcneill /* Do existing FreeBSD case */ 793297627Sjmcneill for (i = 0; chunk_info[i]; i++) { 794297627Sjmcneill if (chunk_info[i]->type == freebsd) 795297627Sjmcneill break; 796297627Sjmcneill } 797297627Sjmcneill if (!chunk_info[i]) { 798297627Sjmcneill dialog_clear(); 799297627Sjmcneill msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); 800297627Sjmcneill return; 801297627Sjmcneill } 802297627Sjmcneill } 803297627Sjmcneill else { 804297627Sjmcneill dialog_clear(); 805297627Sjmcneill msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); 806297627Sjmcneill return; 807297627Sjmcneill } 808297627Sjmcneill if (!all_disk) { 809297627Sjmcneill mbrContents = getBootMgr(d->name); 810297627Sjmcneill Set_Boot_Mgr(d, mbrContents); 811297627Sjmcneill } 812297627Sjmcneill variable_set2(DISK_PARTITIONED, "yes", 0); 813299703Sgonzo } 814297627Sjmcneill} 815297627Sjmcneill