disks.c revision 8302
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$ 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 47/* 48 * I make some pretty gross assumptions about having a max of 50 chunks 49 * total - 8 slices and 42 partitions. I can't easily display many more 50 * than that on the screen at once! 51 * 52 * For 2.1 I'll revisit this and try to make it more dynamic, but since 53 * this will catch 99.99% of all possible cases, I'm not too worried. 54 */ 55 56#define MAX_CHUNKS 50 57 58#define FS_SWAP 1 59 60/* Where to start printing the freebsd slices */ 61#define CHUNK_SLICE_START_ROW 2 62#define CHUNK_PART_START_ROW 10 63 64/* The smallest filesystem we're willing to create */ 65#define FS_MIN_SIZE 2048 66 67typedef enum { PART_NONE, PART_SLICE, PART_SWAP, PART_FILESYSTEM } part_type; 68 69struct part_info { 70 Boolean newfs; 71 char mountpoint[FILENAME_MAX]; 72}; 73 74static struct { 75 struct disk *d; 76 struct chunk *c; 77 struct part_info *p; 78 part_type type; 79} fbsd_chunk_info[MAX_CHUNKS + 1]; 80static int current_chunk; 81 82 83/* If the given disk has a root partition on it, return TRUE */ 84static Boolean 85contains_root_partition(struct disk *d) 86{ 87 struct chunk *c1; 88 89 if (!d->chunks) 90 msgFatal("Disk %s has no chunks!", d->name); 91 c1 = d->chunks->part; 92 while (c1) { 93 if (c1->type == freebsd) { 94 struct chunk *c2 = c1->part; 95 96 while (c2) { 97 if (c2->flags & CHUNK_IS_ROOT) 98 return TRUE; 99 c2 = c2->next; 100 } 101 } 102 c1 = c1->next; 103 } 104 return FALSE; 105} 106 107static Boolean 108check_conflict(char *name) 109{ 110 int i; 111 112 for (i = 0; fbsd_chunk_info[i].d; i++) 113 if (fbsd_chunk_info[i].type == PART_FILESYSTEM && 114 !strcmp(fbsd_chunk_info[i].c->name, name)) 115 return TRUE; 116 return FALSE; 117} 118 119static int 120space_free(struct chunk *c) 121{ 122 struct chunk *c1 = c->part; 123 int sz = c->size; 124 125 while (c1) { 126 if (c1->type != unused) 127 sz -= c1->size; 128 c1 = c1->next; 129 } 130 if (sz < 0) 131 msgFatal("Partitions are larger than actual chunk??"); 132 return sz; 133} 134 135static void 136record_fbsd_chunks(struct disk **disks) 137{ 138 int i, j, p; 139 140 j = p = 0; 141 for (i = 0; disks[i]; i++) { 142 struct chunk *c1; 143 144 if (!disks[i]->chunks) 145 msgFatal("No chunk list found for %s!", disks[i]->name); 146 c1 = disks[i]->chunks->part; 147 while (c1) { 148 if (c1->type == freebsd) { 149 struct chunk *c2 = c1->part; 150 151 fbsd_chunk_info[j].type = PART_SLICE; 152 fbsd_chunk_info[j].d = disks[i]; 153 fbsd_chunk_info[j].c = c1; 154 fbsd_chunk_info[j++].p = NULL; 155 while (c2) { 156 if (c2->type == part) { 157 if (c2->subtype == FS_SWAP) 158 fbsd_chunk_info[j].type = PART_SWAP; 159 else 160 fbsd_chunk_info[j].type = PART_FILESYSTEM; 161 fbsd_chunk_info[j].d = disks[i]; 162 fbsd_chunk_info[j].c = c2; 163 fbsd_chunk_info[j++].p = c2->private; 164 } 165 c2 = c2->next; 166 } 167 } 168 c1 = c1->next; 169 } 170 } 171 fbsd_chunk_info[j].d = NULL; 172 fbsd_chunk_info[j].c = NULL; 173} 174 175int 176get_mountpoint(struct chunk *c) 177{ 178 char *val; 179 struct part_info *part; 180 181 val = msgGetInput(c->private, 182 "Please specify mount point for new partition"); 183 if (val) { 184 if (!strcmp(val, "/")) { 185 if (c->flags & CHUNK_PAST_1024) { 186msgConfirm("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!"); 187 return 1; 188 } 189 c->flags |= CHUNK_IS_ROOT; 190 } 191 if (check_conflict(val)) { 192 msgConfirm("You already have a mountpoint for %s assigned!", val); 193 return 1; 194 } 195 safe_free(c->private); 196 part = (struct part_info *)malloc(sizeof(struct part_info)); 197 strncpy(part->mountpoint, val, FILENAME_MAX); 198 part->newfs = TRUE; 199 c->private = (void *)part; 200 c->private_free = free; 201 return 0; 202 } 203 return 1; 204} 205 206static part_type 207get_partition_type(struct chunk *c) 208{ 209 char selection[20]; 210 static unsigned char *fs_types[] = { 211 "Swap", 212 "A swap partition.", 213 "FS", 214 "A file system", 215 }; 216 217 if (!dialog_menu("Please choose a partition type", 218 "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)) { 219 if (!strcmp(selection, "FS")) 220 return PART_FILESYSTEM; 221 else if (!strcmp(selection, "Swap")) 222 return PART_SWAP; 223 } 224 return PART_NONE; 225} 226 227#define PART_PART_COL 0 228#define PART_MOUNT_COL 8 229#define PART_NEWFS_COL 32 230#define PART_OFF 40 231 232static void 233print_fbsd_chunks(void) 234{ 235 int i, srow, prow, pcol; 236 int sz; 237 238 attrset(A_REVERSE); 239 mvaddstr(0, 25, "FreeBSD Partition Editor"); 240 attrset(A_NORMAL); 241 242 for (i = 0; i < 2; i++) { 243 attrset(A_UNDERLINE); 244 mvaddstr(CHUNK_PART_START_ROW - 1, PART_PART_COL + (i * PART_OFF), 245 "Part"); 246 attrset(A_NORMAL); 247 248 attrset(A_UNDERLINE); 249 mvaddstr(CHUNK_PART_START_ROW - 1, PART_MOUNT_COL + (i * PART_OFF), 250 "Mount"); 251 attrset(A_NORMAL); 252 253 attrset(A_UNDERLINE); 254 mvaddstr(CHUNK_PART_START_ROW - 1, PART_NEWFS_COL + (i * PART_OFF), 255 "Newfs"); 256 attrset(A_NORMAL); 257 } 258 259 srow = CHUNK_SLICE_START_ROW; 260 prow = CHUNK_PART_START_ROW; 261 262 for (i = 0; fbsd_chunk_info[i].d; i++) { 263 if (i == current_chunk) 264 attrset(A_BOLD); 265 if (fbsd_chunk_info[i].type == PART_SLICE) { 266 sz = space_free(fbsd_chunk_info[i].c); 267 mvprintw(srow++, 0, 268 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 269 fbsd_chunk_info[i].d->name, 270 fbsd_chunk_info[i].c->name, sz, (sz / 2048)); 271 } 272 else { 273 /* Go for two columns */ 274 if (prow == (CHUNK_PART_START_ROW + 9)) 275 pcol = PART_OFF; 276 else 277 pcol = 0; 278 mvaddstr(prow, pcol + PART_PART_COL, fbsd_chunk_info[i].c->name); 279 if (fbsd_chunk_info[i].type == PART_FILESYSTEM) { 280 char *mountpoint, *newfs; 281 282 if (fbsd_chunk_info[i].c->private) { 283 mountpoint = ((struct part_info *)fbsd_chunk_info[i].c->private)->mountpoint; 284 newfs = ((struct part_info *)fbsd_chunk_info[i].c->private)->newfs ? "Y" : "N"; 285 } 286 else { 287 mountpoint = "?"; 288 newfs = ""; 289 } 290 mvaddstr(prow, pcol + PART_MOUNT_COL, mountpoint); 291 mvaddstr(prow, pcol + PART_NEWFS_COL, newfs); 292 } 293 else 294 mvaddstr(prow, pcol + PART_MOUNT_COL, "swap"); 295 ++prow; 296 } 297 if (i == current_chunk) 298 attrset(A_NORMAL); 299 } 300} 301 302static void 303print_command_summary() 304{ 305 int attrs = ColorDisplay ? A_BOLD : A_UNDERLINE; 306 307 mvprintw(19, 0, 308 "The following commands are valid here (upper or lower case):"); 309 mvprintw(20, 0, "C = Create FreeBSD Partition D = Delete Partition"); 310 mvprintw(21, 0, "M = Mount Partition (no newfs) ESC = Proceed to summary screen"); 311 mvprintw(22, 0, "The default target will be displayed in "); 312 313 attrset(attrs); 314 addstr(ColorDisplay ? "bold" : "underline"); 315 attrset(A_NORMAL); 316 move(0, 0); 317} 318 319void 320partition_disks(struct disk **disks) 321{ 322 int sz, key = 0; 323 Boolean partitioning; 324 char *msg = NULL; 325 326 dialog_clear(); 327 partitioning = TRUE; 328 keypad(stdscr, TRUE); 329 record_fbsd_chunks(disks); 330 331 while (partitioning) { 332 clear(); 333 print_fbsd_chunks(); 334 print_command_summary(); 335 if (msg) { 336 standout(); mvprintw(23, 0, msg); standend(); 337 beep(); 338 msg = NULL; 339 } 340 refresh(); 341 key = toupper(getch()); 342 switch (key) { 343 case KEY_UP: 344 case '-': 345 if (current_chunk != 0) 346 --current_chunk; 347 break; 348 349 case KEY_DOWN: 350 case '+': 351 case '\r': 352 case '\n': 353 if (fbsd_chunk_info[current_chunk + 1].d) 354 ++current_chunk; 355 break; 356 357 case KEY_HOME: 358 current_chunk = 0; 359 break; 360 361 case KEY_END: 362 while (fbsd_chunk_info[current_chunk + 1].d) 363 ++current_chunk; 364 break; 365 366 case KEY_F(1): 367 case '?': 368 systemDisplayFile("partitioning.hlp"); 369 break; 370 371 case 'C': 372 if (fbsd_chunk_info[current_chunk].type != PART_SLICE) { 373 msg = "Can only create sub-partitions in a master partition (at top)"; 374 break; 375 } 376 sz = space_free(fbsd_chunk_info[current_chunk].c); 377 if (sz <= FS_MIN_SIZE) 378 msg = "Not enough space to create additional FreeBSD partition"; 379 else { 380 char *val, tmp[20]; 381 int size; 382 383 snprintf(tmp, 20, "%d", sz); 384 val = msgGetInput(tmp, "Please specify size for new FreeBSD partition"); 385 if (val && (size = strtol(val, 0, 0)) > 0) { 386 part_type type; 387 388 if (get_mountpoint(fbsd_chunk_info[current_chunk].c)) 389 break; 390 type = get_partition_type(fbsd_chunk_info[current_chunk].c); 391 if (type == PART_NONE) 392 break; 393 Create_Chunk(fbsd_chunk_info[current_chunk].d, 394 fbsd_chunk_info[current_chunk].c->offset, 395 size, 396 part, 397 type == PART_SWAP ? FS_SWAP : freebsd, 398 fbsd_chunk_info[current_chunk].c->flags); 399 record_fbsd_chunks(disks); 400 } 401 } 402 break; 403 404 case 27: /* ESC */ 405 partitioning = FALSE; 406 break; 407 } 408 } 409} 410 411int 412write_disks(struct disk **disks) 413{ 414 int i; 415 extern u_char boot1[], boot2[]; 416 extern u_char mbr[], bteasy17[]; 417 418 dialog_clear(); 419 if (!msgYesNo("Last Chance! Are you sure you want to write your changes to disk?")) { 420 for (i = 0; disks[i]; i++) { 421 if (contains_root_partition(disks[i])) 422 Set_Boot_Blocks(disks[i], boot1, boot2); 423 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, as well as boot from a driver other than the first.")) 424 Set_Boot_Mgr(disks[i], bteasy17); 425 else if (i == 0 && !msgYesNo("Would you like to remove an existing boot manager?")) 426 Set_Boot_Mgr(disks[i], mbr); 427#if 0 428 Write_Disk(disks[i]); 429#endif 430 } 431 return 0; 432 } 433 return 1; 434} 435 436void 437make_filesystems(struct disk **disks) 438{ 439} 440 441void 442cpio_extract(struct disk **disks) 443{ 444} 445 446void 447extract_dists(struct disk **disks) 448{ 449} 450 451void 452do_final_setup(struct disk **disks) 453{ 454} 455 456