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