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