1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This file contains functions to implement the partition menu commands. 31 */ 32 #include "global.h" 33 #include "partition.h" 34 #include "menu_partition.h" 35 #include "menu_command.h" 36 #include "modify_partition.h" 37 #include "checkmount.h" 38 #include "misc.h" 39 #include "label.h" 40 #include "auto_sense.h" 41 42 #include <stdlib.h> 43 #include <string.h> 44 45 #ifdef __STDC__ 46 47 /* Function prototypes for ANSI C Compilers */ 48 49 static void adj_cyl_offset(struct dk_map32 *map); 50 static int check_map(struct dk_map32 *map); 51 static void get_user_map(struct dk_map32 *map, int float_part); 52 static void get_user_map_efi(struct dk_gpt *map, int float_part); 53 54 #else /* __STDC__ */ 55 56 /* Function prototypes for non-ANSI C Compilers */ 57 58 static void adj_cyl_offset(); 59 static int check_map(); 60 static void get_user_map(); 61 static void get_user_map_efi(); 62 63 #endif /* __STDC__ */ 64 65 static char *partn_list[] = { "0", "1", "2", "3", "4", "5", "6", "7", NULL }; 66 67 static char *sel_list[] = { "0", "1", "2", "3", NULL }; 68 69 #define MBYTE (1024*1024) 70 71 72 /* 73 * Modify/Create a predefined partition table. 74 */ 75 int 76 p_modify() 77 { 78 struct partition_info tmp_pinfo[1]; 79 struct dk_map32 *map = tmp_pinfo->pinfo_map; 80 u_ioparam_t ioparam; 81 int inpt_dflt = 0; 82 int free_hog = -1; 83 int i; 84 char tmpstr[80]; 85 char tmpstr2[300]; 86 int sel_type = 0; 87 88 /* 89 * There must be a current disk type (and therefore a current disk). 90 */ 91 if (cur_dtype == NULL) { 92 err_print("Current Disk Type is not set.\n"); 93 return (-1); 94 } 95 96 /* 97 * check if there exists a partition table for the disk. 98 */ 99 if (cur_parts == NULL) { 100 err_print("Current Disk has no partition table.\n"); 101 return (-1); 102 } 103 104 105 /* 106 * If the disk has mounted partitions, cannot modify 107 */ 108 if (checkmount((daddr_t)-1, (daddr_t)-1)) { 109 err_print( 110 "Cannot modify disk partitions while it has mounted partitions.\n\n"); 111 return (-1); 112 } 113 /* 114 * If the disk has partitions currently being used for 115 * swapping, cannot modify 116 */ 117 if (checkswap((daddr_t)-1, (daddr_t)-1)) { 118 err_print( 119 "Cannot modify disk partitions while it is \ 120 currently being used for swapping.\n"); 121 return (-1); 122 } 123 /* 124 * prompt user for a partition table base 125 */ 126 if (cur_parts->pinfo_name != NULL) { 127 (void) snprintf(tmpstr, sizeof (tmpstr), 128 "\t0. Current partition table (%s)", 129 cur_parts->pinfo_name); 130 } else { 131 (void) sprintf(tmpstr, 132 "\t0. Current partition table (unnamed)"); 133 } 134 135 (void) snprintf(tmpstr2, sizeof (tmpstr2), 136 "Select partitioning base:\n%s\n" 137 "\t1. All Free Hog\n" 138 "Choose base (enter number) ", 139 tmpstr); 140 141 ioparam.io_charlist = sel_list; 142 sel_type = input(FIO_MSTR, tmpstr2, '?', &ioparam, 143 &sel_type, DATA_INPUT); 144 145 switch (cur_label) { 146 case L_TYPE_SOLARIS: 147 if (sel_type == 0) { 148 /* 149 * Check for invalid parameters but do 150 * not modify the table. 151 */ 152 if (check_map(cur_parts->pinfo_map)) { 153 err_print("\ 154 Warning: Fix, or select a different partition table.\n"); 155 return (0); 156 } 157 /* 158 * Create partition map from existing map 159 */ 160 tmp_pinfo->vtoc = cur_parts->vtoc; 161 for (i = 0; i < NDKMAP; i++) { 162 map[i].dkl_nblk = cur_parts->pinfo_map[i].dkl_nblk; 163 map[i].dkl_cylno = cur_parts->pinfo_map[i].dkl_cylno; 164 } 165 } else { 166 /* 167 * Make an empty partition map, with all the space 168 * in the c partition. 169 */ 170 set_vtoc_defaults(tmp_pinfo); 171 for (i = 0; i < NDKMAP; i++) { 172 map[i].dkl_nblk = 0; 173 map[i].dkl_cylno = 0; 174 } 175 map[C_PARTITION].dkl_nblk = ncyl * spc(); 176 177 #if defined(i386) 178 /* 179 * Adjust for the boot and possibly alternates partitions 180 */ 181 map[I_PARTITION].dkl_nblk = spc(); 182 map[I_PARTITION].dkl_cylno = 0; 183 if (cur_ctype->ctype_ctype != DKC_SCSI_CCS) { 184 map[J_PARTITION].dkl_nblk = 2 * spc(); 185 map[J_PARTITION].dkl_cylno = spc() / spc(); 186 } 187 #endif /* defined(i386) */ 188 } 189 break; 190 case L_TYPE_EFI: 191 if (sel_type == 1) { 192 for (i = 0; i < cur_parts->etoc->efi_nparts; i++) { 193 cur_parts->etoc->efi_parts[i].p_start = 0; 194 cur_parts->etoc->efi_parts[i].p_size = 0; 195 } 196 } 197 break; 198 } 199 200 fmt_print("\n"); 201 if (cur_label == L_TYPE_SOLARIS) { 202 print_map(tmp_pinfo); 203 } else { 204 print_map(cur_parts); 205 } 206 207 ioparam.io_charlist = confirm_list; 208 if (input(FIO_MSTR, 209 "Do you wish to continue creating a new partition\ntable based on above table", 210 '?', &ioparam, &inpt_dflt, DATA_INPUT)) { 211 return (0); 212 } 213 214 /* 215 * get Free Hog partition 216 */ 217 inpt_dflt = 1; 218 while ((free_hog < 0) && (cur_label == L_TYPE_SOLARIS)) { 219 free_hog = G_PARTITION; /* default to g partition */ 220 ioparam.io_charlist = partn_list; 221 free_hog = input(FIO_MSTR, "Free Hog partition", '?', 222 &ioparam, &free_hog, DATA_INPUT); 223 /* disallow c partition */ 224 if (free_hog == C_PARTITION) { 225 fmt_print("'%c' cannot be the 'Free Hog' partition.\n", 226 C_PARTITION + PARTITION_BASE); 227 free_hog = -1; 228 continue; 229 } 230 /* 231 * If user selected all float set the 232 * float to be the whole disk. 233 */ 234 if (sel_type == 1) { 235 map[free_hog].dkl_nblk = map[C_PARTITION].dkl_nblk; 236 #if defined(i386) 237 map[free_hog].dkl_nblk -= map[I_PARTITION].dkl_nblk; 238 if (cur_ctype->ctype_ctype != DKC_SCSI_CCS) { 239 map[free_hog].dkl_nblk -= 240 map[J_PARTITION].dkl_nblk; 241 } 242 #endif /* defined(i386) */ 243 break; 244 } 245 /* 246 * Warn the user if there is no free space in 247 * the float partition. 248 */ 249 if (map[free_hog].dkl_nblk == 0) { 250 err_print("\ 251 Warning: No space available from Free Hog partition.\n"); 252 ioparam.io_charlist = confirm_list; 253 if (input(FIO_MSTR, "Continue", '?', 254 &ioparam, &inpt_dflt, DATA_INPUT)) { 255 free_hog = -1; 256 } 257 } 258 } 259 inpt_dflt = 0; 260 261 if (cur_label == L_TYPE_EFI) { 262 free_hog = G_PARTITION; /* default to g partition */ 263 ioparam.io_charlist = partn_list; 264 free_hog = input(FIO_MSTR, "Free Hog partition", '?', 265 &ioparam, &free_hog, DATA_INPUT); 266 /* disallow c partition */ 267 if (free_hog == C_PARTITION) { 268 fmt_print("'%c' cannot be the 'Free Hog' partition.\n", 269 C_PARTITION + PARTITION_BASE); 270 return (-1); 271 } 272 get_user_map_efi(cur_parts->etoc, free_hog); 273 print_map(cur_parts); 274 if (check("Ready to label disk, continue")) { 275 return (-1); 276 } 277 fmt_print("\n"); 278 if (write_label()) { 279 err_print("Writing label failed\n"); 280 return (-1); 281 } 282 return (0); 283 } 284 /* 285 * get user modified partition table 286 */ 287 get_user_map(map, free_hog); 288 289 /* 290 * Update cylno offsets 291 */ 292 adj_cyl_offset(map); 293 294 fmt_print("\n"); 295 print_map(tmp_pinfo); 296 297 ioparam.io_charlist = confirm_list; 298 if (input(FIO_MSTR, "\ 299 Okay to make this the current partition table", '?', 300 &ioparam, &inpt_dflt, DATA_INPUT)) { 301 return (0); 302 } else { 303 make_partition(); 304 /* 305 * Update new partition map 306 */ 307 for (i = 0; i < NDKMAP; i++) { 308 cur_parts->pinfo_map[i].dkl_nblk = map[i].dkl_nblk; 309 cur_parts->pinfo_map[i].dkl_cylno = map[i].dkl_cylno; 310 #ifdef i386 311 cur_parts->vtoc.v_part[i].p_start = 312 map[i].dkl_cylno * nhead * nsect; 313 cur_parts->vtoc.v_part[i].p_size = 314 map[i].dkl_nblk; 315 #endif 316 } 317 (void) p_name(); 318 319 /* 320 * Label the disk now 321 */ 322 if (check("Ready to label disk, continue")) { 323 return (-1); 324 } 325 fmt_print("\n"); 326 if (write_label()) { 327 err_print("Writing label failed\n"); 328 return (-1); 329 } 330 return (0); 331 } 332 } 333 334 335 336 /* 337 * Adjust cylinder offsets 338 */ 339 static void 340 adj_cyl_offset(map) 341 struct dk_map32 *map; 342 { 343 int i; 344 int cyloffset = 0; 345 346 347 /* 348 * Update cylno offsets 349 */ 350 351 #if defined(_SUNOS_VTOC_16) 352 /* 353 * Correct cylinder allocation for having the boot and alternates 354 * slice in the beginning of the disk 355 */ 356 for (i = NDKMAP/2; i < NDKMAP; i++) { 357 if (i != C_PARTITION && map[i].dkl_nblk) { 358 map[i].dkl_cylno = cyloffset; 359 cyloffset += (map[i].dkl_nblk + (spc()-1))/spc(); 360 } else if (map[i].dkl_nblk == 0) { 361 map[i].dkl_cylno = 0; 362 } 363 } 364 for (i = 0; i < NDKMAP/2; i++) { 365 366 #else /* !defined(_SUNOS_VTOC_16) */ 367 for (i = 0; i < NDKMAP; i++) { 368 #endif /* defined(_SUNOS_VTOC_16) */ 369 370 if (i != C_PARTITION && map[i].dkl_nblk) { 371 map[i].dkl_cylno = cyloffset; 372 cyloffset += (map[i].dkl_nblk + (spc()-1))/spc(); 373 } else if (map[i].dkl_nblk == 0) { 374 map[i].dkl_cylno = 0; 375 } 376 } 377 } 378 379 380 /* 381 * Check partition table 382 */ 383 static int 384 check_map(map) 385 struct dk_map32 *map; 386 { 387 int i; 388 int cyloffset = 0; 389 int tot_blks = 0; 390 391 #ifdef i386 392 /* 393 * On x86, we must account for the boot and alternates 394 */ 395 cyloffset = map[0].dkl_cylno; 396 tot_blks = map[0].dkl_nblk; 397 #endif 398 399 /* 400 * Do some checks for invalid parameters but do 401 * not modify the table. 402 */ 403 for (i = 0; i < NDKMAP; i++) { 404 if (map[i].dkl_cylno < 0 || 405 map[i].dkl_cylno > (daddr_t)ncyl-1) { 406 err_print("\ 407 Warning: Partition %c starting cylinder %d is out of range.\n", 408 (PARTITION_BASE+i), map[i].dkl_cylno); 409 return (-1); 410 } 411 if (map[i].dkl_nblk < 0 || map[i].dkl_nblk > (daddr_t)(ncyl - 412 map[i].dkl_cylno) * spc()) { 413 err_print("\ 414 Warning: Partition %c, specified # of blocks, %d, is out of range.\n", 415 (PARTITION_BASE+i), map[i].dkl_nblk); 416 return (-1); 417 } 418 if (i != C_PARTITION && map[i].dkl_nblk) { 419 #ifdef i386 420 if (i == I_PARTITION || i == J_PARTITION) 421 continue; 422 #endif 423 if (map[i].dkl_cylno < cyloffset) { 424 err_print( 425 "Warning: Overlapping partition (%c) in table.\n", PARTITION_BASE+i); 426 return (-1); 427 } else if (map[i].dkl_cylno > cyloffset) { 428 err_print( 429 "Warning: Non-contiguous partition (%c) in table.\n", PARTITION_BASE+i); 430 } 431 cyloffset += (map[i].dkl_nblk + (spc()-1))/spc(); 432 tot_blks = map[i].dkl_nblk; 433 } 434 } 435 if (tot_blks > map[C_PARTITION].dkl_nblk) { 436 err_print("\ 437 Warning: Total blocks used is greater than number of blocks in '%c'\n\ 438 \tpartition.\n", C_PARTITION + PARTITION_BASE); 439 return (-1); 440 } 441 return (0); 442 } 443 444 445 446 /* 447 * get user defined partitions 448 */ 449 static void 450 get_user_map(map, float_part) 451 struct dk_map32 *map; 452 int float_part; 453 { 454 int i; 455 int newsize; 456 int deflt; 457 char tmpstr[80]; 458 u_ioparam_t ioparam; 459 460 /* 461 * Get partition sizes 462 */ 463 for (i = 0; i < NDKMAP; i++) { 464 if (partn_list[i] == NULL) 465 break; 466 if ((i == C_PARTITION) || (i == float_part)) 467 continue; 468 else { 469 ioparam.io_bounds.lower = 0; 470 ioparam.io_bounds.upper = map[i].dkl_nblk + 471 map[float_part].dkl_nblk; 472 deflt = map[i].dkl_nblk; 473 if (ioparam.io_bounds.upper == 0) { 474 err_print("\ 475 Warning: no space available for '%s' from Free Hog partition\n", 476 partn_list[i]); 477 continue; 478 } 479 (void) snprintf(tmpstr, sizeof (tmpstr), 480 "Enter size of partition '%s' ", 481 partn_list[i]); 482 newsize = input(FIO_CYL, tmpstr, ':', 483 &ioparam, &deflt, DATA_INPUT); 484 map[float_part].dkl_nblk -= (newsize - map[i].dkl_nblk); 485 map[i].dkl_nblk = newsize; 486 } 487 } 488 } 489 490 static struct partition_info * 491 build_partition(tptr) 492 struct disk_type *tptr; 493 { 494 struct partition_info *part; 495 struct dk_label *label; 496 int i; 497 498 #ifdef DEBUG 499 fmt_print("Creating Default Partition for the disk \n"); 500 #endif 501 /* 502 * construct a label and pass it on to 503 * build_default_partition() which builds the 504 * default partition list. 505 */ 506 label = zalloc(sizeof (struct dk_label)); 507 label->dkl_pcyl = tptr->dtype_pcyl; 508 label->dkl_ncyl = tptr->dtype_ncyl; 509 label->dkl_acyl = tptr->dtype_acyl; 510 label->dkl_nhead = tptr->dtype_nhead; 511 label->dkl_nsect = tptr->dtype_nsect; 512 label->dkl_apc = apc; 513 label->dkl_intrlv = 1; 514 label->dkl_rpm = tptr->dtype_rpm; 515 516 if (!build_default_partition(label, cur_ctype->ctype_ctype)) 517 return (NULL); 518 519 part = (struct partition_info *) 520 zalloc(sizeof (struct partition_info)); 521 part->pinfo_name = alloc_string(tptr->dtype_asciilabel); 522 /* 523 * Fill in the partition info from the label 524 */ 525 for (i = 0; i < NDKMAP; i++) { 526 #if defined(_SUNOS_VTOC_8) 527 part->pinfo_map[i] = label->dkl_map[i]; 528 #else 529 part->pinfo_map[i].dkl_cylno = 530 label->dkl_vtoc.v_part[i].p_start / 531 ((int)(tptr->dtype_nhead * tptr->dtype_nsect - apc)); 532 part->pinfo_map[i].dkl_nblk = 533 label->dkl_vtoc.v_part[i].p_size; 534 #endif /* ifdefined(_SUNOS_VTOC_8) */ 535 } 536 part->vtoc = label->dkl_vtoc; 537 return (part); 538 } 539 540 /* 541 * build new partition table for given disk type 542 */ 543 static void 544 get_user_map_efi(map, float_part) 545 struct dk_gpt *map; 546 int float_part; 547 { 548 549 int i; 550 efi_deflt_t efi_deflt; 551 u_ioparam_t ioparam; 552 char tmpstr[80]; 553 uint64_t i64; 554 uint64_t start_lba = 34; 555 556 for (i = 0; i < map->efi_nparts - 1; i++) { 557 if (i == float_part) 558 continue; 559 else { 560 ioparam.io_bounds.lower = start_lba; 561 ioparam.io_bounds.upper = map->efi_last_u_lba; 562 efi_deflt.start_sector = ioparam.io_bounds.lower; 563 efi_deflt.end_sector = map->efi_parts[i].p_size; 564 (void) sprintf(tmpstr, 565 "Enter size of partition %d ", i); 566 i64 = input(FIO_EFI, tmpstr, ':', 567 &ioparam, (int *)&efi_deflt, DATA_INPUT); 568 if (i64 == 0) { 569 map->efi_parts[i].p_tag = V_UNASSIGNED; 570 } else if ((i64 != 0) && (map->efi_parts[i].p_tag == 571 V_UNASSIGNED)) { 572 map->efi_parts[i].p_tag = V_USR; 573 } 574 if (i64 == 0) { 575 map->efi_parts[i].p_start = 0; 576 } else { 577 map->efi_parts[i].p_start = start_lba; 578 } 579 map->efi_parts[i].p_size = i64; 580 start_lba += i64; 581 } 582 } 583 map->efi_parts[float_part].p_start = start_lba; 584 map->efi_parts[float_part].p_size = map->efi_last_u_lba - 585 start_lba - (1024 * 16); 586 map->efi_parts[float_part].p_tag = V_USR; 587 if (map->efi_parts[float_part].p_size == UINT_MAX64) { 588 map->efi_parts[float_part].p_size = 0; 589 map->efi_parts[float_part].p_start = 0; 590 map->efi_parts[float_part].p_tag = V_UNASSIGNED; 591 fmt_print("Warning: No space left for HOG\n"); 592 } 593 594 for (i = 0; i < map->efi_nparts; i++) { 595 if (map->efi_parts[i].p_tag == V_RESERVED) { 596 map->efi_parts[i].p_start = map->efi_last_u_lba - 597 (1024 * 16); 598 map->efi_parts[i].p_size = (1024 * 16); 599 break; 600 } 601 } 602 } 603 604 605 void 606 new_partitiontable(tptr, oldtptr) 607 struct disk_type *tptr, *oldtptr; 608 { 609 struct partition_info *part; 610 611 /* 612 * check if disk geometry has changed , if so add new 613 * partition table else copy the old partition table.(best guess). 614 */ 615 if ((oldtptr != NULL) && 616 (tptr->dtype_ncyl == oldtptr->dtype_ncyl) && 617 (tptr->dtype_nhead == oldtptr->dtype_nhead) && 618 (tptr->dtype_nsect == oldtptr->dtype_nsect)) { 619 620 part = (struct partition_info *) 621 zalloc(sizeof (struct partition_info)); 622 bcopy((char *)cur_parts, (char *)part, 623 sizeof (struct partition_info)); 624 part->pinfo_next = tptr->dtype_plist; 625 tptr->dtype_plist = part; 626 } else { 627 628 #ifdef DEBUG 629 if (cur_parts != NULL) { 630 fmt_print("Warning: Partition Table is set"); 631 fmt_print("to default partition table. \n"); 632 } 633 #endif 634 if (tptr->dtype_plist == NULL) { 635 part = (struct partition_info *)build_partition(tptr); 636 if (part != NULL) { 637 part->pinfo_next = tptr->dtype_plist; 638 tptr->dtype_plist = part; 639 } 640 } 641 } 642 } 643