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