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 that operate on partition tables. 28 */ 29 #include <string.h> 30 #include <stdlib.h> 31 #include "global.h" 32 #include "partition.h" 33 #include "misc.h" 34 #include "menu_command.h" 35 #include "menu_partition.h" 36 37 38 /* 39 * Default vtoc information for non-SVr4 partitions 40 */ 41 struct dk_map2 default_vtoc_map[NDKMAP] = { 42 { V_ROOT, 0 }, /* a - 0 */ 43 { V_SWAP, V_UNMNT }, /* b - 1 */ 44 { V_BACKUP, V_UNMNT }, /* c - 2 */ 45 { V_UNASSIGNED, 0 }, /* d - 3 */ 46 { V_UNASSIGNED, 0 }, /* e - 4 */ 47 { V_UNASSIGNED, 0 }, /* f - 5 */ 48 { V_USR, 0 }, /* g - 6 */ 49 { V_UNASSIGNED, 0 }, /* h - 7 */ 50 51 #if defined(_SUNOS_VTOC_16) 52 53 #if defined(i386) 54 { V_BOOT, V_UNMNT }, /* i - 8 */ 55 { V_ALTSCTR, 0 }, /* j - 9 */ 56 57 #else 58 #error No VTOC format defined. 59 #endif /* defined(i386) */ 60 61 { V_UNASSIGNED, 0 }, /* k - 10 */ 62 { V_UNASSIGNED, 0 }, /* l - 11 */ 63 { V_UNASSIGNED, 0 }, /* m - 12 */ 64 { V_UNASSIGNED, 0 }, /* n - 13 */ 65 { V_UNASSIGNED, 0 }, /* o - 14 */ 66 { V_UNASSIGNED, 0 }, /* p - 15 */ 67 #endif /* defined(_SUNOS_VTOC_16) */ 68 }; 69 70 /* 71 * This routine finds the last usable sector in the partition table. 72 * It skips the BACKUP partition. 73 */ 74 static uint64_t 75 maxofN(struct dk_gpt *map) 76 { 77 uint64_t max; 78 uint64_t sec_no[2], start[2], size[2]; 79 int i; 80 81 for (i = 0; i < map->efi_nparts - 1; i++) { 82 start[0] = map->efi_parts[i].p_start; 83 size[0] = map->efi_parts[i].p_size; 84 sec_no[0] = start[0] + size[0]; 85 86 start[1] = map->efi_parts[i+1].p_start; 87 size[1] = map->efi_parts[i+1].p_size; 88 sec_no[1] = start[1] + size[1]; 89 90 if (map->efi_parts[i].p_tag == V_BACKUP) { 91 sec_no[0] = 0; 92 } 93 if (map->efi_parts[i+1].p_tag == V_BACKUP) { 94 sec_no[1] = 0; 95 } 96 if (i == 0) { 97 max = sec_no[1]; 98 } 99 if (sec_no[0] > max) { 100 max = sec_no[0]; 101 } else { 102 max = max; 103 } 104 } 105 if (max == 0) 106 max = 34; 107 return (max); 108 } 109 110 /* 111 * This routine allows the user to change the boundaries of the given 112 * partition in the current partition map. 113 */ 114 void 115 change_partition(int num) 116 { 117 uint_t i; 118 uint64_t i64, j64; 119 uint_t j; 120 int deflt; 121 part_deflt_t p_deflt; 122 u_ioparam_t ioparam; 123 int tag; 124 int flag; 125 char msg[256]; 126 blkaddr32_t cyl_offset = 0; 127 efi_deflt_t efi_deflt; 128 129 /* 130 * check if there exists a partition table for the disk. 131 */ 132 if (cur_parts == NULL) { 133 err_print("Current Disk has no partition table.\n"); 134 return; 135 } 136 137 if (cur_label == L_TYPE_EFI) { 138 if (num > cur_parts->etoc->efi_nparts - 1) { 139 err_print("Invalid partition for EFI label\n"); 140 return; 141 } 142 print_efi_partition(cur_parts->etoc, num, 1); 143 fmt_print("\n"); 144 /* 145 * Prompt for p_tag and p_flag values for this partition 146 */ 147 deflt = cur_parts->etoc->efi_parts[num].p_tag; 148 if (deflt == V_UNASSIGNED) { 149 deflt = V_USR; 150 } 151 (void) sprintf(msg, "Enter partition id tag"); 152 ioparam.io_slist = ptag_choices; 153 tag = input(FIO_SLIST, msg, ':', &ioparam, &deflt, DATA_INPUT); 154 155 deflt = cur_parts->etoc->efi_parts[num].p_flag; 156 (void) sprintf(msg, "Enter partition permission flags"); 157 ioparam.io_slist = pflag_choices; 158 flag = input(FIO_SLIST, msg, ':', &ioparam, &deflt, DATA_INPUT); 159 160 ioparam.io_bounds.lower = 34; 161 ioparam.io_bounds.upper = cur_parts->etoc->efi_last_u_lba; 162 163 efi_deflt.start_sector = maxofN(cur_parts->etoc); 164 if ((cur_parts->etoc->efi_parts[num].p_start != 0) && 165 (cur_parts->etoc->efi_parts[num].p_size != 0)) { 166 efi_deflt.start_sector = 167 cur_parts->etoc->efi_parts[num].p_start; 168 } 169 efi_deflt.end_sector = ioparam.io_bounds.upper - 170 efi_deflt.start_sector; 171 i64 = input(FIO_INT64, "Enter new starting Sector", ':', &ioparam, 172 (int *)&efi_deflt, DATA_INPUT); 173 174 ioparam.io_bounds.lower = 0; 175 ioparam.io_bounds.upper = cur_parts->etoc->efi_last_u_lba; 176 efi_deflt.end_sector = cur_parts->etoc->efi_parts[num].p_size; 177 efi_deflt.start_sector = i64; 178 j64 = input(FIO_EFI, "Enter partition size", ':', &ioparam, 179 (int *)&efi_deflt, DATA_INPUT); 180 if (j64 == 0) { 181 tag = V_UNASSIGNED; 182 i64 = 0; 183 } else if ((j64 != 0) && (tag == V_UNASSIGNED)) { 184 tag = V_USR; 185 } 186 187 if (cur_parts->pinfo_name != NULL) 188 make_partition(); 189 190 cur_parts->etoc->efi_parts[num].p_tag = tag; 191 cur_parts->etoc->efi_parts[num].p_flag = flag; 192 cur_parts->etoc->efi_parts[num].p_start = i64; 193 cur_parts->etoc->efi_parts[num].p_size = j64; 194 /* 195 * We are now done with EFI part, so return now 196 */ 197 return; 198 } 199 /* 200 * Print out the given partition so the user knows what he/she's 201 * getting into. 202 */ 203 print_partition(cur_parts, num, 1); 204 fmt_print("\n"); 205 206 /* 207 * Prompt for p_tag and p_flag values for this partition. 208 */ 209 assert(cur_parts->vtoc.v_version == V_VERSION); 210 deflt = cur_parts->vtoc.v_part[num].p_tag; 211 (void) sprintf(msg, "Enter partition id tag"); 212 ioparam.io_slist = ptag_choices; 213 tag = input(FIO_SLIST, msg, ':', &ioparam, &deflt, DATA_INPUT); 214 215 deflt = cur_parts->vtoc.v_part[num].p_flag; 216 (void) sprintf(msg, "Enter partition permission flags"); 217 ioparam.io_slist = pflag_choices; 218 flag = input(FIO_SLIST, msg, ':', &ioparam, &deflt, DATA_INPUT); 219 220 /* 221 * Ask for the new values. The old values are the defaults, and 222 * strict bounds checking is done on the values given. 223 */ 224 225 #if defined(i386) 226 227 if (tag != V_UNASSIGNED && tag != V_BACKUP && tag != V_BOOT) { 228 /* 229 * Determine cyl offset for boot and alternate partitions. 230 * Assuming that the alternate sectors partition (slice) 231 * physical location immediately follows the boot 232 * partition and partition sizes are expressed in multiples 233 * of cylinder size. 234 */ 235 cyl_offset = cur_parts->pinfo_map[I_PARTITION].dkl_cylno + 1; 236 if (tag != V_ALTSCTR) { 237 if (cur_parts->pinfo_map[J_PARTITION].dkl_nblk != 0) { 238 cyl_offset = 239 cur_parts->pinfo_map[J_PARTITION].dkl_cylno + 240 ((cur_parts->pinfo_map[J_PARTITION].dkl_nblk + 241 (spc()-1)) / spc()); 242 } 243 } 244 } 245 #endif /* defined(i386) */ 246 247 ioparam.io_bounds.lower = 0; 248 ioparam.io_bounds.upper = ncyl - 1; 249 deflt = max(cur_parts->pinfo_map[num].dkl_cylno, 250 cyl_offset); 251 i = (uint_t)input(FIO_INT, "Enter new starting cyl", ':', &ioparam, 252 &deflt, DATA_INPUT); 253 254 ioparam.io_bounds.lower = 0; 255 ioparam.io_bounds.upper = (ncyl - i) * spc(); 256 257 /* fill in defaults for the current partition */ 258 p_deflt.start_cyl = i; 259 p_deflt.deflt_size = 260 min(cur_parts->pinfo_map[num].dkl_nblk, 261 ioparam.io_bounds.upper); 262 263 /* call input, passing p_deflt's address, typecast to (int *) */ 264 j = (uint_t)input(FIO_ECYL, "Enter partition size", ':', &ioparam, 265 (int *)&p_deflt, DATA_INPUT); 266 267 /* 268 * If the current partition has a size of zero change the 269 * tag to Unassigned and the starting cylinder to zero 270 */ 271 272 if (j == 0) { 273 tag = V_UNASSIGNED; 274 i = 0; 275 } 276 277 278 #if defined(i386) 279 280 if (i < cyl_offset && tag != V_UNASSIGNED && tag != V_BACKUP && 281 tag != V_BOOT) { 282 /* 283 * This slice overlaps boot and/or alternates slice 284 * Check if it's the boot or alternates slice and warn 285 * accordingly 286 */ 287 if (i < cur_parts->pinfo_map[I_PARTITION].dkl_cylno + 1) { 288 fmt_print("\nWarning: Partition overlaps boot "); 289 fmt_print("partition. Specify different start cyl.\n"); 290 return; 291 } 292 /* 293 * Cyl offset for alternates partition was calculated before 294 */ 295 if (i < cyl_offset) { 296 fmt_print("\nWarning: Partition overlaps alternates "); 297 fmt_print("partition. Specify different start cyl.\n"); 298 return; 299 } 300 } 301 302 #endif /* defined(i386) */ 303 304 /* 305 * If user has entered a V_BACKUP tag then the partition 306 * size should specify full disk capacity else 307 * return an Error. 308 */ 309 if (tag == V_BACKUP) { 310 uint_t fullsz; 311 312 fullsz = ncyl * nhead * nsect; 313 if (fullsz != j) { 314 /* 315 * V_BACKUP Tag Partition != full disk capacity. 316 * print useful messages. 317 */ 318 fmt_print("\nWarning: Partition with V_BACKUP tag should "); 319 fmt_print("specify full disk capacity. \n"); 320 return; 321 } 322 } 323 324 325 /* 326 * If the current partition is named, we can't change it. 327 * We create a new current partition map instead. 328 */ 329 if (cur_parts->pinfo_name != NULL) 330 make_partition(); 331 /* 332 * Change the values. 333 */ 334 cur_parts->pinfo_map[num].dkl_cylno = i; 335 cur_parts->pinfo_map[num].dkl_nblk = j; 336 337 #if defined(_SUNOS_VTOC_16) 338 cur_parts->vtoc.v_part[num].p_start = (daddr_t)(i * (nhead * nsect)); 339 cur_parts->vtoc.v_part[num].p_size = (long)j; 340 #endif /* defined(_SUNOS_VTOC_16) */ 341 342 /* 343 * Install the p_tag and p_flag values for this partition 344 */ 345 assert(cur_parts->vtoc.v_version == V_VERSION); 346 cur_parts->vtoc.v_part[num].p_tag = (ushort_t)tag; 347 cur_parts->vtoc.v_part[num].p_flag = (ushort_t)flag; 348 } 349 350 351 /* 352 * This routine picks to closest partition table which matches the 353 * selected disk type. It is called each time the disk type is 354 * changed. If no match is found, it uses the first element 355 * of the partition table. If no table exists, a dummy is 356 * created. 357 */ 358 int 359 get_partition() 360 { 361 register struct partition_info *pptr; 362 register struct partition_info *parts; 363 364 /* 365 * If there are no pre-defined maps for this disk type, it's 366 * an error. 367 */ 368 parts = cur_dtype->dtype_plist; 369 if (parts == NULL) { 370 err_print("No defined partition tables.\n"); 371 make_partition(); 372 return (-1); 373 } 374 /* 375 * Loop through the pre-defined maps searching for one which match 376 * disk type. If found copy it into unmamed partition. 377 */ 378 enter_critical(); 379 for (pptr = parts; pptr != NULL; pptr = pptr->pinfo_next) { 380 if (cur_dtype->dtype_asciilabel) { 381 if (pptr->pinfo_name != NULL && strcmp(pptr->pinfo_name, 382 cur_dtype->dtype_asciilabel) == 0) { 383 /* 384 * Set current partition and name it. 385 */ 386 cur_disk->disk_parts = cur_parts = pptr; 387 cur_parts->pinfo_name = pptr->pinfo_name; 388 exit_critical(); 389 return (0); 390 } 391 } 392 } 393 /* 394 * If we couldn't find a match, take the first one. 395 * Set current partition and name it. 396 */ 397 cur_disk->disk_parts = cur_parts = cur_dtype->dtype_plist; 398 cur_parts->pinfo_name = parts->pinfo_name; 399 exit_critical(); 400 return (0); 401 } 402 403 404 /* 405 * This routine creates a new partition map and sets it current. If there 406 * was a current map, the new map starts out identical to it. Otherwise 407 * the new map starts out all zeroes. 408 */ 409 void 410 make_partition() 411 { 412 register struct partition_info *pptr, *parts; 413 int i; 414 415 /* 416 * Lock out interrupts so the lists don't get mangled. 417 */ 418 enter_critical(); 419 /* 420 * Get space for for the new map and link it into the list 421 * of maps for the current disk type. 422 */ 423 pptr = (struct partition_info *)zalloc(sizeof (struct partition_info)); 424 parts = cur_dtype->dtype_plist; 425 if (parts == NULL) { 426 cur_dtype->dtype_plist = pptr; 427 } else { 428 while (parts->pinfo_next != NULL) { 429 parts = parts->pinfo_next; 430 } 431 parts->pinfo_next = pptr; 432 pptr->pinfo_next = NULL; 433 } 434 /* 435 * If there was a current map, copy its values. 436 */ 437 if (cur_label == L_TYPE_EFI) { 438 struct dk_gpt *map; 439 int nparts; 440 int size; 441 442 nparts = cur_parts->etoc->efi_nparts; 443 size = sizeof (struct dk_part) * nparts + sizeof (struct dk_gpt); 444 map = zalloc(size); 445 (void) memcpy(map, cur_parts->etoc, size); 446 pptr->etoc = map; 447 cur_disk->disk_parts = cur_parts = pptr; 448 exit_critical(); 449 return; 450 } 451 if (cur_parts != NULL) { 452 for (i = 0; i < NDKMAP; i++) { 453 pptr->pinfo_map[i] = cur_parts->pinfo_map[i]; 454 } 455 pptr->vtoc = cur_parts->vtoc; 456 } else { 457 /* 458 * Otherwise set initial default vtoc values 459 */ 460 set_vtoc_defaults(pptr); 461 } 462 463 /* 464 * Make the new one current. 465 */ 466 cur_disk->disk_parts = cur_parts = pptr; 467 exit_critical(); 468 } 469 470 471 /* 472 * This routine deletes a partition map from the list of maps for 473 * the given disk type. 474 */ 475 void 476 delete_partition(struct partition_info *parts) 477 { 478 struct partition_info *pptr; 479 480 /* 481 * If there isn't a current map, it's an error. 482 */ 483 if (cur_dtype->dtype_plist == NULL) { 484 err_print("Error: unexpected null partition list.\n"); 485 fullabort(); 486 } 487 /* 488 * Remove the map from the list. 489 */ 490 if (cur_dtype->dtype_plist == parts) 491 cur_dtype->dtype_plist = parts->pinfo_next; 492 else { 493 for (pptr = cur_dtype->dtype_plist; pptr->pinfo_next != parts; 494 pptr = pptr->pinfo_next) 495 ; 496 pptr->pinfo_next = parts->pinfo_next; 497 } 498 /* 499 * Free the space it was using. 500 */ 501 destroy_data((char *)parts); 502 } 503 504 505 /* 506 * Set all partition vtoc fields to defaults 507 */ 508 void 509 set_vtoc_defaults(struct partition_info *part) 510 { 511 int i; 512 513 bzero((caddr_t)&part->vtoc, sizeof (struct dk_vtoc)); 514 515 part->vtoc.v_version = V_VERSION; 516 part->vtoc.v_nparts = NDKMAP; 517 part->vtoc.v_sanity = VTOC_SANE; 518 519 for (i = 0; i < NDKMAP; i++) { 520 part->vtoc.v_part[i].p_tag = default_vtoc_map[i].p_tag; 521 part->vtoc.v_part[i].p_flag = default_vtoc_map[i].p_flag; 522 } 523 } 524