disks.c revision 8307
1/* 2 * The new sysinstall program. 3 * 4 * This is probably the last program in the `sysinstall' line - the next 5 * generation being essentially a complete rewrite. 6 * 7 * $Id: disks.c,v 1.2 1995/05/05 23:47:40 jkh Exp $ 8 * 9 * Copyright (c) 1995 10 * Jordan Hubbard. All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer, 17 * verbatim and that no modifications are made prior to this 18 * point in the file. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by Jordan Hubbard 25 * for the FreeBSD Project. 26 * 4. The name of Jordan Hubbard or the FreeBSD project may not be used to 27 * endorse or promote products derived from this software without specific 28 * prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 */ 43 44#include "sysinstall.h" 45#include <ctype.h> 46#include <sys/disklabel.h> 47 48/* 49 * I make some pretty gross assumptions about having a max of 50 chunks 50 * total - 8 slices and 42 partitions. I can't easily display many more 51 * than that on the screen at once! 52 * 53 * For 2.1 I'll revisit this and try to make it more dynamic, but since 54 * this will catch 99.99% of all possible cases, I'm not too worried. 55 */ 56 57#define MAX_CHUNKS 50 58 59/* Where to start printing the freebsd slices */ 60#define CHUNK_SLICE_START_ROW 2 61#define CHUNK_PART_START_ROW 10 62 63/* The smallest filesystem we're willing to create */ 64#define FS_MIN_SIZE 2048 65 66static struct { 67 struct disk *d; 68 struct chunk *c; 69 PartInfo *p; 70 PartType type; 71} fbsd_chunk_info[MAX_CHUNKS + 1]; 72static int current_chunk; 73 74 75/* If the given disk has a root partition on it, return TRUE */ 76static Boolean 77contains_root_partition(struct disk *d) 78{ 79 struct chunk *c1; 80 81 if (!d->chunks) 82 msgFatal("Disk %s has no chunks!", d->name); 83 c1 = d->chunks->part; 84 while (c1) { 85 if (c1->type == freebsd) { 86 struct chunk *c2 = c1->part; 87 88 while (c2) { 89 if (c2->flags & CHUNK_IS_ROOT) 90 return TRUE; 91 c2 = c2->next; 92 } 93 } 94 c1 = c1->next; 95 } 96 return FALSE; 97} 98 99static Boolean 100check_conflict(char *name) 101{ 102 int i; 103 104 for (i = 0; fbsd_chunk_info[i].d; i++) 105 if (fbsd_chunk_info[i].type == PART_FILESYSTEM && 106 !strcmp(fbsd_chunk_info[i].c->name, name)) 107 return TRUE; 108 return FALSE; 109} 110 111static int 112space_free(struct chunk *c) 113{ 114 struct chunk *c1 = c->part; 115 int sz = c->size; 116 117 while (c1) { 118 if (c1->type != unused) 119 sz -= c1->size; 120 c1 = c1->next; 121 } 122 if (sz < 0) 123 msgFatal("Partitions are larger than actual chunk??"); 124 return sz; 125} 126 127static void 128record_fbsd_chunks(struct disk **disks) 129{ 130 int i, j, p; 131 132 j = p = 0; 133 for (i = 0; disks[i]; i++) { 134 struct chunk *c1; 135 136 if (!disks[i]->chunks) 137 msgFatal("No chunk list found for %s!", disks[i]->name); 138 c1 = disks[i]->chunks->part; 139 while (c1) { 140 if (c1->type == freebsd) { 141 struct chunk *c2 = c1->part; 142 143 fbsd_chunk_info[j].type = PART_SLICE; 144 fbsd_chunk_info[j].d = disks[i]; 145 fbsd_chunk_info[j].c = c1; 146 fbsd_chunk_info[j++].p = NULL; 147 while (c2) { 148 if (c2->type == part) { 149 if (c2->subtype == FS_SWAP) 150 fbsd_chunk_info[j].type = PART_SWAP; 151 else 152 fbsd_chunk_info[j].type = PART_FILESYSTEM; 153 fbsd_chunk_info[j].d = disks[i]; 154 fbsd_chunk_info[j].c = c2; 155 fbsd_chunk_info[j++].p = c2->private; 156 } 157 c2 = c2->next; 158 } 159 } 160 c1 = c1->next; 161 } 162 } 163 fbsd_chunk_info[j].d = NULL; 164 fbsd_chunk_info[j].c = NULL; 165} 166 167int 168get_mountpoint(struct chunk *c) 169{ 170 char *val; 171 PartInfo *part; 172 173 val = msgGetInput(c->private, 174 "Please specify mount point for new partition"); 175 if (val) { 176 if (!strcmp(val, "/")) { 177 if (c->flags & CHUNK_PAST_1024) { 178msgConfirm("This region cannot be used for your root partition as\nit is past the 1024'th cylinder mark and the system would not be\nable to boot from it. Please pick another location for your\nroot partition and try again!"); 179 return 1; 180 } 181 c->flags |= CHUNK_IS_ROOT; 182 } 183 if (check_conflict(val)) { 184 msgConfirm("You already have a mountpoint for %s assigned!", val); 185 return 1; 186 } 187 safe_free(c->private); 188 part = (PartInfo *)malloc(sizeof(PartInfo)); 189 strncpy(part->mountpoint, val, FILENAME_MAX); 190 part->newfs = TRUE; 191 c->private = (void *)part; 192 c->private_free = free; 193 return 0; 194 } 195 return 1; 196} 197 198static PartType 199get_partition_type(struct chunk *c) 200{ 201 char selection[20]; 202 static unsigned char *fs_types[] = { 203 "FS", 204 "A file system", 205 "Swap", 206 "A swap partition.", 207 }; 208 209 if (!dialog_menu("Please choose a partition type", 210 "If you want to use this partition for swap space, select Swap.\nIf you want to put a filesystem on it, choose FS.", -1, -1, 2, 2, fs_types, selection, NULL, NULL)) { 211 if (!strcmp(selection, "FS")) 212 return PART_FILESYSTEM; 213 else if (!strcmp(selection, "Swap")) 214 return PART_SWAP; 215 } 216 return PART_NONE; 217} 218 219#define PART_PART_COL 0 220#define PART_MOUNT_COL 8 221#define PART_NEWFS_COL 32 222#define PART_OFF 40 223 224static void 225print_fbsd_chunks(void) 226{ 227 int i, srow, prow, pcol; 228 int sz; 229 230 attrset(A_REVERSE); 231 mvaddstr(0, 25, "FreeBSD Partition Editor"); 232 attrset(A_NORMAL); 233 234 for (i = 0; i < 2; i++) { 235 attrset(A_UNDERLINE); 236 mvaddstr(CHUNK_PART_START_ROW - 1, PART_PART_COL + (i * PART_OFF), 237 "Part"); 238 attrset(A_NORMAL); 239 240 attrset(A_UNDERLINE); 241 mvaddstr(CHUNK_PART_START_ROW - 1, PART_MOUNT_COL + (i * PART_OFF), 242 "Mount"); 243 attrset(A_NORMAL); 244 245 attrset(A_UNDERLINE); 246 mvaddstr(CHUNK_PART_START_ROW - 1, PART_NEWFS_COL + (i * PART_OFF), 247 "Newfs"); 248 attrset(A_NORMAL); 249 } 250 251 srow = CHUNK_SLICE_START_ROW; 252 prow = CHUNK_PART_START_ROW; 253 254 for (i = 0; fbsd_chunk_info[i].d; i++) { 255 if (i == current_chunk) 256 attrset(A_BOLD); 257 if (fbsd_chunk_info[i].type == PART_SLICE) { 258 sz = space_free(fbsd_chunk_info[i].c); 259 mvprintw(srow++, 0, 260 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 261 fbsd_chunk_info[i].d->name, 262 fbsd_chunk_info[i].c->name, sz, (sz / 2048)); 263 } 264 else { 265 /* Go for two columns */ 266 if (prow == (CHUNK_PART_START_ROW + 9)) 267 pcol = PART_OFF; 268 else 269 pcol = 0; 270 mvaddstr(prow, pcol + PART_PART_COL, fbsd_chunk_info[i].c->name); 271 if (fbsd_chunk_info[i].type == PART_FILESYSTEM) { 272 char *mountpoint, *newfs; 273 274 if (fbsd_chunk_info[i].c->private) { 275 mountpoint = ((PartInfo *)fbsd_chunk_info[i].c->private)->mountpoint; 276 newfs = ((PartInfo *)fbsd_chunk_info[i].c->private)->newfs ? "Y" : "N"; 277 } 278 else { 279 mountpoint = "?"; 280 newfs = ""; 281 } 282 mvaddstr(prow, pcol + PART_MOUNT_COL, mountpoint); 283 mvaddstr(prow, pcol + PART_NEWFS_COL, newfs); 284 } 285 else 286 mvaddstr(prow, pcol + PART_MOUNT_COL, "swap"); 287 ++prow; 288 } 289 if (i == current_chunk) 290 attrset(A_NORMAL); 291 } 292} 293 294static void 295print_command_summary() 296{ 297 int attrs = ColorDisplay ? A_BOLD : A_UNDERLINE; 298 299 mvprintw(19, 0, 300 "The following commands are valid here (upper or lower case):"); 301 mvprintw(20, 0, "C = Create FreeBSD Partition D = Delete Partition"); 302 mvprintw(21, 0, "M = Mount Partition (no newfs) ESC = Proceed to summary screen"); 303 mvprintw(22, 0, "The default target will be displayed in "); 304 305 attrset(attrs); 306 addstr(ColorDisplay ? "bold" : "underline"); 307 attrset(A_NORMAL); 308 move(0, 0); 309} 310 311void 312partition_disks(struct disk **disks) 313{ 314 int sz, key = 0; 315 Boolean partitioning; 316 char *msg = NULL; 317 318 dialog_clear(); 319 partitioning = TRUE; 320 keypad(stdscr, TRUE); 321 record_fbsd_chunks(disks); 322 323 while (partitioning) { 324 clear(); 325 print_fbsd_chunks(); 326 print_command_summary(); 327 if (msg) { 328 standout(); mvprintw(23, 0, msg); standend(); 329 beep(); 330 msg = NULL; 331 } 332 refresh(); 333 key = toupper(getch()); 334 switch (key) { 335 case KEY_UP: 336 case '-': 337 if (current_chunk != 0) 338 --current_chunk; 339 break; 340 341 case KEY_DOWN: 342 case '+': 343 case '\r': 344 case '\n': 345 if (fbsd_chunk_info[current_chunk + 1].d) 346 ++current_chunk; 347 break; 348 349 case KEY_HOME: 350 current_chunk = 0; 351 break; 352 353 case KEY_END: 354 while (fbsd_chunk_info[current_chunk + 1].d) 355 ++current_chunk; 356 break; 357 358 case KEY_F(1): 359 case '?': 360 systemDisplayFile("partitioning.hlp"); 361 break; 362 363 case 'C': 364 if (fbsd_chunk_info[current_chunk].type != PART_SLICE) { 365 msg = "Can only create sub-partitions in a master partition (at top)"; 366 break; 367 } 368 sz = space_free(fbsd_chunk_info[current_chunk].c); 369 if (sz <= FS_MIN_SIZE) 370 msg = "Not enough space to create additional FreeBSD partition"; 371 else { 372 char *val, tmp[20]; 373 int size; 374 375 snprintf(tmp, 20, "%d", sz); 376 val = msgGetInput(tmp, "Please specify size for new FreeBSD partition"); 377 if (val && (size = strtol(val, 0, 0)) > 0) { 378 PartType type; 379 380 if (get_mountpoint(fbsd_chunk_info[current_chunk].c)) 381 break; 382 type = get_partition_type(fbsd_chunk_info[current_chunk].c); 383 if (type == PART_NONE) 384 break; 385 Create_Chunk(fbsd_chunk_info[current_chunk].d, 386 fbsd_chunk_info[current_chunk].c->offset + 387 sz - size, 388 size, 389 part, 390 type == PART_SWAP ? FS_SWAP : freebsd, 391 fbsd_chunk_info[current_chunk].c->flags); 392 record_fbsd_chunks(disks); 393 } 394 } 395 break; 396 397 case 'D': 398 if (fbsd_chunk_info[current_chunk].type == PART_SLICE) { 399 msg = "Use the Master Partition Editor to delete one of these"; 400 break; 401 } 402 Delete_Chunk(fbsd_chunk_info[current_chunk].d, 403 fbsd_chunk_info[current_chunk].c); 404 break; 405 406 case 27: /* ESC */ 407 partitioning = FALSE; 408 break; 409 } 410 } 411} 412 413int 414write_disks(struct disk **disks) 415{ 416 int i; 417 extern u_char boot1[], boot2[]; 418 extern u_char mbr[], bteasy17[]; 419 420 dialog_clear(); 421 if (!msgYesNo("Last Chance! Are you sure you want to write out\nall your changes to disk?")) { 422 for (i = 0; disks[i]; i++) { 423 if (contains_root_partition(disks[i])) 424 Set_Boot_Blocks(disks[i], boot1, boot2); 425 if (i == 0 && !msgYesNo("Would you like to install a boot manager?\n\nThis will allow you to easily select between other operating systems\non the first disk, or boot from a disk other than the first.")) 426 Set_Boot_Mgr(disks[i], bteasy17); 427 else if (i == 0 && !msgYesNo("Would you like to remove an existing boot manager?")) 428 Set_Boot_Mgr(disks[i], mbr); 429#if 0 430 Write_Disk(disks[i]); 431#endif 432 } 433 return 0; 434 } 435 return 1; 436} 437