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