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