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