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]
23 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
27 * This file contains functions that operate on partition tables.
32 #include "partition.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)
54 { V_BOOT
, V_UNMNT
}, /* i - 8 */
55 { V_ALTSCTR
, 0 }, /* j - 9 */
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.
75 maxofN(struct dk_gpt
*map
)
78 uint64_t sec_no
[2], start
[2], size
[2];
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
) {
93 if (map
->efi_parts
[i
+1].p_tag
== V_BACKUP
) {
99 if (sec_no
[0] > max
) {
111 * This routine allows the user to change the boundaries of the given
112 * partition in the current partition map.
115 change_partition(int num
)
121 part_deflt_t p_deflt
;
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");
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");
142 print_efi_partition(cur_parts
->etoc
, num
, 1);
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
) {
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
);
183 } else if ((j64
!= 0) && (tag
== V_UNASSIGNED
)) {
187 if (cur_parts
->pinfo_name
!= NULL
)
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
200 * Print out the given partition so the user knows what he/she's
203 print_partition(cur_parts
, num
, 1);
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.
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
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) {
239 cur_parts
->pinfo_map
[J_PARTITION
].dkl_cylno
+
240 ((cur_parts
->pinfo_map
[J_PARTITION
].dkl_nblk
+
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
,
251 i
= (uint_t
)input(FIO_INT
, "Enter new starting cyl", ':', &ioparam
,
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
;
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
280 if (i
< cyl_offset
&& tag
!= V_UNASSIGNED
&& tag
!= V_BACKUP
&&
283 * This slice overlaps boot and/or alternates slice
284 * Check if it's the boot or alternates slice and warn
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");
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");
302 #endif /* defined(i386) */
305 * If user has entered a V_BACKUP tag then the partition
306 * size should specify full disk capacity else
309 if (tag
== V_BACKUP
) {
312 fullsz
= ncyl
* nhead
* nsect
;
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");
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
)
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
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
368 parts
= cur_dtype
->dtype_plist
;
370 err_print("No defined partition tables.\n");
375 * Loop through the pre-defined maps searching for one which match
376 * disk type. If found copy it into unmamed partition.
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
;
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
;
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.
412 register struct partition_info
*pptr
, *parts
;
416 * Lock out interrupts so the lists don't get mangled.
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
;
426 cur_dtype
->dtype_plist
= pptr
;
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
) {
442 nparts
= cur_parts
->etoc
->efi_nparts
;
443 size
= sizeof (struct dk_part
) * nparts
+ sizeof (struct dk_gpt
);
445 (void) memcpy(map
, cur_parts
->etoc
, size
);
447 cur_disk
->disk_parts
= cur_parts
= pptr
;
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
;
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
;
472 * This routine deletes a partition map from the list of maps for
473 * the given disk type.
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");
488 * Remove the map from the list.
490 if (cur_dtype
->dtype_plist
== parts
)
491 cur_dtype
->dtype_plist
= parts
->pinfo_next
;
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
509 set_vtoc_defaults(struct partition_info
*part
)
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
;