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