installboot: fix stage2 size check for MBR
[unleashed.git] / usr / src / cmd / format / partition.c
blob3d06272904da3997e3c1d1a4f55cd44286aa85d4
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
27 * This file contains functions that operate on partition tables.
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"
39 * Default vtoc information for non-SVr4 partitions
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 */
51 #if defined(_SUNOS_VTOC_16)
53 #if defined(i386)
54 { V_BOOT, V_UNMNT }, /* i - 8 */
55 { V_ALTSCTR, 0 }, /* j - 9 */
57 #else
58 #error No VTOC format defined.
59 #endif /* defined(i386) */
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) */
71 * This routine finds the last usable sector in the partition table.
72 * It skips the BACKUP partition.
74 static uint64_t
75 maxofN(struct dk_gpt *map)
77 uint64_t max;
78 uint64_t sec_no[2], start[2], size[2];
79 int i;
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];
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];
90 if (map->efi_parts[i].p_tag == V_BACKUP) {
91 sec_no[0] = 0;
93 if (map->efi_parts[i+1].p_tag == V_BACKUP) {
94 sec_no[1] = 0;
96 if (i == 0) {
97 max = sec_no[1];
99 if (sec_no[0] > max) {
100 max = sec_no[0];
101 } else {
102 max = max;
105 if (max == 0)
106 max = 34;
107 return (max);
111 * This routine allows the user to change the boundaries of the given
112 * partition in the current partition map.
114 void
115 change_partition(int num)
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;
130 * check if there exists a partition table for the disk.
132 if (cur_parts == NULL) {
133 err_print("Current Disk has no partition table.\n");
134 return;
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;
142 print_efi_partition(cur_parts->etoc, num, 1);
143 fmt_print("\n");
145 * Prompt for p_tag and p_flag values for this partition
147 deflt = cur_parts->etoc->efi_parts[num].p_tag;
148 if (deflt == V_UNASSIGNED) {
149 deflt = V_USR;
151 (void) sprintf(msg, "Enter partition id tag");
152 ioparam.io_slist = ptag_choices;
153 tag = input(FIO_SLIST, msg, ':', &ioparam, &deflt, DATA_INPUT);
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);
160 ioparam.io_bounds.lower = 34;
161 ioparam.io_bounds.upper = cur_parts->etoc->efi_last_u_lba;
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;
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);
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;
187 if (cur_parts->pinfo_name != NULL)
188 make_partition();
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;
195 * We are now done with EFI part, so return now
197 return;
200 * Print out the given partition so the user knows what he/she's
201 * getting into.
203 print_partition(cur_parts, num, 1);
204 fmt_print("\n");
207 * Prompt for p_tag and p_flag values for this partition.
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);
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);
221 * Ask for the new values. The old values are the defaults, and
222 * strict bounds checking is done on the values given.
225 #if defined(i386)
227 if (tag != V_UNASSIGNED && tag != V_BACKUP && tag != V_BOOT) {
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.
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());
245 #endif /* defined(i386) */
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);
254 ioparam.io_bounds.lower = 0;
255 ioparam.io_bounds.upper = (ncyl - i) * spc();
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);
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);
268 * If the current partition has a size of zero change the
269 * tag to Unassigned and the starting cylinder to zero
272 if (j == 0) {
273 tag = V_UNASSIGNED;
274 i = 0;
278 #if defined(i386)
280 if (i < cyl_offset && tag != V_UNASSIGNED && tag != V_BACKUP &&
281 tag != V_BOOT) {
283 * This slice overlaps boot and/or alternates slice
284 * Check if it's the boot or alternates slice and warn
285 * accordingly
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;
293 * Cyl offset for alternates partition was calculated before
295 if (i < cyl_offset) {
296 fmt_print("\nWarning: Partition overlaps alternates ");
297 fmt_print("partition. Specify different start cyl.\n");
298 return;
302 #endif /* defined(i386) */
305 * If user has entered a V_BACKUP tag then the partition
306 * size should specify full disk capacity else
307 * return an Error.
309 if (tag == V_BACKUP) {
310 uint_t fullsz;
312 fullsz = ncyl * nhead * nsect;
313 if (fullsz != j) {
315 * V_BACKUP Tag Partition != full disk capacity.
316 * print useful messages.
318 fmt_print("\nWarning: Partition with V_BACKUP tag should ");
319 fmt_print("specify full disk capacity. \n");
320 return;
326 * If the current partition is named, we can't change it.
327 * We create a new current partition map instead.
329 if (cur_parts->pinfo_name != NULL)
330 make_partition();
332 * Change the values.
334 cur_parts->pinfo_map[num].dkl_cylno = i;
335 cur_parts->pinfo_map[num].dkl_nblk = j;
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) */
343 * Install the p_tag and p_flag values for this partition
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;
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.
359 get_partition()
361 register struct partition_info *pptr;
362 register struct partition_info *parts;
365 * If there are no pre-defined maps for this disk type, it's
366 * an error.
368 parts = cur_dtype->dtype_plist;
369 if (parts == NULL) {
370 err_print("No defined partition tables.\n");
371 make_partition();
372 return (-1);
375 * Loop through the pre-defined maps searching for one which match
376 * disk type. If found copy it into unmamed partition.
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) {
384 * Set current partition and name it.
386 cur_disk->disk_parts = cur_parts = pptr;
387 cur_parts->pinfo_name = pptr->pinfo_name;
388 exit_critical();
389 return (0);
394 * If we couldn't find a match, take the first one.
395 * Set current partition and name it.
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);
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.
409 void
410 make_partition()
412 register struct partition_info *pptr, *parts;
413 int i;
416 * Lock out interrupts so the lists don't get mangled.
418 enter_critical();
420 * Get space for for the new map and link it into the list
421 * of maps for the current disk type.
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;
431 parts->pinfo_next = pptr;
432 pptr->pinfo_next = NULL;
435 * If there was a current map, copy its values.
437 if (cur_label == L_TYPE_EFI) {
438 struct dk_gpt *map;
439 int nparts;
440 int size;
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;
451 if (cur_parts != NULL) {
452 for (i = 0; i < NDKMAP; i++) {
453 pptr->pinfo_map[i] = cur_parts->pinfo_map[i];
455 pptr->vtoc = cur_parts->vtoc;
456 } else {
458 * Otherwise set initial default vtoc values
460 set_vtoc_defaults(pptr);
464 * Make the new one current.
466 cur_disk->disk_parts = cur_parts = pptr;
467 exit_critical();
472 * This routine deletes a partition map from the list of maps for
473 * the given disk type.
475 void
476 delete_partition(struct partition_info *parts)
478 struct partition_info *pptr;
481 * If there isn't a current map, it's an error.
483 if (cur_dtype->dtype_plist == NULL) {
484 err_print("Error: unexpected null partition list.\n");
485 fullabort();
488 * Remove the map from the list.
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)
496 pptr->pinfo_next = parts->pinfo_next;
499 * Free the space it was using.
501 destroy_data((char *)parts);
506 * Set all partition vtoc fields to defaults
508 void
509 set_vtoc_defaults(struct partition_info *part)
511 int i;
513 bzero((caddr_t)&part->vtoc, sizeof (struct dk_vtoc));
515 part->vtoc.v_version = V_VERSION;
516 part->vtoc.v_nparts = NDKMAP;
517 part->vtoc.v_sanity = VTOC_SANE;
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;