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.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
28 * This file contains functions that operate on partition tables.
33 #include "partition.h"
35 #include "menu_command.h"
36 #include "menu_partition.h"
40 * Default vtoc information for non-SVr4 partitions
42 struct dk_map2 default_vtoc_map
[NDKMAP
] = {
43 { V_ROOT
, 0 }, /* a - 0 */
44 { V_SWAP
, V_UNMNT
}, /* b - 1 */
45 { V_BACKUP
, V_UNMNT
}, /* c - 2 */
46 { V_UNASSIGNED
, 0 }, /* d - 3 */
47 { V_UNASSIGNED
, 0 }, /* e - 4 */
48 { V_UNASSIGNED
, 0 }, /* f - 5 */
49 { V_USR
, 0 }, /* g - 6 */
50 { V_UNASSIGNED
, 0 }, /* h - 7 */
52 #if defined(_SUNOS_VTOC_16)
55 { V_BOOT
, V_UNMNT
}, /* i - 8 */
56 { V_ALTSCTR
, 0 }, /* j - 9 */
59 #error No VTOC format defined.
60 #endif /* defined(i386) */
62 { V_UNASSIGNED
, 0 }, /* k - 10 */
63 { V_UNASSIGNED
, 0 }, /* l - 11 */
64 { V_UNASSIGNED
, 0 }, /* m - 12 */
65 { V_UNASSIGNED
, 0 }, /* n - 13 */
66 { V_UNASSIGNED
, 0 }, /* o - 14 */
67 { V_UNASSIGNED
, 0 }, /* p - 15 */
68 #endif /* defined(_SUNOS_VTOC_16) */
72 * This routine finds the last usable sector in the partition table.
73 * It skips the BACKUP partition.
76 maxofN(struct dk_gpt
*map
)
79 uint64_t sec_no
[2], start
[2], size
[2];
82 for (i
= 0; i
< map
->efi_nparts
- 1; i
++) {
83 start
[0] = map
->efi_parts
[i
].p_start
;
84 size
[0] = map
->efi_parts
[i
].p_size
;
85 sec_no
[0] = start
[0] + size
[0];
87 start
[1] = map
->efi_parts
[i
+1].p_start
;
88 size
[1] = map
->efi_parts
[i
+1].p_size
;
89 sec_no
[1] = start
[1] + size
[1];
91 if (map
->efi_parts
[i
].p_tag
== V_BACKUP
) {
94 if (map
->efi_parts
[i
+1].p_tag
== V_BACKUP
) {
100 if (sec_no
[0] > max
) {
112 * This routine allows the user to change the boundaries of the given
113 * partition in the current partition map.
116 change_partition(int num
)
122 part_deflt_t p_deflt
;
127 blkaddr32_t cyl_offset
= 0;
128 efi_deflt_t efi_deflt
;
131 * check if there exists a partition table for the disk.
133 if (cur_parts
== NULL
) {
134 err_print("Current Disk has no partition table.\n");
138 if (cur_label
== L_TYPE_EFI
) {
139 if (num
> cur_parts
->etoc
->efi_nparts
- 1) {
140 err_print("Invalid partition for EFI label\n");
143 print_efi_partition(cur_parts
->etoc
, num
, 1);
146 * Prompt for p_tag and p_flag values for this partition
148 deflt
= cur_parts
->etoc
->efi_parts
[num
].p_tag
;
149 if (deflt
== V_UNASSIGNED
) {
152 (void) sprintf(msg
, "Enter partition id tag");
153 ioparam
.io_slist
= ptag_choices
;
154 tag
= input(FIO_SLIST
, msg
, ':', &ioparam
, &deflt
, DATA_INPUT
);
156 deflt
= cur_parts
->etoc
->efi_parts
[num
].p_flag
;
157 (void) sprintf(msg
, "Enter partition permission flags");
158 ioparam
.io_slist
= pflag_choices
;
159 flag
= input(FIO_SLIST
, msg
, ':', &ioparam
, &deflt
, DATA_INPUT
);
161 ioparam
.io_bounds
.lower
= 34;
162 ioparam
.io_bounds
.upper
= cur_parts
->etoc
->efi_last_u_lba
;
164 efi_deflt
.start_sector
= maxofN(cur_parts
->etoc
);
165 if ((cur_parts
->etoc
->efi_parts
[num
].p_start
!= 0) &&
166 (cur_parts
->etoc
->efi_parts
[num
].p_size
!= 0)) {
167 efi_deflt
.start_sector
=
168 cur_parts
->etoc
->efi_parts
[num
].p_start
;
170 efi_deflt
.end_sector
= ioparam
.io_bounds
.upper
-
171 efi_deflt
.start_sector
;
172 i64
= input(FIO_INT64
, "Enter new starting Sector", ':', &ioparam
,
173 (int *)&efi_deflt
, DATA_INPUT
);
175 ioparam
.io_bounds
.lower
= 0;
176 ioparam
.io_bounds
.upper
= cur_parts
->etoc
->efi_last_u_lba
;
177 efi_deflt
.end_sector
= cur_parts
->etoc
->efi_parts
[num
].p_size
;
178 efi_deflt
.start_sector
= i64
;
179 j64
= input(FIO_EFI
, "Enter partition size", ':', &ioparam
,
180 (int *)&efi_deflt
, DATA_INPUT
);
184 } else if ((j64
!= 0) && (tag
== V_UNASSIGNED
)) {
188 if (cur_parts
->pinfo_name
!= NULL
)
191 cur_parts
->etoc
->efi_parts
[num
].p_tag
= tag
;
192 cur_parts
->etoc
->efi_parts
[num
].p_flag
= flag
;
193 cur_parts
->etoc
->efi_parts
[num
].p_start
= i64
;
194 cur_parts
->etoc
->efi_parts
[num
].p_size
= j64
;
196 * We are now done with EFI part, so return now
201 * Print out the given partition so the user knows what they're
204 print_partition(cur_parts
, num
, 1);
208 * Prompt for p_tag and p_flag values for this partition.
210 assert(cur_parts
->vtoc
.v_version
== V_VERSION
);
211 deflt
= cur_parts
->vtoc
.v_part
[num
].p_tag
;
212 (void) sprintf(msg
, "Enter partition id tag");
213 ioparam
.io_slist
= ptag_choices
;
214 tag
= input(FIO_SLIST
, msg
, ':', &ioparam
, &deflt
, DATA_INPUT
);
216 deflt
= cur_parts
->vtoc
.v_part
[num
].p_flag
;
217 (void) sprintf(msg
, "Enter partition permission flags");
218 ioparam
.io_slist
= pflag_choices
;
219 flag
= input(FIO_SLIST
, msg
, ':', &ioparam
, &deflt
, DATA_INPUT
);
222 * Ask for the new values. The old values are the defaults, and
223 * strict bounds checking is done on the values given.
228 if (tag
!= V_UNASSIGNED
&& tag
!= V_BACKUP
&& tag
!= V_BOOT
) {
230 * Determine cyl offset for boot and alternate partitions.
231 * Assuming that the alternate sectors partition (slice)
232 * physical location immediately follows the boot
233 * partition and partition sizes are expressed in multiples
236 cyl_offset
= cur_parts
->pinfo_map
[I_PARTITION
].dkl_cylno
+ 1;
237 if (tag
!= V_ALTSCTR
) {
238 if (cur_parts
->pinfo_map
[J_PARTITION
].dkl_nblk
!= 0) {
240 cur_parts
->pinfo_map
[J_PARTITION
].dkl_cylno
+
241 ((cur_parts
->pinfo_map
[J_PARTITION
].dkl_nblk
+
246 #endif /* defined(i386) */
248 ioparam
.io_bounds
.lower
= 0;
249 ioparam
.io_bounds
.upper
= ncyl
- 1;
250 deflt
= max(cur_parts
->pinfo_map
[num
].dkl_cylno
,
252 i
= (uint_t
)input(FIO_INT
, "Enter new starting cyl", ':', &ioparam
,
255 ioparam
.io_bounds
.lower
= 0;
256 ioparam
.io_bounds
.upper
= (ncyl
- i
) * spc();
258 /* fill in defaults for the current partition */
259 p_deflt
.start_cyl
= i
;
261 min(cur_parts
->pinfo_map
[num
].dkl_nblk
,
262 ioparam
.io_bounds
.upper
);
264 /* call input, passing p_deflt's address, typecast to (int *) */
265 j
= (uint_t
)input(FIO_ECYL
, "Enter partition size", ':', &ioparam
,
266 (int *)&p_deflt
, DATA_INPUT
);
269 * If the current partition has a size of zero change the
270 * tag to Unassigned and the starting cylinder to zero
281 if (i
< cyl_offset
&& tag
!= V_UNASSIGNED
&& tag
!= V_BACKUP
&&
284 * This slice overlaps boot and/or alternates slice
285 * Check if it's the boot or alternates slice and warn
288 if (i
< cur_parts
->pinfo_map
[I_PARTITION
].dkl_cylno
+ 1) {
289 fmt_print("\nWarning: Partition overlaps boot ");
290 fmt_print("partition. Specify different start cyl.\n");
294 * Cyl offset for alternates partition was calculated before
296 if (i
< cyl_offset
) {
297 fmt_print("\nWarning: Partition overlaps alternates ");
298 fmt_print("partition. Specify different start cyl.\n");
303 #endif /* defined(i386) */
306 * If user has entered a V_BACKUP tag then the partition
307 * size should specify full disk capacity else
310 if (tag
== V_BACKUP
) {
313 fullsz
= ncyl
* nhead
* nsect
;
316 * V_BACKUP Tag Partition != full disk capacity.
317 * print useful messages.
319 fmt_print("\nWarning: Partition with V_BACKUP tag should ");
320 fmt_print("specify full disk capacity. \n");
327 * If the current partition is named, we can't change it.
328 * We create a new current partition map instead.
330 if (cur_parts
->pinfo_name
!= NULL
)
335 cur_parts
->pinfo_map
[num
].dkl_cylno
= i
;
336 cur_parts
->pinfo_map
[num
].dkl_nblk
= j
;
338 #if defined(_SUNOS_VTOC_16)
339 cur_parts
->vtoc
.v_part
[num
].p_start
= (daddr_t
)(i
* (nhead
* nsect
));
340 cur_parts
->vtoc
.v_part
[num
].p_size
= (long)j
;
341 #endif /* defined(_SUNOS_VTOC_16) */
344 * Install the p_tag and p_flag values for this partition
346 assert(cur_parts
->vtoc
.v_version
== V_VERSION
);
347 cur_parts
->vtoc
.v_part
[num
].p_tag
= (ushort_t
)tag
;
348 cur_parts
->vtoc
.v_part
[num
].p_flag
= (ushort_t
)flag
;
353 * This routine picks to closest partition table which matches the
354 * selected disk type. It is called each time the disk type is
355 * changed. If no match is found, it uses the first element
356 * of the partition table. If no table exists, a dummy is
362 register struct partition_info
*pptr
;
363 register struct partition_info
*parts
;
366 * If there are no pre-defined maps for this disk type, it's
369 parts
= cur_dtype
->dtype_plist
;
371 err_print("No defined partition tables.\n");
376 * Loop through the pre-defined maps searching for one which match
377 * disk type. If found copy it into unmamed partition.
380 for (pptr
= parts
; pptr
!= NULL
; pptr
= pptr
->pinfo_next
) {
381 if (cur_dtype
->dtype_asciilabel
) {
382 if (pptr
->pinfo_name
!= NULL
&& strcmp(pptr
->pinfo_name
,
383 cur_dtype
->dtype_asciilabel
) == 0) {
385 * Set current partition and name it.
387 cur_disk
->disk_parts
= cur_parts
= pptr
;
388 cur_parts
->pinfo_name
= pptr
->pinfo_name
;
395 * If we couldn't find a match, take the first one.
396 * Set current partition and name it.
398 cur_disk
->disk_parts
= cur_parts
= cur_dtype
->dtype_plist
;
399 cur_parts
->pinfo_name
= parts
->pinfo_name
;
406 * This routine creates a new partition map and sets it current. If there
407 * was a current map, the new map starts out identical to it. Otherwise
408 * the new map starts out all zeroes.
413 register struct partition_info
*pptr
, *parts
;
417 * Lock out interrupts so the lists don't get mangled.
421 * Get space for for the new map and link it into the list
422 * of maps for the current disk type.
424 pptr
= (struct partition_info
*)zalloc(sizeof (struct partition_info
));
425 parts
= cur_dtype
->dtype_plist
;
427 cur_dtype
->dtype_plist
= pptr
;
429 while (parts
->pinfo_next
!= NULL
) {
430 parts
= parts
->pinfo_next
;
432 parts
->pinfo_next
= pptr
;
433 pptr
->pinfo_next
= NULL
;
436 * If there was a current map, copy its values.
438 if (cur_label
== L_TYPE_EFI
) {
443 nparts
= cur_parts
->etoc
->efi_nparts
;
444 size
= sizeof (struct dk_part
) * nparts
+ sizeof (struct dk_gpt
);
446 (void) memcpy(map
, cur_parts
->etoc
, size
);
448 cur_disk
->disk_parts
= cur_parts
= pptr
;
452 if (cur_parts
!= NULL
) {
453 for (i
= 0; i
< NDKMAP
; i
++) {
454 pptr
->pinfo_map
[i
] = cur_parts
->pinfo_map
[i
];
456 pptr
->vtoc
= cur_parts
->vtoc
;
459 * Otherwise set initial default vtoc values
461 set_vtoc_defaults(pptr
);
465 * Make the new one current.
467 cur_disk
->disk_parts
= cur_parts
= pptr
;
473 * This routine deletes a partition map from the list of maps for
474 * the given disk type.
477 delete_partition(struct partition_info
*parts
)
479 struct partition_info
*pptr
;
482 * If there isn't a current map, it's an error.
484 if (cur_dtype
->dtype_plist
== NULL
) {
485 err_print("Error: unexpected null partition list.\n");
489 * Remove the map from the list.
491 if (cur_dtype
->dtype_plist
== parts
)
492 cur_dtype
->dtype_plist
= parts
->pinfo_next
;
494 for (pptr
= cur_dtype
->dtype_plist
; pptr
->pinfo_next
!= parts
;
495 pptr
= pptr
->pinfo_next
)
497 pptr
->pinfo_next
= parts
->pinfo_next
;
500 * Free the space it was using.
502 destroy_data((char *)parts
);
507 * Set all partition vtoc fields to defaults
510 set_vtoc_defaults(struct partition_info
*part
)
514 bzero((caddr_t
)&part
->vtoc
, sizeof (struct dk_vtoc
));
516 part
->vtoc
.v_version
= V_VERSION
;
517 part
->vtoc
.v_nparts
= NDKMAP
;
518 part
->vtoc
.v_sanity
= VTOC_SANE
;
520 for (i
= 0; i
< NDKMAP
; i
++) {
521 part
->vtoc
.v_part
[i
].p_tag
= default_vtoc_map
[i
].p_tag
;
522 part
->vtoc
.v_part
[i
].p_flag
= default_vtoc_map
[i
].p_flag
;