disks.c revision 8317
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.5 1995/05/07 03:37:59 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 struct chunk *c1, *c2; 132 133 j = p = current_chunk = 0; 134 for (i = 0; disks[i]; i++) { 135 if (!disks[i]->chunks) 136 msgFatal("No chunk list found for %s!", disks[i]->name); 137 138 /* Put the freebsd chunks first */ 139 for (c1 = disks[i]->chunks->part; c1; c1 = c1->next) { 140 if (c1->type == freebsd) { 141 fbsd_chunk_info[j].type = PART_SLICE; 142 fbsd_chunk_info[j].d = disks[i]; 143 fbsd_chunk_info[j].c = c1; 144 fbsd_chunk_info[j].p = NULL; 145 ++j; 146 } 147 } 148 } 149 for (i = 0; disks[i]; i++) { 150 /* Then buzz through and pick up the partitions */ 151 for (c1 = disks[i]->chunks->part; c1; c1 = c1->next) { 152 if (c1->type == freebsd) { 153 for (c2 = c1->part; c2; c2 = c2->next) { 154 if (c2->type == part) { 155 if (c2->subtype == FS_SWAP) 156 fbsd_chunk_info[j].type = PART_SWAP; 157 else 158 fbsd_chunk_info[j].type = PART_FILESYSTEM; 159 fbsd_chunk_info[j].d = disks[i]; 160 fbsd_chunk_info[j].c = c2; 161 fbsd_chunk_info[j].p = c2->private; 162 ++j; 163 } 164 } 165 } 166 } 167 } 168 fbsd_chunk_info[j].d = NULL; 169 fbsd_chunk_info[j].c = NULL; 170} 171 172static PartInfo * 173new_part(char *mpoint, Boolean newfs) 174{ 175 PartInfo *ret; 176 177 ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 178 strncpy(ret->mountpoint, mpoint, FILENAME_MAX); 179 ret->newfs = newfs; 180 return ret; 181} 182 183int 184get_mountpoint(int i) 185{ 186 char *val; 187 188 val = msgGetInput(fbsd_chunk_info[i].p ? 189 fbsd_chunk_info[i].p->mountpoint : NULL, 190 "Please specify a mount point for the new partition"); 191 if (val) { 192 if (!strcmp(val, "/")) { 193 if (fbsd_chunk_info[i].c->flags & CHUNK_PAST_1024) { 194msgConfirm("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!"); 195 return 1; 196 } 197 fbsd_chunk_info[i].c->flags |= CHUNK_IS_ROOT; 198 } 199 if (check_conflict(val)) { 200 msgConfirm("You already have a mountpoint for %s assigned!", val); 201 return 1; 202 } 203 safe_free(fbsd_chunk_info[i].c->private); 204 fbsd_chunk_info[i].c->private = new_part(val, TRUE); 205 fbsd_chunk_info[i].c->private_free = free; 206 fbsd_chunk_info[i].p = fbsd_chunk_info[i].c->private; 207 return 0; 208 } 209 return 1; 210} 211 212static PartType 213get_partition_type(void) 214{ 215 char selection[20]; 216 static unsigned char *fs_types[] = { 217 "FS", 218 "A file system", 219 "Swap", 220 "A swap partition.", 221 }; 222 223 if (!dialog_menu("Please choose a partition type", 224 "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)) { 225 if (!strcmp(selection, "FS")) 226 return PART_FILESYSTEM; 227 else if (!strcmp(selection, "Swap")) 228 return PART_SWAP; 229 } 230 return PART_NONE; 231} 232 233#define MAX_MOUNT_NAME 12 234 235#define PART_PART_COL 0 236#define PART_MOUNT_COL 8 237#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 4) 238#define PART_NEWFS_COL (PART_SIZE_COL + 8) 239#define PART_OFF 42 240 241static void 242print_fbsd_chunks(void) 243{ 244 int i, j, srow, prow, pcol; 245 int sz; 246 247 attrset(A_REVERSE); 248 mvaddstr(0, 25, "FreeBSD Partition Editor"); 249 attrset(A_NORMAL); 250 251 for (i = 0; i < 2; i++) { 252 attrset(A_UNDERLINE); 253 mvaddstr(CHUNK_PART_START_ROW - 1, PART_PART_COL + (i * PART_OFF), 254 "Part"); 255 attrset(A_NORMAL); 256 257 attrset(A_UNDERLINE); 258 mvaddstr(CHUNK_PART_START_ROW - 1, PART_MOUNT_COL + (i * PART_OFF), 259 "Mount"); 260 attrset(A_NORMAL); 261 262 attrset(A_UNDERLINE); 263 mvaddstr(CHUNK_PART_START_ROW - 1, PART_SIZE_COL + (i * PART_OFF) + 2, 264 "Size"); 265 attrset(A_NORMAL); 266 267 attrset(A_UNDERLINE); 268 mvaddstr(CHUNK_PART_START_ROW - 1, PART_NEWFS_COL + (i * PART_OFF), 269 "Newfs"); 270 attrset(A_NORMAL); 271 } 272 273 srow = CHUNK_SLICE_START_ROW; 274 prow = CHUNK_PART_START_ROW; 275 276 for (i = 0; fbsd_chunk_info[i].d; i++) { 277 if (i == current_chunk) 278 attrset(A_REVERSE); 279 /* Is it a slice entry displayed at the top? */ 280 if (fbsd_chunk_info[i].type == PART_SLICE) { 281 sz = space_free(fbsd_chunk_info[i].c); 282 mvprintw(srow++, 0, 283 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 284 fbsd_chunk_info[i].d->name, 285 fbsd_chunk_info[i].c->name, sz, (sz / 2048)); 286 } 287 /* Otherwise it's a swap or filesystem entry, at the bottom */ 288 else { 289 char onestr[PART_OFF], num[10], *mountpoint, *newfs; 290 291 memset(onestr, ' ', PART_OFF - 1); 292 onestr[PART_OFF - 1] = '\0'; 293 /* Go for two columns */ 294 if (prow == (CHUNK_PART_START_ROW + 8)) 295 pcol = PART_OFF; 296 else 297 pcol = 0; 298 memcpy(onestr + PART_PART_COL, fbsd_chunk_info[i].c->name, 299 strlen(fbsd_chunk_info[i].c->name)); 300 if (fbsd_chunk_info[i].type == PART_FILESYSTEM) { 301 if (fbsd_chunk_info[i].p) { 302 mountpoint = fbsd_chunk_info[i].p->mountpoint; 303 newfs = fbsd_chunk_info[i].p->newfs ? "Y" : "N"; 304 } 305 else { 306 fbsd_chunk_info[i].c->private = new_part("", FALSE); 307 fbsd_chunk_info[i].c->private_free = free; 308 fbsd_chunk_info[i].p = fbsd_chunk_info[i].c->private; 309 mountpoint = " "; 310 newfs = "N"; 311 } 312 } 313 else { 314 mountpoint = "swap"; 315 newfs = " "; 316 } 317 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 318 onestr[PART_MOUNT_COL + j] = mountpoint[j]; 319 sprintf(num, "%4ldMB", fbsd_chunk_info[i].c->size ? 320 fbsd_chunk_info[i].c->size / 2048 : 0); 321 memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 322 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 323 mvaddstr(prow, pcol, onestr); 324 ++prow; 325 } 326 if (i == current_chunk) 327 attrset(A_NORMAL); 328 } 329} 330 331static void 332print_command_summary() 333{ 334 mvprintw(19, 0, 335 "The following commands are valid here (upper or lower case):"); 336 mvprintw(20, 0, "C = Create FreeBSD Partition D = Delete Partition"); 337 mvprintw(21, 0, "M = Mount Partition (no newfs) ESC = Proceed to summary screen"); 338 mvprintw(22, 0, "The default target will be displayed in "); 339 340 attrset(A_REVERSE); 341 addstr("reverse video"); 342 attrset(A_NORMAL); 343 move(0, 0); 344} 345 346void 347partition_disks(struct disk **disks) 348{ 349 int sz, key = 0; 350 Boolean partitioning; 351 char *msg = NULL; 352 353 dialog_clear(); 354 partitioning = TRUE; 355 keypad(stdscr, TRUE); 356 record_fbsd_chunks(disks); 357 358 while (partitioning) { 359 clear(); 360 print_fbsd_chunks(); 361 print_command_summary(); 362 if (msg) { 363 attrset(A_REVERSE); mvprintw(23, 0, msg); attrset(A_NORMAL); 364 beep(); 365 msg = NULL; 366 } 367 refresh(); 368 key = toupper(getch()); 369 switch (key) { 370 371 case KEY_UP: 372 case '-': 373 if (current_chunk != 0) 374 --current_chunk; 375 break; 376 377 case KEY_DOWN: 378 case '+': 379 case '\r': 380 case '\n': 381 if (fbsd_chunk_info[current_chunk + 1].d) 382 ++current_chunk; 383 break; 384 385 case KEY_HOME: 386 current_chunk = 0; 387 break; 388 389 case KEY_END: 390 while (fbsd_chunk_info[current_chunk + 1].d) 391 ++current_chunk; 392 break; 393 394 case KEY_F(1): 395 case '?': 396 systemDisplayFile("partitioning.hlp"); 397 break; 398 399 case 'C': 400 if (fbsd_chunk_info[current_chunk].type != PART_SLICE) { 401 msg = "Can't create a sub-partition here (that only works in master partitions)"; 402 break; 403 } 404 sz = space_free(fbsd_chunk_info[current_chunk].c); 405 if (sz <= FS_MIN_SIZE) 406 msg = "Not enough space to create additional FreeBSD partition"; 407 else { 408 char *val, tmp[20]; 409 int size; 410 411 snprintf(tmp, 20, "%d", sz); 412 val = msgGetInput(tmp, "Please specify size for new FreeBSD partition"); 413 if (val && (size = strtol(val, 0, 0)) > 0) { 414 PartType type; 415 416 type = get_partition_type(); 417 if (type == PART_NONE) 418 break; 419 Create_Chunk(fbsd_chunk_info[current_chunk].d, 420 fbsd_chunk_info[current_chunk].c->offset + 421 sz - size, 422 size, 423 part, 424 type == PART_SWAP ? FS_SWAP : freebsd, 425 fbsd_chunk_info[current_chunk].c->flags); 426 if (get_mountpoint(current_chunk)) 427 break; 428 record_fbsd_chunks(disks); 429 } 430 } 431 break; 432 433 case 'D': /* delete */ 434 if (fbsd_chunk_info[current_chunk].type == PART_SLICE) { 435 msg = "Use the Master Partition Editor to delete one of these"; 436 break; 437 } 438 Delete_Chunk(fbsd_chunk_info[current_chunk].d, 439 fbsd_chunk_info[current_chunk].c); 440 record_fbsd_chunks(disks); 441 break; 442 443 case 'M': /* mount */ 444 if (fbsd_chunk_info[current_chunk].type == PART_SLICE) { 445 msg = "You can't mount one of these directly!"; 446 break; 447 } 448 if (get_mountpoint(current_chunk)) 449 record_fbsd_chunks(disks); 450 break; 451 452 case 27: /* ESC */ 453 partitioning = FALSE; 454 break; 455 } 456 } 457} 458 459int 460write_disks(struct disk **disks) 461{ 462 int i; 463 extern u_char boot1[], boot2[]; 464 extern u_char mbr[], bteasy17[]; 465 466 dialog_clear(); 467 if (!msgYesNo("Last Chance! Are you sure you want to write out\nall your changes to disk?")) { 468 for (i = 0; disks[i]; i++) { 469 if (contains_root_partition(disks[i])) 470 Set_Boot_Blocks(disks[i], boot1, boot2); 471 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.")) 472 Set_Boot_Mgr(disks[i], bteasy17); 473 else if (i == 0 && !msgYesNo("Would you like to remove an existing boot manager?")) 474 Set_Boot_Mgr(disks[i], mbr); 475#if 0 476 Write_Disk(disks[i]); 477#endif 478 } 479 return 0; 480 } 481 return 1; 482} 483