disks.c revision 8313
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.3 1995/05/06 09:34:11 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 MAX_MOUNT_NAME 12 220 221#define PART_PART_COL 0 222#define PART_MOUNT_COL 8 223#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 4) 224#define PART_NEWFS_COL (PART_SIZE_COL + 8) 225#define PART_OFF 40 226 227static void 228print_fbsd_chunks(void) 229{ 230 int i, srow, prow, pcol; 231 int sz; 232 233 attrset(A_REVERSE); 234 mvaddstr(0, 25, "FreeBSD Partition Editor"); 235 attrset(A_NORMAL); 236 237 for (i = 0; i < 2; i++) { 238 attrset(A_UNDERLINE); 239 mvaddstr(CHUNK_PART_START_ROW - 1, PART_PART_COL + (i * PART_OFF), 240 "Part"); 241 attrset(A_NORMAL); 242 243 attrset(A_UNDERLINE); 244 mvaddstr(CHUNK_PART_START_ROW - 1, PART_MOUNT_COL + (i * PART_OFF), 245 "Mount"); 246 attrset(A_NORMAL); 247 248 attrset(A_UNDERLINE); 249 mvaddstr(CHUNK_PART_START_ROW - 1, PART_SIZE_COL + (i * PART_OFF), 250 "Size"); 251 252 attrset(A_UNDERLINE); 253 mvaddstr(CHUNK_PART_START_ROW - 1, PART_NEWFS_COL + (i * PART_OFF), 254 "Newfs"); 255 attrset(A_NORMAL); 256 } 257 258 srow = CHUNK_SLICE_START_ROW; 259 prow = CHUNK_PART_START_ROW; 260 261 for (i = 0; fbsd_chunk_info[i].d; i++) { 262 if (i == current_chunk) 263 attrset(ColorDisplay ? A_BOLD : A_UNDERLINE); 264 /* Is it a slice entry displayed at the top? */ 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 /* Otherwise it's a swap or filesystem entry, at the bottom */ 273 else { 274 char *mountpoint, *newfs; 275 276 /* Go for two columns */ 277 if (prow == (CHUNK_PART_START_ROW + 9)) 278 pcol = PART_OFF; 279 else 280 pcol = 0; 281 mvaddstr(prow, pcol + PART_PART_COL, fbsd_chunk_info[i].c->name); 282 if (fbsd_chunk_info[i].type == PART_FILESYSTEM) { 283 if (fbsd_chunk_info[i].p) { 284 mountpoint = fbsd_chunk_info[i].p->mountpoint; 285 newfs = fbsd_chunk_info[i].p->newfs ? "Y" : "N"; 286 } 287 else { 288 mountpoint = " "; 289 newfs = " "; 290 } 291 } 292 else { 293 mountpoint = "swap"; 294 newfs = " "; 295 } 296 for (i = 0; i < MAX_MOUNT_NAME && mountpoint[i]; i++) 297 mvaddch(prow, pcol + PART_MOUNT_COL + i, mountpoint[i]); 298 mvprintw(prow, pcol + PART_SIZE_COL, "%4dMB", 299 fbsd_chunk_info[i].c->size ? 300 fbsd_chunk_info[i].c->size / 2048 : 0); 301 mvaddstr(prow, pcol + PART_NEWFS_COL, newfs); 302 ++prow; 303 } 304 if (i == current_chunk) 305 attrset(A_NORMAL); 306 } 307} 308 309static void 310print_command_summary() 311{ 312 int attrs = ColorDisplay ? A_BOLD : A_UNDERLINE; 313 314 mvprintw(19, 0, 315 "The following commands are valid here (upper or lower case):"); 316 mvprintw(20, 0, "C = Create FreeBSD Partition D = Delete Partition"); 317 mvprintw(21, 0, "M = Mount Partition (no newfs) ESC = Proceed to summary screen"); 318 mvprintw(22, 0, "The default target will be displayed in "); 319 320 attrset(attrs); 321 addstr(ColorDisplay ? "bold" : "underline"); 322 attrset(A_NORMAL); 323 move(0, 0); 324} 325 326void 327partition_disks(struct disk **disks) 328{ 329 int sz, key = 0; 330 Boolean partitioning; 331 char *msg = NULL; 332 333 dialog_clear(); 334 partitioning = TRUE; 335 keypad(stdscr, TRUE); 336 record_fbsd_chunks(disks); 337 338 while (partitioning) { 339 clear(); 340 print_fbsd_chunks(); 341 print_command_summary(); 342 if (msg) { 343 standout(); mvprintw(23, 0, msg); standend(); 344 beep(); 345 msg = NULL; 346 } 347 refresh(); 348 key = toupper(getch()); 349 switch (key) { 350 case KEY_UP: 351 case '-': 352 if (current_chunk != 0) 353 --current_chunk; 354 break; 355 356 case KEY_DOWN: 357 case '+': 358 case '\r': 359 case '\n': 360 if (fbsd_chunk_info[current_chunk + 1].d) 361 ++current_chunk; 362 break; 363 364 case KEY_HOME: 365 current_chunk = 0; 366 break; 367 368 case KEY_END: 369 while (fbsd_chunk_info[current_chunk + 1].d) 370 ++current_chunk; 371 break; 372 373 case KEY_F(1): 374 case '?': 375 systemDisplayFile("partitioning.hlp"); 376 break; 377 378 case 'C': 379 if (fbsd_chunk_info[current_chunk].type != PART_SLICE) { 380 msg = "Can only create sub-partitions in a master partition (at top)"; 381 break; 382 } 383 sz = space_free(fbsd_chunk_info[current_chunk].c); 384 if (sz <= FS_MIN_SIZE) 385 msg = "Not enough space to create additional FreeBSD partition"; 386 else { 387 char *val, tmp[20]; 388 int size; 389 390 snprintf(tmp, 20, "%d", sz); 391 val = msgGetInput(tmp, "Please specify size for new FreeBSD partition"); 392 if (val && (size = strtol(val, 0, 0)) > 0) { 393 PartType type; 394 395 if (get_mountpoint(fbsd_chunk_info[current_chunk].c)) 396 break; 397 type = get_partition_type(fbsd_chunk_info[current_chunk].c); 398 if (type == PART_NONE) 399 break; 400 Create_Chunk(fbsd_chunk_info[current_chunk].d, 401 fbsd_chunk_info[current_chunk].c->offset + 402 sz - size, 403 size, 404 part, 405 type == PART_SWAP ? FS_SWAP : freebsd, 406 fbsd_chunk_info[current_chunk].c->flags); 407 record_fbsd_chunks(disks); 408 } 409 } 410 break; 411 412 case 'D': 413 if (fbsd_chunk_info[current_chunk].type == PART_SLICE) { 414 msg = "Use the Master Partition Editor to delete one of these"; 415 break; 416 } 417 Delete_Chunk(fbsd_chunk_info[current_chunk].d, 418 fbsd_chunk_info[current_chunk].c); 419 break; 420 421 case 27: /* ESC */ 422 partitioning = FALSE; 423 break; 424 } 425 } 426} 427 428int 429write_disks(struct disk **disks) 430{ 431 int i; 432 extern u_char boot1[], boot2[]; 433 extern u_char mbr[], bteasy17[]; 434 435 dialog_clear(); 436 if (!msgYesNo("Last Chance! Are you sure you want to write out\nall your changes to disk?")) { 437 for (i = 0; disks[i]; i++) { 438 if (contains_root_partition(disks[i])) 439 Set_Boot_Blocks(disks[i], boot1, boot2); 440 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.")) 441 Set_Boot_Mgr(disks[i], bteasy17); 442 else if (i == 0 && !msgYesNo("Would you like to remove an existing boot manager?")) 443 Set_Boot_Mgr(disks[i], mbr); 444#if 0 445 Write_Disk(disks[i]); 446#endif 447 } 448 return 0; 449 } 450 return 1; 451} 452